/// <summary>
        /// Retrieves the method layout for a UdonSharpBehaviour method.
        /// This includes the method name, name of return variable, and name of parameter values.
        /// This is used internally by GetMethodLinkage in the EmitContext.
        /// This is also used when calling across UdonSharpBehaviours to determine what variables to set for parameters and such.
        /// </summary>
        /// <remarks>This method is thread safe and may be called safely from multiple Contexts at a time</remarks>
        public MethodExportLayout GetUsbMethodLayout(MethodSymbol method, AbstractPhaseContext context)
        {
            if (_udonSharpBehaviourType == null)
            {
                _udonSharpBehaviourType = GetTypeSymbol(typeof(UdonSharpBehaviour), context);
            }

            while (method.OverridenMethod != null &&
                   method.OverridenMethod.ContainingType != _udonSharpBehaviourType &&
                   !method.OverridenMethod.ContainingType.IsExtern)
            {
                method = method.OverridenMethod;
            }

            lock (_layoutLock)
            {
                if (_layouts.TryGetValue(method, out MethodExportLayout layout))
                {
                    return(layout);
                }

                BuildLayout(method.ContainingType, context);

                return(_layouts[method]);
            }
        }
        public TypeSymbol GetUdonTypeSymbol(ITypeSymbol type, AbstractPhaseContext context)
        {
            if (!TypeSymbol.TryGetSystemType(type, out var systemType))
            {
                throw new InvalidOperationException("foundType should not be null");
            }

            systemType = UdonSharpUtils.UserTypeToUdonType(systemType);

            return(GetTypeSymbol(systemType, context));
        }
        /// <summary>
        /// Builds a layout for a given type.
        /// First traverses all base types and builds their layouts when needed since the base type layouts inform the layout of derived types.
        /// </summary>
        private void BuildLayout(TypeSymbol typeSymbol, AbstractPhaseContext context)
        {
            Stack <TypeSymbol> typesToBuild = new Stack <TypeSymbol>();

            while (typeSymbol.BaseType != null && !_builtLayouts.ContainsKey(typeSymbol))
            {
                typesToBuild.Push(typeSymbol);
                if (typeSymbol == _udonSharpBehaviourType)
                {
                    break;
                }

                typeSymbol = typeSymbol.BaseType;
            }

            while (typesToBuild.Count > 0)
            {
                TypeSymbol currentBuildType = typesToBuild.Pop();

                Dictionary <string, int> idCounters;

                if (currentBuildType.BaseType != null &&
                    _builtLayouts.TryGetValue(currentBuildType.BaseType, out TypeLayout parentLayout))
                {
                    idCounters = new Dictionary <string, int>(parentLayout.SymbolCounters);
                }
                else
                {
                    idCounters = new Dictionary <string, int>();
                }

                Dictionary <MethodSymbol, MethodExportLayout> layouts =
                    new Dictionary <MethodSymbol, MethodExportLayout>();

                foreach (Symbol symbol in currentBuildType.GetMembers(context))
                {
                    if (symbol is MethodSymbol methodSymbol &&
                        (methodSymbol.OverridenMethod == null ||
                         methodSymbol.OverridenMethod.ContainingType == _udonSharpBehaviourType ||
                         methodSymbol.OverridenMethod.ContainingType.IsExtern))
                    {
                        layouts.Add(methodSymbol, BuildMethodLayout(methodSymbol, idCounters));
                    }
                }

                _builtLayouts.Add(currentBuildType, new TypeLayout(layouts, idCounters));
            }
        }
        public Symbol GetSymbol(ISymbol sourceSymbol, AbstractPhaseContext context)
        {
            if (sourceSymbol == null)
            {
                throw new NullReferenceException("Source symbol cannot be null");
            }

            if (sourceSymbol is ITypeSymbol typeSymbol)
            {
                return(GetTypeSymbol(typeSymbol, context));
            }

            if (sourceSymbol.ContainingType != null)
            {
                return(GetTypeSymbol(sourceSymbol.ContainingType, context).GetMember(sourceSymbol, context));
            }

            throw new InvalidOperationException($"Could not get symbol for {sourceSymbol}");
        }
        public TypeSymbol GetTypeSymbol(Type systemType, AbstractPhaseContext context)
        {
            int arrayDepth = 0;

            while (systemType.IsArray)
            {
                arrayDepth++;
                systemType = systemType.GetElementType();
            }

            ITypeSymbol typeSymbol = RoslynCompilation.GetTypeByMetadataName(systemType.FullName);

            for (int i = 0; i < arrayDepth; ++i)
            {
                typeSymbol = RoslynCompilation.CreateArrayTypeSymbol(typeSymbol, 1);
            }

            return(GetTypeSymbol(typeSymbol, context));
        }
 public TypeSymbol GetTypeSymbol(SpecialType type, AbstractPhaseContext context)
 {
     return(GetTypeSymbol(RoslynCompilation.GetSpecialType(type), context));
 }
        public TypeSymbol GetTypeSymbol(ITypeSymbol type, AbstractPhaseContext context)
        {
            TypeSymbol typeSymbol = _typeSymbolLookup.GetOrAdd(type, (key) => TypeSymbolFactory.CreateSymbol(type, context));

            return(typeSymbol);
        }