private static bool TryCreateUdonSharpMetadataInvocation(AbstractPhaseContext context, SyntaxNode node,
                                                                 MethodSymbol symbol, BoundExpression instanceExpression,
                                                                 out BoundInvocationExpression createdInvocation)
        {
            if (symbol.Name == "GetUdonTypeID" || symbol.Name == "GetUdonTypeName")
            {
                if (symbol.IsStatic &&
                    symbol.TypeArguments.Length == 1 &&
                    symbol.ContainingType == context.GetTypeSymbol(typeof(UdonSharpBehaviour)))
                {
                    IConstantValue constantValue;
                    TypeSymbol     constantType;

                    var typeArgs = symbol.TypeArguments.Select(e => context.GetTypeSymbol(e.RoslynSymbol)).ToArray();

                    if (symbol.Name == "GetUdonTypeID")
                    {
                        constantValue = new ConstantValue <long>(UdonSharpInternalUtility.GetTypeID(TypeSymbol.GetFullTypeName(typeArgs[0].RoslynSymbol)));
                        constantType  = context.GetTypeSymbol(SpecialType.System_Int64);
                    }
                    else
                    {
                        constantValue = new ConstantValue <string>(TypeSymbol.GetFullTypeName(typeArgs[0].RoslynSymbol));
                        constantType  = context.GetTypeSymbol(SpecialType.System_String);
                    }

                    createdInvocation = new BoundConstantInvocationExpression(node, constantValue, constantType);

                    return(true);
                }

                if (!symbol.IsStatic &&
                    instanceExpression != null &&
                    symbol.ContainingType == context.GetTypeSymbol(typeof(UdonSharpBehaviour)))
                {
                    TypeSymbol methodContainer = context.GetTypeSymbol(typeof(UdonSharpBehaviourMethods));
                    var        shimMethod      = methodContainer.GetMember <MethodSymbol>(symbol.Name, context);
                    context.MarkSymbolReferenced(shimMethod);

                    createdInvocation = CreateBoundInvocation(context, node, shimMethod, null, new [] { instanceExpression });

                    return(true);
                }
            }

            createdInvocation = null;
            return(false);
        }
        private static bool TryCreateInstantiationInvocation(AbstractPhaseContext context, SyntaxNode node,
                                                             MethodSymbol symbol, BoundExpression instanceExpression, BoundExpression[] parameterExpressions,
                                                             out BoundInvocationExpression createdInvocation)
        {
            switch (symbol.Name)
            {
            case "Instantiate_Extern" when symbol.ContainingType == context.GetTypeSymbol(typeof(InstantiationShim)):
                createdInvocation = new BoundExternInvocation(node, context,
                                                              new ExternSynthesizedMethodSymbol(context,
                                                                                                "VRCInstantiate.__Instantiate__UnityEngineGameObject__UnityEngineGameObject",
                                                                                                parameterExpressions.Select(e => e.ValueType).ToArray(),
                                                                                                context.GetTypeSymbol(typeof(GameObject)), true),
                                                              instanceExpression, parameterExpressions);

                return(true);

            case "VRCInstantiate" when symbol.ContainingType == context.GetTypeSymbol(typeof(UdonSharpBehaviour)):     // Backwards compatibility for UdonSharpBehaviour.VRCInstantiate
            case "Instantiate" when symbol.ContainingType == context.GetTypeSymbol(typeof(UnityEngine.Object)):
            {
                if (symbol.Name != "VRCInstantiate" &&
                    (symbol.TypeArguments.Length != 1 ||
                     symbol.TypeArguments[0] != context.GetTypeSymbol(typeof(GameObject))))
                {
                    throw new NotSupportedException("Udon does not support instantiating non-GameObject types");
                }

                TypeSymbol   instantiateShim   = context.GetTypeSymbol(typeof(InstantiationShim));
                MethodSymbol instantiateMethod = instantiateShim.GetMembers <MethodSymbol>("Instantiate", context)
                                                 .First(e => e.Parameters
                                                        .Select(p => p.Type)
                                                        .SequenceEqual(parameterExpressions
                                                                       .Select(p => p.ValueType)));

                context.MarkSymbolReferenced(instantiateMethod);

                createdInvocation = new BoundStaticUserMethodInvocation(node, instantiateMethod, parameterExpressions);
                return(true);
            }
            }

            createdInvocation = null;
            return(false);
        }
        private static bool TryCreateGetComponentInvocation(AbstractPhaseContext context, SyntaxNode node,
                                                            MethodSymbol symbol, BoundExpression instanceExpression, BoundExpression[] parameterExpressions,
                                                            out BoundInvocationExpression createdInvocation)
        {
            if (symbol.RoslynSymbol != null &&
                symbol.RoslynSymbol.IsGenericMethod &&
                symbol.TypeArguments.Length == 1 &&
                _getComponentNames.Contains(symbol.Name) &&
                (symbol.ContainingType.UdonType.SystemType == typeof(Component) || symbol.ContainingType.UdonType.SystemType == typeof(GameObject)))
            {
                TypeSymbol gameObjectType = context.GetTypeSymbol(typeof(GameObject));
                TypeSymbol typeArgument   = symbol.TypeArguments[0];

                // udon-workaround: Work around the udon bug where it checks the strongbox type instead of variable type and blows up when the strong box is `object`
                if (instanceExpression.ValueType == gameObjectType)
                {
                    PropertySymbol accessProperty = gameObjectType.GetMember <PropertySymbol>("transform", context);
                    instanceExpression = BoundAccessExpression.BindAccess(context, node, accessProperty, instanceExpression);
                }
                else
                {
                    PropertySymbol accessProperty = context.GetTypeSymbol(typeof(Component)).GetMember <PropertySymbol>("transform", context);
                    instanceExpression = BoundAccessExpression.BindAccess(context, node, accessProperty, instanceExpression);
                }

                TypeSymbol udonSharpBehaviourType = context.GetTypeSymbol(typeof(UdonSharpBehaviour));

                // Exact UdonSharpBehaviour type match
                if (typeArgument == udonSharpBehaviourType)
                {
                    MethodSymbol getComponentMethodShim = context.GetTypeSymbol(typeof(GetComponentShim))
                                                          .GetMembers <MethodSymbol>(symbol.Name + "USB", context)
                                                          .First(e => e.Parameters.Length == parameterExpressions.Length + 1);

                    createdInvocation = new BoundStaticUserMethodInvocation(node, getComponentMethodShim,
                                                                            new [] { instanceExpression }.Concat(parameterExpressions).ToArray());

                    context.MarkSymbolReferenced(getComponentMethodShim);

                    return(true);
                }

                // Subclass of UdonSharpBehaviour
                if (typeArgument.IsUdonSharpBehaviour)
                {
                    // Handle inherited types
                    if (context.CompileContext.HasInheritedUdonSharpBehaviours(typeArgument))
                    {
                        MethodSymbol getComponentInheritedMethodShim = context.GetTypeSymbol(typeof(GetComponentShim))
                                                                       .GetMembers <MethodSymbol>(symbol.Name + "I", context)
                                                                       .First(e => e.Parameters.Length == parameterExpressions.Length + 1);

                        getComponentInheritedMethodShim = getComponentInheritedMethodShim.ConstructGenericMethod(context, new [] { typeArgument });

                        createdInvocation = new BoundStaticUserMethodInvocation(node, getComponentInheritedMethodShim,
                                                                                new [] { instanceExpression }.Concat(parameterExpressions).ToArray());

                        context.MarkSymbolReferenced(getComponentInheritedMethodShim);

                        return(true);
                    }

                    MethodSymbol getComponentMethodShim = context.GetTypeSymbol(typeof(GetComponentShim))
                                                          .GetMembers <MethodSymbol>(symbol.Name, context)
                                                          .First(e => e.Parameters.Length == parameterExpressions.Length + 1);

                    getComponentMethodShim = getComponentMethodShim.ConstructGenericMethod(context, new [] { typeArgument });

                    createdInvocation = new BoundStaticUserMethodInvocation(node, getComponentMethodShim,
                                                                            new [] { instanceExpression }.Concat(parameterExpressions).ToArray());

                    context.MarkSymbolReferenced(getComponentMethodShim);

                    return(true);
                }

                if (_brokenGetComponentTypes.Contains(typeArgument.UdonType.SystemType))
                {
                    MethodSymbol getComponentInheritedMethodShim = context.GetTypeSymbol(typeof(GetComponentShim))
                                                                   .GetMembers <MethodSymbol>(symbol.Name + "VRC", context)
                                                                   .First(e => e.Parameters.Length == parameterExpressions.Length + 1);

                    getComponentInheritedMethodShim = getComponentInheritedMethodShim.ConstructGenericMethod(context, new [] { typeArgument });

                    createdInvocation = new BoundStaticUserMethodInvocation(node, getComponentInheritedMethodShim,
                                                                            new [] { instanceExpression }.Concat(parameterExpressions).ToArray());

                    context.MarkSymbolReferenced(getComponentInheritedMethodShim);

                    return(true);
                }

                createdInvocation = new BoundGetUnityEngineComponentInvocation(context, node, symbol,
                                                                               instanceExpression,
                                                                               parameterExpressions);

                return(true);
            }

            createdInvocation = null;
            return(false);
        }