internal override SymbolInfo GetSymbolInfoWorker( CSharpSyntaxNode node, SymbolInfoOptions options, CancellationToken cancellationToken = default(CancellationToken) ) { var cref = node as CrefSyntax; if (cref != null) { return(_parentSemanticModel.GetSpeculativeSymbolInfo(_position, cref, options)); } var expression = (ExpressionSyntax)node; if ((options & SymbolInfoOptions.PreserveAliases) != 0) { var aliasSymbol = _parentSemanticModel.GetSpeculativeAliasInfo( _position, expression, this.GetSpeculativeBindingOption(expression) ); return(new SymbolInfo( aliasSymbol, ImmutableArray <ISymbol> .Empty, CandidateReason.None )); } return(_parentSemanticModel.GetSpeculativeSymbolInfo( _position, expression, this.GetSpeculativeBindingOption(expression) )); }
internal override SymbolInfo GetSymbolInfoWorker(LanguageSyntaxNode node, SymbolInfoOptions options, CancellationToken cancellationToken = default(CancellationToken)) { if ((options & SymbolInfoOptions.PreserveAliases) != 0) { var aliasSymbol = (AliasSymbol)_parentSemanticModel.GetSpeculativeAliasInfo(_position, node, this.GetSpeculativeBindingOption(node)); return(new SymbolInfo(aliasSymbol, ImmutableArray <ISymbol> .Empty, CandidateReason.None)); } return(_parentSemanticModel.GetSpeculativeSymbolInfo(_position, node, this.GetSpeculativeBindingOption(node))); }
internal override SymbolInfo GetSymbolInfoWorker(LanguageSyntaxNode node, SymbolInfoOptions options, CancellationToken cancellationToken = default(CancellationToken)) { ValidateSymbolInfoOptions(options); // in case this is right side of a qualified name or member access (or part of a cref) node = SyntaxFactory.GetStandaloneNode(node); var model = this.GetMemberModel(node); SymbolInfo result; if (model != null) { // Expression occurs in an executable code (method body or initializer) context. Use that // model to get the information. result = model.GetSymbolInfoWorker(node, options, cancellationToken); // If we didn't get anything and were in Type/Namespace only context, let's bind normally and see // if any symbol comes out. if ((object)result.Symbol == null && result.CandidateReason == CandidateReason.None && this.Language.SyntaxFacts.IsInNamespaceOrTypeContext(node)) { var binder = this.GetEnclosingBinder(GetAdjustedNodePosition(node)); if (binder != null) { // Wrap the binder in a LocalScopeBinder because Binder.BindExpression assumes there // will be one in the binder chain and one isn't necessarily required for the batch case. binder = new LocalScopeBinder(binder); BoundExpression bound = binder.BindExpression(node, _boundTree); SymbolInfo info = GetSymbolInfoForNode(options, bound, bound, boundNodeForSyntacticParent: null, binderOpt: null); if ((object)info.Symbol != null) { result = new SymbolInfo(null, ImmutableArray.Create <ISymbol>(info.Symbol), CandidateReason.NotATypeOrNamespace); } else if (!info.CandidateSymbols.IsEmpty) { result = new SymbolInfo(null, info.CandidateSymbols, CandidateReason.NotATypeOrNamespace); } } } } else { // if expression is not part of a member context then caller may really just have a // reference to a type or namespace name var symbol = GetSemanticInfoSymbolInNonMemberContext(node, bindVarAsAliasFirst: (options & SymbolInfoOptions.PreserveAliases) != 0); result = (object)symbol != null?GetSymbolInfoForSymbol(symbol, options) : SymbolInfo.None; } return(result); }
internal override SymbolInfo GetSymbolInfoWorker(LanguageSyntaxNode node, SymbolInfoOptions options, CancellationToken cancellationToken = default(CancellationToken)) { ValidateSymbolInfoOptions(options); LanguageSyntaxNode bindableNode; BoundNode lowestBoundNode; BoundNode highestBoundNode; BoundNode boundParent; GetBoundNodes(node, out bindableNode, out lowestBoundNode, out highestBoundNode, out boundParent); Debug.Assert(IsInTree(node), "Since the node is in the tree, we can always recompute the binder later"); return(base.GetSymbolInfoForNode(options, lowestBoundNode, highestBoundNode, boundParent, binderOpt: null)); }
/// <summary> /// Bind the cref in the context of the specified location and get semantic information /// such as type, symbols and diagnostics. This method is used to get semantic information about a cref /// that did not actually appear in the source code. /// </summary> /// <param name="position">A character position used to identify a declaration scope and accessibility. This /// character position must be within the FullSpan of the Root syntax node in this SemanticModel. In order to obtain /// the correct scoping rules for the cref, position should be the Start position of the Span of the original cref. /// </param> /// <param name="cref">A syntax node that represents a parsed cref. This syntax node /// need not and typically does not appear in the source code referred to SemanticModel instance.</param> /// <param name="options">SymbolInfo options.</param> /// <returns>The semantic information for the topmost node of the cref.</returns> public SymbolInfo GetSpeculativeSymbolInfo(int position, CrefSyntax cref, SymbolInfoOptions options = SymbolInfoOptions.DefaultOptions) { Debug.Assert(CanGetSemanticInfo(cref, isSpeculative: true)); position = CheckAndAdjustPosition(position); return this.GetCrefSymbolInfo(position, cref, options, HasParameterList(cref)); }
internal static void ValidateSymbolInfoOptions(SymbolInfoOptions options) { Debug.Assert(((options & SymbolInfoOptions.PreferConstructorsToType) != 0) != ((options & SymbolInfoOptions.PreferTypeToConstructors) != 0), "Options are mutually exclusive"); Debug.Assert(((options & SymbolInfoOptions.ResolveAliases) != 0) != ((options & SymbolInfoOptions.PreserveAliases) != 0), "Options are mutually exclusive"); }
private static SymbolInfo GetCrefSymbolInfo(ImmutableArray<Symbol> symbols, SymbolInfoOptions options, bool hasParameterList) { switch (symbols.Length) { case 0: return SymbolInfo.None; case 1: // Might have to expand an ExtendedErrorTypeSymbol into multiple candidates. return GetSymbolInfoForSymbol(symbols[0], options); default: if ((options & SymbolInfoOptions.ResolveAliases) == SymbolInfoOptions.ResolveAliases) { symbols = UnwrapAliases(symbols); } LookupResultKind resultKind = LookupResultKind.Ambiguous; // The boundary between Ambiguous and OverloadResolutionFailure is let clear-cut for crefs. // We'll say that overload resolution failed if the syntax has a parameter list and if // all of the candidates have the same kind. SymbolKind firstCandidateKind = symbols[0].Kind; if (hasParameterList && symbols.All(s => s.Kind == firstCandidateKind)) { resultKind = LookupResultKind.OverloadResolutionFailure; } return SymbolInfoFactory.Create(symbols, resultKind, isDynamic: false); } }
internal SymbolInfo GetCrefSymbolInfo(int position, CrefSyntax crefSyntax, SymbolInfoOptions options, bool hasParameterList) { var binder = this.GetEnclosingBinder(position); if (binder?.InCref == true) { ImmutableArray<Symbol> symbols = BindCref(crefSyntax, binder); return GetCrefSymbolInfo(symbols, options, hasParameterList); } return SymbolInfo.None; }
// Get the symbols and possible method or property group associated with a bound node, as // they should be exposed through GetSemanticInfo. // NB: It is not safe to pass a null binderOpt during speculative binding. 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 = ImmutableArray.Create<Symbol>(thisParam); } 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; }
internal override SymbolInfo GetSymbolInfoWorker(CSharpSyntaxNode node, SymbolInfoOptions options, CancellationToken cancellationToken = default(CancellationToken)) { ValidateSymbolInfoOptions(options); // in case this is right side of a qualified name or member access (or part of a cref) node = SyntaxFactory.GetStandaloneNode(node); var model = this.GetMemberModel(node); SymbolInfo result; XmlNameAttributeSyntax attrSyntax; CrefSyntax crefSyntax; if (model != null) { // Expression occurs in an executable code (method body or initializer) context. Use that // model to get the information. result = model.GetSymbolInfoWorker(node, options, cancellationToken); // If we didn't get anything and were in Type/Namespace only context, let's bind normally and see // if any symbol comes out. if ((object)result.Symbol == null && result.CandidateReason == CandidateReason.None && node is ExpressionSyntax && SyntaxFacts.IsInNamespaceOrTypeContext((ExpressionSyntax)node)) { var binder = this.GetEnclosingBinder(GetAdjustedNodePosition(node)); if (binder != null) { // Wrap the binder in a LocalScopeBinder because Binder.BindExpression assumes there // will be one in the binder chain and one isn't necessarily required for the batch case. binder = new LocalScopeBinder(binder); var diagnostics = DiagnosticBag.GetInstance(); BoundExpression bound = binder.BindExpression((ExpressionSyntax)node, diagnostics); diagnostics.Free(); SymbolInfo info = GetSymbolInfoForNode(options, bound, bound, boundNodeForSyntacticParent: null, binderOpt: null); if ((object)info.Symbol != null) { result = new SymbolInfo(null, ImmutableArray.Create<ISymbol>(info.Symbol), CandidateReason.NotATypeOrNamespace); } else if (!info.CandidateSymbols.IsEmpty) { result = new SymbolInfo(null, info.CandidateSymbols, CandidateReason.NotATypeOrNamespace); } } } } else if (node.Parent.Kind() == SyntaxKind.XmlNameAttribute && (attrSyntax = (XmlNameAttributeSyntax)node.Parent).Identifier == node) { result = SymbolInfo.None; var binder = this.GetEnclosingBinder(GetAdjustedNodePosition(node)); if (binder != null) { HashSet<DiagnosticInfo> useSiteDiagnostics = null; var symbols = binder.BindXmlNameAttribute(attrSyntax, ref useSiteDiagnostics); // NOTE: We don't need to call GetSymbolInfoForSymbol because the symbols // can only be parameters or type parameters. Debug.Assert(symbols.All(s => s.Kind == SymbolKind.TypeParameter || s.Kind == SymbolKind.Parameter)); switch (symbols.Length) { case 0: result = SymbolInfo.None; break; case 1: result = SymbolInfoFactory.Create(symbols, LookupResultKind.Viable, isDynamic: false); break; default: result = SymbolInfoFactory.Create(symbols, LookupResultKind.Ambiguous, isDynamic: false); break; } } } else if ((crefSyntax = node as CrefSyntax) != null) { int adjustedPosition = GetAdjustedNodePosition(crefSyntax); result = GetCrefSymbolInfo(adjustedPosition, crefSyntax, options, HasParameterList(crefSyntax)); } else { // if expression is not part of a member context then caller may really just have a // reference to a type or namespace name var symbol = GetSemanticInfoSymbolInNonMemberContext(node, bindVarAsAliasFirst: (options & SymbolInfoOptions.PreserveAliases) != 0); result = (object)symbol != null ? GetSymbolInfoForSymbol(symbol, options) : SymbolInfo.None; } return result; }
/// <summary> /// Gets a list of indexer symbols for a syntax node. This is overridden by various specializations of SemanticModel. /// It can assume that CheckSyntaxNode and CanGetSemanticInfo have already been called, as well as that named /// argument nodes have been handled. /// </summary> /// <param name="node">The syntax node to get semantic information for.</param> /// <param name="options"></param> /// <param name="cancellationToken">The cancellation token.</param> internal abstract ImmutableArray<PropertySymbol> GetIndexerGroupWorker(CSharpSyntaxNode node, SymbolInfoOptions options, CancellationToken cancellationToken = default(CancellationToken));
// Gets the semantic info from a specific bound node and a set of diagnostics // lowestBoundNode: The lowest node in the bound tree associated with node // highestBoundNode: The highest node in the bound tree associated with node // boundNodeForSyntacticParent: The lowest node in the bound tree associated with node.Parent. // binderOpt: If this is null, then the one enclosing the bound node's syntax will be used (unsafe during speculative binding). internal SymbolInfo GetSymbolInfoForNode( SymbolInfoOptions options, BoundNode lowestBoundNode, BoundNode highestBoundNode, BoundNode boundNodeForSyntacticParent, Binder binderOpt) { var boundExpr = lowestBoundNode as BoundExpression; var highestBoundExpr = highestBoundNode as BoundExpression; if (boundExpr != null) { // TODO: Should parenthesized expression really not have symbols? At least for C#, I'm not sure that // is right. For example, C# allows the assignment statement: // (i) = 9; // So we don't think this code should special case parenthesized expressions. // Get symbols and result kind from the lowest and highest nodes associated with the // syntax node. LookupResultKind resultKind; bool isDynamic; ImmutableArray<Symbol> unusedMemberGroup; var symbols = GetSemanticSymbols(boundExpr, boundNodeForSyntacticParent, binderOpt, options, out isDynamic, out resultKind, out unusedMemberGroup); if (highestBoundExpr != null) { LookupResultKind highestResultKind; bool highestIsDynamic; ImmutableArray<Symbol> unusedHighestMemberGroup; ImmutableArray<Symbol> highestSymbols = GetSemanticSymbols(highestBoundExpr, boundNodeForSyntacticParent, binderOpt, options, out highestIsDynamic, out highestResultKind, out unusedHighestMemberGroup); if ((symbols.Length != 1 || resultKind == LookupResultKind.OverloadResolutionFailure) && highestSymbols.Length > 0) { symbols = highestSymbols; resultKind = highestResultKind; isDynamic = highestIsDynamic; } else if (highestResultKind != LookupResultKind.Empty && highestResultKind < resultKind) { resultKind = highestResultKind; isDynamic = highestIsDynamic; } else if (highestBoundExpr.Kind == BoundKind.TypeOrValueExpression) { symbols = highestSymbols; resultKind = highestResultKind; isDynamic = highestIsDynamic; } else if (highestBoundExpr.Kind == BoundKind.UnaryOperator) { if (IsUserDefinedTrueOrFalse((BoundUnaryOperator)highestBoundExpr)) { symbols = highestSymbols; resultKind = highestResultKind; isDynamic = highestIsDynamic; } else { Debug.Assert(ReferenceEquals(lowestBoundNode, highestBoundNode), "How is it that this operator has the same syntax node as its operand?"); } } } if (resultKind == LookupResultKind.Empty) { // Empty typically indicates an error symbol that was created because no real // symbol actually existed. return SymbolInfoFactory.Create(ImmutableArray<Symbol>.Empty, LookupResultKind.Empty, isDynamic); } else { // Caas clients don't want ErrorTypeSymbol in the symbols, but the best guess // instead. If no best guess, then nothing is returned. var builder = ArrayBuilder<Symbol>.GetInstance(); foreach (var s in symbols) { AddUnwrappingErrorTypes(builder, s); } symbols = builder.ToImmutableAndFree(); } if ((options & SymbolInfoOptions.ResolveAliases) != 0) { symbols = UnwrapAliases(symbols); } if (resultKind == LookupResultKind.Viable && symbols.Length > 1) { resultKind = LookupResultKind.OverloadResolutionFailure; } return SymbolInfoFactory.Create(symbols, resultKind, isDynamic); } return SymbolInfo.None; }
/// <summary> /// Gets symbol information about a syntax node. This is overridden by various specializations of SemanticModel. /// It can assume that CheckSyntaxNode and CanGetSemanticInfo have already been called, as well as that named /// argument nodes have been handled. /// </summary> /// <param name="node">The syntax node to get semantic information for.</param> /// <param name="options">Options to control behavior.</param> /// <param name="cancellationToken">The cancellation token.</param> internal abstract SymbolInfo GetSymbolInfoWorker(CSharpSyntaxNode node, SymbolInfoOptions options, CancellationToken cancellationToken = default(CancellationToken));
internal override SymbolInfo GetSymbolInfoWorker(CSharpSyntaxNode node, SymbolInfoOptions options, CancellationToken cancellationToken = default(CancellationToken)) { var cref = node as CrefSyntax; if (cref != null) { return parentSemanticModel.GetSpeculativeSymbolInfo(position, cref, options); } var expression = (ExpressionSyntax)node; if ((options & SymbolInfoOptions.PreserveAliases) != 0) { var aliasSymbol = (AliasSymbol)parentSemanticModel.GetSpeculativeAliasInfo(position, expression, this.GetSpeculativeBindingOption(expression)); return new SymbolInfo(aliasSymbol, ImmutableArray<ISymbol>.Empty, CandidateReason.None); } return parentSemanticModel.GetSpeculativeSymbolInfo(position, expression, this.GetSpeculativeBindingOption(expression)); }
internal override ImmutableArray <Symbol> GetMemberGroupWorker(LanguageSyntaxNode node, SymbolInfoOptions options, CancellationToken cancellationToken = default(CancellationToken)) { // in case this is right side of a qualified name or member access (or part of a cref) node = SyntaxFactory.GetStandaloneNode(node); var model = this.GetMemberModel(node); return(model == null ? ImmutableArray <Symbol> .Empty : model.GetMemberGroupWorker(node, options, cancellationToken)); }
internal override SymbolInfo GetSymbolInfoWorker(CSharpSyntaxNode node, SymbolInfoOptions options, CancellationToken cancellationToken = default(CancellationToken)) { ValidateSymbolInfoOptions(options); CSharpSyntaxNode bindableNode; BoundNode lowestBoundNode; BoundNode highestBoundNode; BoundNode boundParent; GetBoundNodes(node, out bindableNode, out lowestBoundNode, out highestBoundNode, out boundParent); Debug.Assert(IsInTree(node), "Since the node is in the tree, we can always recompute the binder later"); return base.GetSymbolInfoForNode(options, lowestBoundNode, highestBoundNode, boundParent, binderOpt: null); }
internal override ImmutableArray<PropertySymbol> GetIndexerGroupWorker(CSharpSyntaxNode node, SymbolInfoOptions options, CancellationToken cancellationToken = default(CancellationToken)) { CSharpSyntaxNode bindableNode; BoundNode lowestBoundNode; BoundNode highestBoundNode; BoundNode boundParent; GetBoundNodes(node, out bindableNode, out lowestBoundNode, out highestBoundNode, out boundParent); Debug.Assert(IsInTree(node), "Since the node is in the tree, we can always recompute the binder later"); return base.GetIndexerGroupForNode(lowestBoundNode, binderOpt: null); }
// Gets the method or property group from a specific bound node. // lowestBoundNode: The lowest node in the bound tree associated with node // highestBoundNode: The highest node in the bound tree associated with node // boundNodeForSyntacticParent: The lowest node in the bound tree associated with node.Parent. internal ImmutableArray<Symbol> GetMemberGroupForNode( SymbolInfoOptions options, BoundNode lowestBoundNode, BoundNode boundNodeForSyntacticParent, Binder binderOpt) { var boundExpr = lowestBoundNode as BoundExpression; if (boundExpr != null) { LookupResultKind resultKind; ImmutableArray<Symbol> memberGroup; bool isDynamic; GetSemanticSymbols(boundExpr, boundNodeForSyntacticParent, binderOpt, options, out isDynamic, out resultKind, out memberGroup); return memberGroup; } return ImmutableArray<Symbol>.Empty; }
internal override ImmutableArray<PropertySymbol> GetIndexerGroupWorker(CSharpSyntaxNode node, SymbolInfoOptions options, CancellationToken cancellationToken = default(CancellationToken)) { // in case this is right side of a qualified name or member access (or part of a cref) node = SyntaxFactory.GetStandaloneNode(node); var model = this.GetMemberModel(node); return model == null ? ImmutableArray<PropertySymbol>.Empty : model.GetIndexerGroupWorker(node, options, cancellationToken); }
// Gets symbol info for a type or namespace or alias reference. It is assumed that any error cases will come in // as a type whose OriginalDefinition is an error symbol from which the ResultKind can be retrieved. internal static SymbolInfo GetSymbolInfoForSymbol(Symbol symbol, SymbolInfoOptions options) { Debug.Assert((object)symbol != null); // Determine type. Dig through aliases if necessary. Symbol unwrapped = UnwrapAlias(symbol); TypeSymbol type = unwrapped as TypeSymbol; // Determine symbols and resultKind. var originalErrorSymbol = (object)type != null ? type.OriginalDefinition as ErrorTypeSymbol : null; if ((object)originalErrorSymbol != null) { // Error case. var symbols = ImmutableArray<Symbol>.Empty; LookupResultKind resultKind = originalErrorSymbol.ResultKind; if (resultKind != LookupResultKind.Empty) { symbols = originalErrorSymbol.CandidateSymbols; } if ((options & SymbolInfoOptions.ResolveAliases) != 0) { symbols = UnwrapAliases(symbols); } return SymbolInfoFactory.Create(symbols, resultKind, isDynamic: false); } else { // Non-error case. Use constructor that doesn't require creation of a Symbol array. var symbolToReturn = ((options & SymbolInfoOptions.ResolveAliases) != 0) ? unwrapped : symbol; return new SymbolInfo(symbolToReturn, ImmutableArray<ISymbol>.Empty, CandidateReason.None); } }