private ImmutableArray GetSemanticSymbols()

in src/Compilers/CSharp/Portable/Compilation/CSharpSemanticModel.cs [3005:3332]


        private ImmutableArray<Symbol> GetSemanticSymbols(BoundExpression boundNode,
            BoundNode boundNodeForSyntacticParent,
            Binder binderOpt,
            SymbolInfoOptions options,
            out bool isDynamic,
            out LookupResultKind resultKind,
            out ImmutableArray<Symbol> memberGroup)
        {
            memberGroup = ImmutableArray<Symbol>.Empty;
            ImmutableArray<Symbol> symbols = ImmutableArray<Symbol>.Empty;
            resultKind = LookupResultKind.Viable;
            isDynamic = false;

            switch (boundNode.Kind)
            {
                case BoundKind.MethodGroup:
                    symbols = GetMethodGroupSemanticSymbols((BoundMethodGroup)boundNode, boundNodeForSyntacticParent, binderOpt, out resultKind, out isDynamic, out memberGroup);
                    break;

                case BoundKind.PropertyGroup:
                    symbols = GetPropertyGroupSemanticSymbols((BoundPropertyGroup)boundNode, boundNodeForSyntacticParent, binderOpt, out resultKind, out memberGroup);
                    break;

                case BoundKind.BadExpression:
                    {
                        var expr = (BoundBadExpression)boundNode;
                        resultKind = expr.ResultKind;

                        if (expr.Syntax.Kind() == SyntaxKind.ObjectCreationExpression)
                        {
                            if (resultKind == LookupResultKind.NotCreatable)
                            {
                                return expr.Symbols;
                            }
                            else if (expr.Type.IsDelegateType())
                            {
                                resultKind = LookupResultKind.Empty;
                                return symbols;
                            }

                            memberGroup = expr.Symbols;
                        }

                        return expr.Symbols;
                    }

                case BoundKind.DelegateCreationExpression:
                    break;

                case BoundKind.TypeExpression:
                    {
                        var boundType = (BoundTypeExpression)boundNode;

                        // Watch out for not creatable types within object creation syntax
                        if (boundNodeForSyntacticParent != null &&
                           boundNodeForSyntacticParent.Syntax.Kind() == SyntaxKind.ObjectCreationExpression &&
                           ((ObjectCreationExpressionSyntax)boundNodeForSyntacticParent.Syntax).Type == boundType.Syntax &&
                           boundNodeForSyntacticParent.Kind == BoundKind.BadExpression &&
                           ((BoundBadExpression)boundNodeForSyntacticParent).ResultKind == LookupResultKind.NotCreatable)
                        {
                            resultKind = LookupResultKind.NotCreatable;
                        }

                        // could be a type or alias.
                        var typeSymbol = boundType.AliasOpt ?? (Symbol)boundType.Type;

                        var originalErrorType = typeSymbol.OriginalDefinition as ErrorTypeSymbol;
                        if ((object)originalErrorType != null)
                        {
                            resultKind = originalErrorType.ResultKind;
                            symbols = originalErrorType.CandidateSymbols;
                        }
                        else
                        {
                            symbols = ImmutableArray.Create<Symbol>(typeSymbol);
                        }
                    }
                    break;

                case BoundKind.TypeOrValueExpression:
                    {
                        // If we're seeing a node of this kind, then we failed to resolve the member access
                        // as either a type or a property/field/event/local/parameter.  In such cases,
                        // the second interpretation applies so just visit the node for that.
                        BoundExpression valueExpression = ((BoundTypeOrValueExpression)boundNode).Data.ValueExpression;
                        return GetSemanticSymbols(valueExpression, boundNodeForSyntacticParent, binderOpt, options, out isDynamic, out resultKind, out memberGroup);
                    }

                case BoundKind.Call:
                    {
                        // Either overload resolution succeeded for this call or it did not. If it
                        // did not succeed then we've stashed the original method symbols from the
                        // method group, and we should use those as the symbols displayed for the
                        // call. If it did succeed then we did not stash any symbols; just fall
                        // through to the default case.

                        var call = (BoundCall)boundNode;
                        if (call.OriginalMethodsOpt.IsDefault)
                        {
                            if ((object)call.Method != null)
                            {
                                symbols = CreateReducedExtensionMethodIfPossible(call);
                                resultKind = call.ResultKind;
                            }
                        }
                        else
                        {
                            symbols = StaticCast<Symbol>.From(CreateReducedExtensionMethodsFromOriginalsIfNecessary(call));
                            resultKind = call.ResultKind;
                        }
                    }
                    break;

                case BoundKind.IndexerAccess:
                    {
                        // As for BoundCall, pull out stashed candidates if overload resolution failed.

                        BoundIndexerAccess indexerAccess = (BoundIndexerAccess)boundNode;
                        Debug.Assert((object)indexerAccess.Indexer != null);

                        resultKind = indexerAccess.ResultKind;

                        ImmutableArray<PropertySymbol> originalIndexersOpt = indexerAccess.OriginalIndexersOpt;
                        symbols = originalIndexersOpt.IsDefault ? ImmutableArray.Create<Symbol>(indexerAccess.Indexer) : StaticCast<Symbol>.From(originalIndexersOpt);
                    }
                    break;

                case BoundKind.EventAssignmentOperator:
                    var eventAssignment = (BoundEventAssignmentOperator)boundNode;
                    isDynamic = eventAssignment.IsDynamic;
                    var eventSymbol = eventAssignment.Event;
                    var methodSymbol = eventAssignment.IsAddition ? eventSymbol.AddMethod : eventSymbol.RemoveMethod;
                    if ((object)methodSymbol == null)
                    {
                        symbols = ImmutableArray<Symbol>.Empty;
                        resultKind = LookupResultKind.Empty;
                    }
                    else
                    {
                        symbols = ImmutableArray.Create<Symbol>(methodSymbol);
                        resultKind = eventAssignment.ResultKind;
                    }
                    break;

                case BoundKind.Conversion:
                    var conversion = (BoundConversion)boundNode;
                    isDynamic = conversion.ConversionKind.IsDynamic();
                    if (!isDynamic)
                    {
                        if ((conversion.ConversionKind == ConversionKind.MethodGroup) && conversion.IsExtensionMethod)
                        {
                            var symbol = conversion.SymbolOpt;
                            Debug.Assert((object)symbol != null);
                            symbols = ImmutableArray.Create<Symbol>(ReducedExtensionMethodSymbol.Create(symbol));
                            resultKind = conversion.ResultKind;
                        }
                        else if (conversion.ConversionKind.IsUserDefinedConversion())
                        {
                            GetSymbolsAndResultKind(conversion, conversion.SymbolOpt, conversion.OriginalUserDefinedConversionsOpt, out symbols, out resultKind);
                        }
                        else
                        {
                            goto default;
                        }
                    }
                    break;

                case BoundKind.BinaryOperator:
                    GetSymbolsAndResultKind((BoundBinaryOperator)boundNode, out isDynamic, ref resultKind, ref symbols);
                    break;

                case BoundKind.UnaryOperator:
                    GetSymbolsAndResultKind((BoundUnaryOperator)boundNode, out isDynamic, ref resultKind, ref symbols);
                    break;

                case BoundKind.UserDefinedConditionalLogicalOperator:
                    var @operator = (BoundUserDefinedConditionalLogicalOperator)boundNode;
                    isDynamic = false;
                    GetSymbolsAndResultKind(@operator, @operator.LogicalOperator, @operator.OriginalUserDefinedOperatorsOpt, out symbols, out resultKind);
                    break;

                case BoundKind.CompoundAssignmentOperator:
                    GetSymbolsAndResultKind((BoundCompoundAssignmentOperator)boundNode, out isDynamic, ref resultKind, ref symbols);
                    break;

                case BoundKind.IncrementOperator:
                    GetSymbolsAndResultKind((BoundIncrementOperator)boundNode, out isDynamic, ref resultKind, ref symbols);
                    break;

                case BoundKind.AwaitExpression:
                    var await = (BoundAwaitExpression)boundNode;
                    isDynamic = await.IsDynamic;
                    // TODO:
                    goto default;

                case BoundKind.ConditionalOperator:
                    Debug.Assert((object)boundNode.ExpressionSymbol == null);
                    var conditional = (BoundConditionalOperator)boundNode;
                    isDynamic = conditional.IsDynamic;
                    goto default;

                case BoundKind.Attribute:
                    {
                        Debug.Assert(boundNodeForSyntacticParent == null);
                        var attribute = (BoundAttribute)boundNode;
                        resultKind = attribute.ResultKind;

                        // If attribute name bound to a single named type or an error type
                        // with a single named type candidate symbol, we will return constructors
                        // of the named type in the semantic info.
                        // Otherwise, we will return the error type candidate symbols.

                        var namedType = (NamedTypeSymbol)attribute.Type;
                        if (namedType.IsErrorType())
                        {
                            Debug.Assert(resultKind != LookupResultKind.Viable);
                            var errorType = (ErrorTypeSymbol)namedType;
                            var candidateSymbols = errorType.CandidateSymbols;

                            // If error type has a single named type candidate symbol, we want to 
                            // use that type for symbol info. 
                            if (candidateSymbols.Length == 1 && candidateSymbols[0] is NamedTypeSymbol)
                            {
                                namedType = (NamedTypeSymbol)candidateSymbols[0];
                            }
                            else
                            {
                                symbols = candidateSymbols;
                                break;
                            }
                        }

                        AdjustSymbolsForObjectCreation(attribute, namedType, attribute.Constructor, binderOpt, ref resultKind, ref symbols, ref memberGroup);
                    }
                    break;

                case BoundKind.QueryClause:
                    {
                        var query = (BoundQueryClause)boundNode;
                        var builder = ArrayBuilder<Symbol>.GetInstance();
                        if (query.Operation != null && (object)query.Operation.ExpressionSymbol != null) builder.Add(query.Operation.ExpressionSymbol);
                        if ((object)query.DefinedSymbol != null) builder.Add(query.DefinedSymbol);
                        if (query.Cast != null && (object)query.Cast.ExpressionSymbol != null) builder.Add(query.Cast.ExpressionSymbol);
                        symbols = builder.ToImmutableAndFree();
                    }
                    break;

                case BoundKind.DynamicInvocation:
                    Debug.Assert((object)boundNode.ExpressionSymbol == null);
                    var dynamicInvocation = (BoundDynamicInvocation)boundNode;
                    symbols = memberGroup = dynamicInvocation.ApplicableMethods.Cast<MethodSymbol, Symbol>();
                    isDynamic = true;
                    break;

                case BoundKind.DynamicCollectionElementInitializer:
                    Debug.Assert((object)boundNode.ExpressionSymbol == null);
                    var collectionInit = (BoundDynamicCollectionElementInitializer)boundNode;
                    symbols = memberGroup = collectionInit.ApplicableMethods.Cast<MethodSymbol, Symbol>();
                    isDynamic = true;
                    break;

                case BoundKind.DynamicIndexerAccess:
                    Debug.Assert((object)boundNode.ExpressionSymbol == null);
                    var dynamicIndexer = (BoundDynamicIndexerAccess)boundNode;
                    symbols = memberGroup = dynamicIndexer.ApplicableIndexers.Cast<PropertySymbol, Symbol>();
                    isDynamic = true;
                    break;

                case BoundKind.DynamicMemberAccess:
                    Debug.Assert((object)boundNode.ExpressionSymbol == null);
                    isDynamic = true;
                    break;

                case BoundKind.DynamicObjectCreationExpression:
                    var objectCreation = (BoundDynamicObjectCreationExpression)boundNode;
                    symbols = memberGroup = objectCreation.ApplicableMethods.Cast<MethodSymbol, Symbol>();
                    isDynamic = true;
                    break;

                case BoundKind.ObjectCreationExpression:
                    var boundObjectCreation = (BoundObjectCreationExpression)boundNode;

                    if ((object)boundObjectCreation.Constructor != null)
                    {
                        Debug.Assert(boundObjectCreation.ConstructorsGroup.Contains(boundObjectCreation.Constructor));
                        symbols = ImmutableArray.Create<Symbol>(boundObjectCreation.Constructor);
                    }
                    else if (boundObjectCreation.ConstructorsGroup.Length > 0)
                    {
                        symbols = StaticCast<Symbol>.From(boundObjectCreation.ConstructorsGroup);
                        resultKind = resultKind.WorseResultKind(LookupResultKind.OverloadResolutionFailure);
                    }

                    memberGroup = boundObjectCreation.ConstructorsGroup.Cast<MethodSymbol, Symbol>();
                    break;

                case BoundKind.ThisReference:
                case BoundKind.BaseReference:
                    {
                        Binder binder = binderOpt ?? GetEnclosingBinder(GetAdjustedNodePosition(boundNode.Syntax));
                        NamedTypeSymbol containingType = binder.ContainingType;
                        var containingMember = binder.ContainingMember();

                        var thisParam = GetThisParameter(boundNode.Type, containingType, containingMember, out resultKind);
                        symbols = thisParam != null ? ImmutableArray.Create<Symbol>(thisParam) : ImmutableArray<Symbol>.Empty;
                    }
                    break;

                default:
                    {
                        var symbol = boundNode.ExpressionSymbol;
                        if ((object)symbol != null)
                        {
                            symbols = ImmutableArray.Create(symbol);
                            resultKind = boundNode.ResultKind;
                        }
                    }
                    break;
            }

            if (boundNodeForSyntacticParent != null && (options & SymbolInfoOptions.PreferConstructorsToType) != 0)
            {
                // Adjust symbols to get the constructors if we're T in a "new T(...)".
                AdjustSymbolsForObjectCreation(boundNode, boundNodeForSyntacticParent, binderOpt, ref resultKind, ref symbols, ref memberGroup);
            }

            return symbols;
        }