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;
}