|
' Licensed to the .NET Foundation under one or more agreements.
' The .NET Foundation licenses this file to you under the MIT license.
' See the LICENSE file in the project root for more information.
Imports System.Collections.Immutable
Imports System.Diagnostics.CodeAnalysis
Imports System.Runtime.InteropServices
Imports System.Threading
Imports Microsoft.CodeAnalysis.PooledObjects
Imports Microsoft.CodeAnalysis.Text
Imports Microsoft.CodeAnalysis.VisualBasic.Symbols
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Namespace Microsoft.CodeAnalysis.VisualBasic
''' <summary>
''' Allows asking semantic questions about a tree of syntax nodes in a Compilation. Typically,
''' an instance is obtained by a call to Compilation.GetBinding.
''' </summary>
''' <remarks>
''' <para>An instance of SemanticModel caches local symbols and semantic information. Thus, it
''' is much more efficient to use a single instance of SemanticModel when asking multiple
''' questions about a syntax tree, because information from the first question may be reused.
''' This also means that holding onto an instance of SemanticModel for a long time may keep a
''' significant amount of memory from being garbage collected.
''' </para>
''' <para>
''' When an answer is a named symbol that is reachable by traversing from the root of the symbol
''' table, (that is, from an AssemblySymbol of the Compilation), that symbol will be returned
''' (i.e. the returned value will be reference-equal to one reachable from the root of the
''' symbol table). Symbols representing entities without names (e.g. array-of-int) may or may
''' not exhibit reference equality. However, some named symbols (such as local variables) are
''' not reachable from the root. These symbols are visible as answers to semantic questions.
''' When the same SemanticModel object is used, the answers exhibit reference-equality.
''' </para>
''' </remarks>
Friend MustInherit Class VBSemanticModel
Inherits SemanticModel
''' <summary>
''' The compilation associated with this binding.
''' </summary>
Public MustOverride Shadows ReadOnly Property Compilation As VisualBasicCompilation
''' <summary>
''' The root node of the syntax tree that this binding is based on.
''' </summary>
Friend MustOverride Shadows ReadOnly Property Root As SyntaxNode
<Experimental(RoslynExperiments.NullableDisabledSemanticModel, UrlFormat:=RoslynExperiments.NullableDisabledSemanticModel_Url)>
Public NotOverridable Overrides ReadOnly Property NullableAnalysisIsDisabled As Boolean = False
''' <summary>
''' Gets symbol information about an expression syntax node. This is the worker
''' function that is overridden in various derived kinds of Semantic Models. It can assume that
''' CheckSyntaxNode has already been called.
''' </summary>
Friend MustOverride Function GetExpressionSymbolInfo(node As ExpressionSyntax, options As SymbolInfoOptions, Optional cancellationToken As CancellationToken = Nothing) As SymbolInfo
''' <summary>
''' Gets symbol information about the 'Add' method corresponding to an expression syntax <paramref name="node"/> within collection initializer.
''' This is the worker function that is overridden in various derived kinds of Semantic Models. It can assume that
''' CheckSyntaxNode has already been called and the <paramref name="node"/> is in the right place in the syntax tree.
''' </summary>
Friend MustOverride Function GetCollectionInitializerAddSymbolInfo(collectionInitializer As ObjectCreationExpressionSyntax, node As ExpressionSyntax, Optional cancellationToken As CancellationToken = Nothing) As SymbolInfo
''' <summary>
''' Gets symbol information about an attribute syntax node. This is the worker
''' function that is overridden in various derived kinds of Semantic Models. It can assume that
''' CheckSyntaxNode has already been called.
''' </summary>
Friend MustOverride Function GetAttributeSymbolInfo(attribute As AttributeSyntax, Optional cancellationToken As CancellationToken = Nothing) As SymbolInfo
''' <summary>
''' Gets type information about an expression syntax node. This is the worker
''' function that is overridden in various derived kinds of Semantic Models. It can assume that
''' CheckSyntaxNode has already been called.
''' </summary>
Friend MustOverride Function GetExpressionTypeInfo(node As ExpressionSyntax, Optional cancellationToken As CancellationToken = Nothing) As VisualBasicTypeInfo
''' <summary>
''' Gets type information about an attribute syntax node. This is the worker
''' function that is overridden in various derived kinds of Semantic Models. It can assume that
''' CheckSyntaxNode has already been called.
''' </summary>
Friend MustOverride Function GetAttributeTypeInfo(attribute As AttributeSyntax, Optional cancellationToken As CancellationToken = Nothing) As VisualBasicTypeInfo
''' <summary>
''' Gets constant value information about an expression syntax node. This is the worker
''' function that is overridden in various derived kinds of Semantic Models. It can assume that
''' CheckSyntaxNode has already been called.
''' </summary>
Friend MustOverride Function GetExpressionConstantValue(node As ExpressionSyntax, Optional cancellationToken As CancellationToken = Nothing) As ConstantValue
''' <summary>
''' Gets member group information about an expression syntax node. This is the worker
''' function that is overridden in various derived kinds of Semantic Models. It can assume that
''' CheckSyntaxNode has already been called.
''' </summary>
Friend MustOverride Function GetExpressionMemberGroup(node As ExpressionSyntax, Optional cancellationToken As CancellationToken = Nothing) As ImmutableArray(Of Symbol)
''' <summary>
''' Gets member group information about an attribute syntax node. This is the worker
''' function that is overridden in various derived kinds of Semantic Models. It can assume that
''' CheckSyntaxNode has already been called.
''' </summary>
Friend MustOverride Function GetAttributeMemberGroup(attribute As AttributeSyntax, Optional cancellationToken As CancellationToken = Nothing) As ImmutableArray(Of Symbol)
''' <summary>
''' Gets symbol information about a cref reference syntax node. This is the worker
''' function that is overridden in various derived kinds of Semantic Models.
''' </summary>
Friend MustOverride Function GetCrefReferenceSymbolInfo(crefReference As CrefReferenceSyntax, options As SymbolInfoOptions, Optional cancellationToken As CancellationToken = Nothing) As SymbolInfo
' Is this node one that could be successfully interrogated by GetSymbolInfo/GetTypeInfo/GetMemberGroup/GetConstantValue?
Friend Function CanGetSemanticInfo(node As VisualBasicSyntaxNode, Optional allowNamedArgumentName As Boolean = False) As Boolean
Debug.Assert(node IsNot Nothing)
' These aren't really expressions - it's just a manifestation of the SyntaxNode type hierarchy.
If node.Kind = SyntaxKind.XmlName Then
Return False
End If
Dim trivia As StructuredTriviaSyntax = node.EnclosingStructuredTrivia
If trivia IsNot Nothing Then
' Allow getting semantic info on names from Cref and Name attributes
' inside documentation trivia
Return IsInCrefOrNameAttributeInterior(node)
End If
Return Not node.IsMissing AndAlso
(TypeOf (node) Is ExpressionSyntax AndAlso (allowNamedArgumentName OrElse Not SyntaxFacts.IsNamedArgumentName(node)) OrElse
TypeOf (node) Is AttributeSyntax OrElse
TypeOf (node) Is QueryClauseSyntax OrElse
TypeOf (node) Is ExpressionRangeVariableSyntax OrElse
TypeOf (node) Is OrderingSyntax)
End Function
Protected Overrides Function GetOperationCore(node As SyntaxNode, cancellationToken As CancellationToken) As IOperation
Dim vbnode = DirectCast(node, VisualBasicSyntaxNode)
CheckSyntaxNode(vbnode)
Return GetOperationWorker(vbnode, cancellationToken)
End Function
Friend Overridable Function GetOperationWorker(node As VisualBasicSyntaxNode, cancellationToken As CancellationToken) As IOperation
Return Nothing
End Function
''' <summary>
''' Returns what symbol(s), if any, the given expression syntax bound to in the program.
'''
''' An AliasSymbol will never be returned by this method. What the alias refers to will be
''' returned instead. To get information about aliases, call GetAliasInfo.
'''
''' If binding the type name C in the expression "new C(...)" the actual constructor bound to
''' will be returned (or all constructor if overload resolution failed). This occurs as long as C
''' unambiguously binds to a single type that has a constructor. If C ambiguously binds to multiple
''' types, or C binds to a static class, then type(s) are returned.
''' </summary>
Public Shadows Function GetSymbolInfo(expression As ExpressionSyntax, Optional cancellationToken As CancellationToken = Nothing) As SymbolInfo
CheckSyntaxNode(expression)
If CanGetSemanticInfo(expression, allowNamedArgumentName:=True) Then
If SyntaxFacts.IsNamedArgumentName(expression) Then
' Named arguments are handled in a special way.
Return GetNamedArgumentSymbolInfo(DirectCast(expression, IdentifierNameSyntax), cancellationToken)
Else
Return GetExpressionSymbolInfo(expression, SymbolInfoOptions.DefaultOptions, cancellationToken)
End If
Else
Return SymbolInfo.None
End If
End Function
''' <summary>
''' Returns what 'Add' method symbol(s), if any, corresponds to the given expression syntax
''' within <see cref="ObjectCollectionInitializerSyntax.Initializer"/>.
''' </summary>
Public Shadows Function GetCollectionInitializerSymbolInfo(expression As ExpressionSyntax, Optional cancellationToken As CancellationToken = Nothing) As SymbolInfo
CheckSyntaxNode(expression)
If expression.Parent IsNot Nothing AndAlso expression.Parent.Kind = SyntaxKind.CollectionInitializer AndAlso
expression.Parent.Parent IsNot Nothing AndAlso expression.Parent.Parent.Kind = SyntaxKind.ObjectCollectionInitializer AndAlso
DirectCast(expression.Parent.Parent, ObjectCollectionInitializerSyntax).Initializer Is expression.Parent AndAlso
expression.Parent.Parent.Parent IsNot Nothing AndAlso expression.Parent.Parent.Parent.Kind = SyntaxKind.ObjectCreationExpression AndAlso
CanGetSemanticInfo(expression.Parent.Parent.Parent, allowNamedArgumentName:=False) Then
Dim collectionInitializer = DirectCast(expression.Parent.Parent.Parent, ObjectCreationExpressionSyntax)
If collectionInitializer.Initializer Is expression.Parent.Parent Then
Return GetCollectionInitializerAddSymbolInfo(collectionInitializer, expression, cancellationToken)
End If
End If
Return SymbolInfo.None
End Function
''' <summary>
''' Returns what symbol(s), if any, the given cref reference syntax bound to in the documentation comment.
'''
''' An AliasSymbol will never be returned by this method. What the alias refers to will be
''' returned instead.
''' </summary>
Public Shadows Function GetSymbolInfo(crefReference As CrefReferenceSyntax, Optional cancellationToken As CancellationToken = Nothing) As SymbolInfo
CheckSyntaxNode(crefReference)
Return GetCrefReferenceSymbolInfo(crefReference, SymbolInfoOptions.DefaultOptions, cancellationToken)
End Function
''' <summary>
''' Binds the expression 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 an expression 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.
''' </param>
''' <param name="expression">A syntax node that represents a parsed expression. This syntax
''' node need not and typically does not appear in the source code referred to SemanticModel
''' instance.</param>
''' <param name="bindingOption">Indicates whether to binding the expression as a full expressions,
''' or as a type or namespace. If SpeculativeBindingOption.BindAsTypeOrNamespace is supplied, then
''' expression should derive from TypeSyntax.</param>
''' <returns>The semantic information for the topmost node of the expression.</returns>
''' <remarks>The passed in expression is interpreted as a stand-alone expression, as if it
''' appeared by itself somewhere within the scope that encloses "position".</remarks>
Public Shadows Function GetSpeculativeSymbolInfo(position As Integer, expression As ExpressionSyntax, bindingOption As SpeculativeBindingOption) As SymbolInfo
Dim binder As Binder = Nothing ' Passed ByRef to GetSpeculativelyBoundNodeSummary.
Dim bnodeSummary = GetSpeculativelyBoundNodeSummary(position, expression, bindingOption, binder)
If bnodeSummary.LowestBoundNode IsNot Nothing Then
Return Me.GetSymbolInfoForNode(SymbolInfoOptions.DefaultOptions, bnodeSummary, binder)
Else
Return SymbolInfo.None
End If
End Function
''' <summary>
''' Bind the attribute 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 an attribute
''' 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 attribute, position should be the Start position of the Span of the symbol that
''' the attribute is being applied to.
''' </param>
''' <param name="attribute">A syntax node that represents a parsed attribute. This syntax node
''' need not and typically does not appear in the source code referred to SemanticModel instance.</param>
''' <returns>The semantic information for the topmost node of the attribute.</returns>
Public Shadows Function GetSpeculativeSymbolInfo(position As Integer, attribute As AttributeSyntax) As SymbolInfo
Dim binder As Binder = Nothing ' Passed ByRef to GetSpeculativelyBoundNodeSummary.
Dim bnodeSummary = GetSpeculativelyBoundAttributeSummary(position, attribute, binder)
If bnodeSummary.LowestBoundNode IsNot Nothing Then
Return Me.GetSymbolInfoForNode(SymbolInfoOptions.DefaultOptions, bnodeSummary, binder)
Else
Return SymbolInfo.None
End If
End Function
Public Shadows Function GetSymbolInfo(attribute As AttributeSyntax, Optional cancellationToken As CancellationToken = Nothing) As SymbolInfo
CheckSyntaxNode(attribute)
If CanGetSemanticInfo(attribute) Then
Return GetAttributeSymbolInfo(attribute, cancellationToken)
Else
Return SymbolInfo.None
End If
End Function
' Gets the symbol info from a specific bound node
Friend Function GetSymbolInfoForNode(options As SymbolInfoOptions, boundNodes As BoundNodeSummary, binderOpt As Binder) As SymbolInfo
' Determine the symbols, resultKind, and member group.
Dim resultKind As LookupResultKind = LookupResultKind.Empty
Dim memberGroup As ImmutableArray(Of Symbol) = Nothing
Dim symbols As ImmutableArray(Of Symbol) = GetSemanticSymbols(boundNodes, binderOpt, options, resultKind, memberGroup)
Return SymbolInfoFactory.Create(symbols, resultKind)
End Function
''' <summary>
''' Gets type information about an expression.
''' </summary>
''' <param name="expression">The syntax node to get type information for.</param>
Public Shadows Function GetTypeInfo(expression As ExpressionSyntax, Optional cancellationToken As CancellationToken = Nothing) As TypeInfo
Return GetTypeInfoWorker(expression, cancellationToken)
End Function
Friend Overloads Function GetTypeInfoWorker(expression As ExpressionSyntax, Optional cancellationToken As CancellationToken = Nothing) As VisualBasicTypeInfo
CheckSyntaxNode(expression)
If CanGetSemanticInfo(expression) Then
If SyntaxFacts.IsNamedArgumentName(expression) Then
Return VisualBasicTypeInfo.None
Else
Return GetExpressionTypeInfo(expression, cancellationToken)
End If
Else
Return VisualBasicTypeInfo.None
End If
End Function
''' <summary>
''' Binds the expression in the context of the specified location and gets type information.
''' This method is used to get type information about an expression 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.
''' </param>
''' <param name="expression">A syntax node that represents a parsed expression. This syntax
''' node need not and typically does not appear in the source code referred to by the
''' SemanticModel instance.</param>
''' <param name="bindingOption">Indicates whether to binding the expression as a full expressions,
''' or as a type or namespace. If SpeculativeBindingOption.BindAsTypeOrNamespace is supplied, then
''' expression should derive from TypeSyntax.</param>
''' <returns>The type information for the topmost node of the expression.</returns>
''' <remarks>The passed in expression is interpreted as a stand-alone expression, as if it
''' appeared by itself somewhere within the scope that encloses "position".</remarks>
Public Shadows Function GetSpeculativeTypeInfo(position As Integer, expression As ExpressionSyntax, bindingOption As SpeculativeBindingOption) As TypeInfo
Return GetSpeculativeTypeInfoWorker(position, expression, bindingOption)
End Function
Friend Function GetSpeculativeTypeInfoWorker(position As Integer, expression As ExpressionSyntax, bindingOption As SpeculativeBindingOption) As VisualBasicTypeInfo
Dim binder As Binder = Nothing ' passed ByRef to GetSpeculativelyBoundNodeSummary
Dim bnodeSummary = GetSpeculativelyBoundNodeSummary(position, expression, bindingOption, binder)
If bnodeSummary.LowestBoundNode IsNot Nothing Then
Return Me.GetTypeInfoForNode(bnodeSummary)
Else
Return VisualBasicTypeInfo.None
End If
End Function
Public Shadows Function GetTypeInfo(attribute As AttributeSyntax, Optional cancellationToken As CancellationToken = Nothing) As TypeInfo
Return GetTypeInfoWorker(attribute, cancellationToken)
End Function
Private Overloads Function GetTypeInfoWorker(attribute As AttributeSyntax, Optional cancellationToken As CancellationToken = Nothing) As VisualBasicTypeInfo
CheckSyntaxNode(attribute)
If CanGetSemanticInfo(attribute) Then
Return GetAttributeTypeInfo(attribute, cancellationToken)
Else
Return VisualBasicTypeInfo.None
End If
End Function
' Gets the type info from a specific bound node
Friend Function GetTypeInfoForNode(boundNodes As BoundNodeSummary) As VisualBasicTypeInfo
' Determine the type, converted type, and expression
Dim type As TypeSymbol = Nothing
Dim convertedType As TypeSymbol = Nothing
Dim conversion As Conversion = Nothing
type = GetSemanticType(boundNodes, convertedType, conversion)
Return New VisualBasicTypeInfo(type, convertedType, conversion)
End Function
''' <summary>
''' Gets the conversion that occurred between the expression's type and type implied by the expression's context.
''' </summary>
Public Function GetConversion(node As SyntaxNode, Optional cancellationToken As CancellationToken = Nothing) As Conversion
Dim expression = TryCast(node, ExpressionSyntax)
If expression IsNot Nothing Then
Return GetTypeInfoWorker(expression, cancellationToken).ImplicitConversion
End If
Dim attribute = TryCast(node, AttributeSyntax)
If attribute IsNot Nothing Then
Return GetTypeInfoWorker(attribute, cancellationToken).ImplicitConversion
End If
Return VisualBasicTypeInfo.None.ImplicitConversion
End Function
''' <summary>
''' Gets the conversion that occurred between the expression's type and type implied by the expression's context.
''' </summary>
Public Function GetSpeculativeConversion(position As Integer, expression As ExpressionSyntax, bindingOption As SpeculativeBindingOption) As Conversion
Return GetSpeculativeTypeInfoWorker(position, expression, bindingOption).ImplicitConversion
End Function
Public Shadows Function GetConstantValue(expression As ExpressionSyntax, Optional cancellationToken As CancellationToken = Nothing) As [Optional](Of Object)
CheckSyntaxNode(expression)
If CanGetSemanticInfo(expression) Then
Dim val As ConstantValue = GetExpressionConstantValue(expression, cancellationToken)
If val IsNot Nothing AndAlso Not val.IsBad Then
Return New [Optional](Of Object)(val.Value)
End If
End If
Return Nothing
End Function
''' <summary>
''' Binds the expression in the context of the specified location and gets constant value information.
''' This method is used to get information about an expression 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.
''' </param>
''' <param name="expression">A syntax node that represents a parsed expression. This syntax
''' node need not and typically does not appear in the source code referred to by SemanticModel
''' instance.</param>
''' <remarks>The passed in expression is interpreted as a stand-alone expression, as if it
''' appeared by itself somewhere within the scope that encloses "position".</remarks>
Public Shadows Function GetSpeculativeConstantValue(position As Integer, expression As ExpressionSyntax) As [Optional](Of Object)
Dim binder As Binder = Nothing ' passed ByRef to GetSpeculativelyBoundNodeSummary
Dim bnodeSummary = GetSpeculativelyBoundNodeSummary(position, expression, SpeculativeBindingOption.BindAsExpression, binder)
If bnodeSummary.LowestBoundNode IsNot Nothing Then
Dim val As ConstantValue = Me.GetConstantValueForNode(bnodeSummary)
If val IsNot Nothing AndAlso Not val.IsBad Then
Return New [Optional](Of Object)(val.Value)
End If
End If
Return Nothing
End Function
Friend Function GetConstantValueForNode(boundNodes As BoundNodeSummary) As ConstantValue
Dim constValue As ConstantValue = Nothing
Dim lowerExpr = TryCast(boundNodes.LowestBoundNode, BoundExpression)
If lowerExpr IsNot Nothing Then
constValue = lowerExpr.ConstantValueOpt
End If
Return constValue
End Function
Public Shadows Function GetMemberGroup(expression As ExpressionSyntax, Optional cancellationToken As CancellationToken = Nothing) As ImmutableArray(Of ISymbol)
CheckSyntaxNode(expression)
If CanGetSemanticInfo(expression) Then
Dim result = GetExpressionMemberGroup(expression, cancellationToken)
#If DEBUG Then
For Each item In result
Debug.Assert(item.Kind <> SymbolKind.Namespace)
Next
#End If
Return StaticCast(Of ISymbol).From(result)
Else
Return ImmutableArray(Of ISymbol).Empty
End If
End Function
Public Shadows Function GetSpeculativeMemberGroup(position As Integer, expression As ExpressionSyntax) As ImmutableArray(Of ISymbol)
Dim binder As Binder = Nothing ' passed ByRef to GetSpeculativelyBoundNodeSummary
Dim bnodeSummary = GetSpeculativelyBoundNodeSummary(position, expression, SpeculativeBindingOption.BindAsExpression, binder)
If bnodeSummary.LowestBoundNode IsNot Nothing Then
Dim result = Me.GetMemberGroupForNode(bnodeSummary, binderOpt:=Nothing)
#If DEBUG Then
For Each item In result
Debug.Assert(item.Kind <> SymbolKind.Namespace)
Next
#End If
Return StaticCast(Of ISymbol).From(result)
Else
Return ImmutableArray(Of ISymbol).Empty
End If
End Function
Public Shadows Function GetMemberGroup(attribute As AttributeSyntax, Optional cancellationToken As CancellationToken = Nothing) As ImmutableArray(Of ISymbol)
CheckSyntaxNode(attribute)
If CanGetSemanticInfo(attribute) Then
Dim result = GetAttributeMemberGroup(attribute, cancellationToken)
#If DEBUG Then
For Each item In result
Debug.Assert(item.Kind <> SymbolKind.Namespace)
Next
#End If
Return StaticCast(Of ISymbol).From(result)
Else
Return ImmutableArray(Of ISymbol).Empty
End If
End Function
Friend Function GetMemberGroupForNode(boundNodes As BoundNodeSummary, binderOpt As Binder) As ImmutableArray(Of Symbol)
' Determine the symbols, resultKind, and member group.
Dim resultKind As LookupResultKind = LookupResultKind.Empty
Dim memberGroup As ImmutableArray(Of Symbol) = Nothing
Dim symbols As ImmutableArray(Of Symbol) = GetSemanticSymbols(boundNodes, binderOpt, SymbolInfoOptions.DefaultOptions, resultKind, memberGroup)
Return memberGroup
End Function
''' <summary>
''' If "nameSyntax" resolves to an alias name, return the AliasSymbol corresponding
''' to A. Otherwise return null.
''' </summary>
Public Shadows Function GetAliasInfo(nameSyntax As IdentifierNameSyntax, Optional cancellationToken As CancellationToken = Nothing) As IAliasSymbol
CheckSyntaxNode(nameSyntax)
If CanGetSemanticInfo(nameSyntax) Then
Dim info = GetExpressionSymbolInfo(nameSyntax, SymbolInfoOptions.PreferTypeToConstructors Or SymbolInfoOptions.PreserveAliases, cancellationToken)
Return TryCast(info.Symbol, IAliasSymbol)
Else
Return Nothing
End If
End Function
''' <summary>
''' Binds the name in the context of the specified location and sees if it resolves to an
''' alias name. If it does, return the AliasSymbol corresponding to it. Otherwise, return null.
''' </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.
''' </param>
''' <param name="nameSyntax">A syntax node that represents a name. This syntax
''' node need not and typically does not appear in the source code referred to by the
''' SemanticModel instance.</param>
''' <param name="bindingOption">Indicates whether to binding the name as a full expression,
''' or as a type or namespace. If SpeculativeBindingOption.BindAsTypeOrNamespace is supplied, then
''' expression should derive from TypeSyntax.</param>
''' <remarks>The passed in name is interpreted as a stand-alone name, as if it
''' appeared by itself somewhere within the scope that encloses "position".</remarks>
Public Shadows Function GetSpeculativeAliasInfo(position As Integer, nameSyntax As IdentifierNameSyntax, bindingOption As SpeculativeBindingOption) As IAliasSymbol
Dim binder As Binder = Nothing
Dim bnodeSummary = GetSpeculativelyBoundNodeSummary(position, nameSyntax, bindingOption, binder)
If bnodeSummary.LowestBoundNode IsNot Nothing Then
Dim info As SymbolInfo = Me.GetSymbolInfoForNode(SymbolInfoOptions.PreferTypeToConstructors Or SymbolInfoOptions.PreserveAliases, bnodeSummary, binderOpt:=binder)
Return TryCast(info.Symbol, IAliasSymbol)
Else
Return Nothing
End If
End Function
''' <summary>
''' Gets the binder that encloses the position. See comment on LookupSymbols for how
''' positions are interpreted.
''' </summary>
Friend MustOverride Function GetEnclosingBinder(position As Integer) As Binder
Friend Function IsInTree(node As SyntaxNode) As Boolean
Return IsUnderNode(node, Me.Root)
End Function
Private Shared Function IsUnderNode(node As SyntaxNode, root As SyntaxNode) As Boolean
While node IsNot Nothing
If node Is root Then
Return True
End If
If node.IsStructuredTrivia Then
node = DirectCast(node, StructuredTriviaSyntax).ParentTrivia.Token.Parent
Else
node = node.Parent
End If
End While
Return False
End Function
' Checks that a position is within the span of the root of this binding.
Protected Sub CheckPosition(position As Integer)
Dim fullStart As Integer = Root.Position
Dim fullEnd As Integer = Root.EndPosition
' Is position at the actual end of file (not just end of Root.FullSpan)?
Dim atEOF As Boolean = (position = fullEnd AndAlso position = SyntaxTree.GetRoot().FullSpan.End)
If (fullStart <= position AndAlso position < fullEnd) OrElse
atEOF OrElse
(fullStart = fullEnd AndAlso position = fullEnd) Then
Return
End If
Throw New ArgumentException(VBResources.PositionIsNotWithinSyntax)
End Sub
Friend Sub CheckSyntaxNode(node As VisualBasicSyntaxNode)
If node Is Nothing Then
Throw New ArgumentNullException(NameOf(node))
End If
If Not IsInTree(node) Then
Throw New ArgumentException(VBResources.NodeIsNotWithinSyntaxTree)
End If
End Sub
Private Sub CheckModelAndSyntaxNodeToSpeculate(node As VisualBasicSyntaxNode)
If node Is Nothing Then
Throw New ArgumentNullException(NameOf(node))
End If
If Me.IsSpeculativeSemanticModel Then
Throw New InvalidOperationException(VBResources.ChainingSpeculativeModelIsNotSupported)
End If
If Me.Compilation.ContainsSyntaxTree(node.SyntaxTree) Then
Throw New ArgumentException(VBResources.SpeculatedSyntaxNodeCannotBelongToCurrentCompilation)
End If
End Sub
' Find the initial syntax node to start traversing up the syntax when getting binders from
' a position. Just using FindToken doesn't give quite the right results, especially in situations where
' end constructs haven't been typed yet. If we are in the trivia between two tokens, we move backward to the previous
' token. There are also some special cases around beginning and end of the whole tree.
Friend Function FindInitialNodeFromPosition(position As Integer) As SyntaxNode
Dim fullStart As Integer = Root.Position
Dim fullEnd As Integer = Root.EndPosition
' Is position at the actual end of file (not just end of Root.FullSpan)?
Dim atEOF As Boolean = (position = fullEnd AndAlso position = SyntaxTree.GetRoot().FullSpan.End)
If (fullStart <= position AndAlso position < fullEnd) OrElse atEOF Then
Dim token As SyntaxToken
If atEOF Then
token = SyntaxTree.GetRoot().FindToken(position, True)
Else
token = Root.FindToken(position, True)
End If
Dim trivia As StructuredTriviaSyntax = DirectCast(token.Parent, VisualBasicSyntaxNode).EnclosingStructuredTrivia
If trivia Is Nothing OrElse Not IsInCrefOrNameAttributeInterior(DirectCast(token.Parent, VisualBasicSyntaxNode)) Then
If atEOF Then
token = SyntaxTree.GetRoot().FindToken(position)
Else
token = Root.FindToken(position)
End If
End If
If (position < token.SpanStart) Then
' Before the start of this token, go to previous token.
token = token.GetPreviousToken(includeSkipped:=False, includeDirectives:=False, includeDocumentationComments:=False)
End If
' If the first token in the root is missing, it's possible to step backwards
' past the start of the root. All sorts of bad things will happen in that case,
' so just use the root.
If token.SpanStart < fullStart Then
Return Root
ElseIf token.Parent IsNot Nothing Then
Debug.Assert(IsInTree(token.Parent))
Return DirectCast(token.Parent, VisualBasicSyntaxNode)
Else
Return Root
End If
ElseIf fullStart = fullEnd AndAlso position = fullEnd Then
' The root is an empty span and isn't the full compilation unit. No other choice here.
Return Root
End If
' Should have been caught by CheckPosition
Throw ExceptionUtilities.Unreachable
End Function
' Is this node in a place where it bind to an implemented member.
Friend Shared Function IsInCrefOrNameAttributeInterior(node As VisualBasicSyntaxNode) As Boolean
Debug.Assert(node IsNot Nothing)
Select Case node.Kind
Case SyntaxKind.IdentifierName,
SyntaxKind.GenericName,
SyntaxKind.PredefinedType,
SyntaxKind.QualifiedName,
SyntaxKind.GlobalName,
SyntaxKind.QualifiedCrefOperatorReference,
SyntaxKind.CrefOperatorReference,
SyntaxKind.CrefReference,
SyntaxKind.XmlString
' fall through
Case Else
Return False
End Select
Dim parent As VisualBasicSyntaxNode = node.Parent
Dim inXmlAttribute As Boolean = False
While parent IsNot Nothing
Select Case parent.Kind
Case SyntaxKind.XmlCrefAttribute,
SyntaxKind.XmlNameAttribute
Return True
Case SyntaxKind.XmlAttribute
inXmlAttribute = True
parent = parent.Parent
Case SyntaxKind.DocumentationCommentTrivia
If inXmlAttribute Then
Return True
End If
parent = parent.Parent
Case Else
parent = parent.Parent
End Select
End While
Return False
End Function
Friend Function GetSpeculativeBinderForExpression(position As Integer, expression As ExpressionSyntax, bindingOption As SpeculativeBindingOption) As SpeculativeBinder
Debug.Assert(expression IsNot Nothing)
CheckPosition(position)
If bindingOption = SpeculativeBindingOption.BindAsTypeOrNamespace Then
If TryCast(expression, TypeSyntax) Is Nothing Then
Return Nothing
End If
End If
Dim binder = Me.GetEnclosingBinder(position)
' Add speculative binder to bind speculatively.
Return If(binder IsNot Nothing, SpeculativeBinder.Create(binder), Nothing)
End Function
Private Function GetSpeculativelyBoundNode(
binder As Binder,
expression As ExpressionSyntax,
bindingOption As SpeculativeBindingOption
) As BoundNode
Debug.Assert(binder IsNot Nothing)
Debug.Assert(binder.IsSemanticModelBinder)
Debug.Assert(expression IsNot Nothing)
Debug.Assert(bindingOption <> SpeculativeBindingOption.BindAsTypeOrNamespace OrElse
TryCast(expression, TypeSyntax) IsNot Nothing)
Dim bnode As BoundNode
If bindingOption = SpeculativeBindingOption.BindAsTypeOrNamespace Then
bnode = binder.BindNamespaceOrTypeExpression(DirectCast(expression, TypeSyntax), BindingDiagnosticBag.Discarded)
Else
Debug.Assert(bindingOption = SpeculativeBindingOption.BindAsExpression)
bnode = Me.Bind(binder, expression, BindingDiagnosticBag.Discarded)
bnode = MakeValueIfPossible(binder, bnode)
End If
Return bnode
End Function
Friend Function GetSpeculativelyBoundNode(position As Integer,
expression As ExpressionSyntax,
bindingOption As SpeculativeBindingOption,
<Out> ByRef binder As Binder) As BoundNode
Debug.Assert(expression IsNot Nothing)
binder = Me.GetSpeculativeBinderForExpression(position, expression, bindingOption)
If binder IsNot Nothing Then
Dim bnode = Me.GetSpeculativelyBoundNode(binder, expression, bindingOption)
Return bnode
Else
Return Nothing
End If
End Function
Private Function GetSpeculativelyBoundNodeSummary(position As Integer,
expression As ExpressionSyntax,
bindingOption As SpeculativeBindingOption,
<Out> ByRef binder As Binder) As BoundNodeSummary
If expression Is Nothing Then
Throw New ArgumentNullException(NameOf(expression))
End If
Dim standalone = SyntaxFactory.GetStandaloneExpression(expression)
Dim bnode = Me.GetSpeculativelyBoundNode(position, standalone, bindingOption, binder)
If bnode IsNot Nothing Then
Debug.Assert(binder IsNot Nothing)
Return New BoundNodeSummary(bnode, bnode, Nothing)
Else
Return Nothing
End If
End Function
''' <summary>
''' When doing speculative binding, we don't have any context information about expressions or the
''' context that is expected. We try to interpret as a value, but
''' only if it doesn't cause additional errors (indicating that it wasn't value to interpret it
''' that way). This should get us the most "liberal" interpretation
''' for semantic information.
''' </summary>
Private Function MakeValueIfPossible(binder As Binder, node As BoundNode) As BoundNode
' Convert a stand-alone speculatively bound expression to an rvalue.
' This will get the value of properties, convert lambdas to anonymous
' delegate type, etc.
Dim boundExpression = TryCast(node, BoundExpression)
If boundExpression IsNot Nothing Then
' Try calling ReclassifyAsValue
Dim diagnostics = BindingDiagnosticBag.GetInstance(withDiagnostics:=True, withDependencies:=False)
Dim resultNode = binder.ReclassifyAsValue(boundExpression, diagnostics)
' Reclassify ArrayLiterals and other expressions missing types to expressions with types.
If Not resultNode.HasErrors AndAlso resultNode.Type Is Nothing Then
resultNode = binder.ReclassifyExpression(resultNode, diagnostics)
End If
Dim noErrors As Boolean = Not diagnostics.HasAnyErrors()
diagnostics.Free()
If noErrors Then
Return resultNode
End If
End If
Return node
End Function
Private Function GetSpeculativeAttributeBinder(position As Integer, attribute As AttributeSyntax) As AttributeBinder
Debug.Assert(attribute IsNot Nothing)
CheckPosition(position)
Dim binder = Me.GetEnclosingBinder(position)
' Add speculative attribute binder to bind speculatively.
Return If(binder IsNot Nothing,
BinderBuilder.CreateBinderForAttribute(binder.SyntaxTree, binder, attribute),
Nothing)
End Function
''' <summary>
''' Bind the given attribute speculatively at the given position, and return back
''' the resulting bound node. May return null in some error cases.
''' </summary>
Friend Function GetSpeculativelyBoundAttribute(position As Integer, attribute As AttributeSyntax, <Out> ByRef binder As Binder) As BoundAttribute
binder = Me.GetSpeculativeAttributeBinder(position, attribute)
If binder IsNot Nothing Then
Dim bnode As BoundAttribute = binder.BindAttribute(attribute, BindingDiagnosticBag.Discarded)
Return bnode
Else
Return Nothing
End If
End Function
''' <summary>
''' Bind the given attribute speculatively at the given position, and return back
''' the resulting bound node summary. May return null in some error cases.
''' </summary>
Private Function GetSpeculativelyBoundAttributeSummary(position As Integer, attribute As AttributeSyntax, <Out> ByRef binder As Binder) As BoundNodeSummary
If attribute Is Nothing Then
Throw New ArgumentNullException(NameOf(attribute))
End If
Dim bnode = GetSpeculativelyBoundAttribute(position, attribute, binder)
If bnode IsNot Nothing Then
Debug.Assert(binder IsNot Nothing)
Return New BoundNodeSummary(bnode, bnode, Nothing)
Else
Return Nothing
End If
End Function
' Given a diagnosticInfo, add any symbols from the diagnosticInfo to the symbol builder.
Private Sub AddSymbolsFromDiagnosticInfo(symbolsBuilder As ArrayBuilder(Of Symbol), diagnosticInfo As DiagnosticInfo)
Dim diagInfoWithSymbols = TryCast(diagnosticInfo, IDiagnosticInfoWithSymbols)
If diagInfoWithSymbols IsNot Nothing Then
diagInfoWithSymbols.GetAssociatedSymbols(symbolsBuilder)
End If
End Sub
' Given a symbolsBuilder with a bunch of symbols in it, return an ImmutableArray containing
' just the symbols that are not ErrorTypeSymbols, and without any duplicates.
Friend Function RemoveErrorTypesAndDuplicates(symbolsBuilder As ArrayBuilder(Of Symbol), options As SymbolInfoOptions) As ImmutableArray(Of Symbol)
' Common case is 0 or 1 symbol, so we optimize those cases to not allocate a HashSet, since
' duplicates aren't possible for those cases.
If symbolsBuilder.Count = 0 Then
Return ImmutableArray(Of Symbol).Empty
ElseIf symbolsBuilder.Count = 1 Then
Dim s = symbolsBuilder(0)
If (options And SymbolInfoOptions.ResolveAliases) <> 0 Then
s = UnwrapAlias(s)
End If
If TypeOf s Is ErrorTypeSymbol Then
symbolsBuilder.Clear()
AddSymbolsFromDiagnosticInfo(symbolsBuilder, DirectCast(s, ErrorTypeSymbol).ErrorInfo)
Return symbolsBuilder.ToImmutable()
Else
Return ImmutableArray.Create(s)
End If
Else
' 2 or more symbols. Use a hash set to remove duplicates.
Dim symbolSet = PooledHashSet(Of Symbol).GetInstance()
For Each s In symbolsBuilder
If (options And SymbolInfoOptions.ResolveAliases) <> 0 Then
s = UnwrapAlias(s)
End If
If TypeOf s Is ErrorTypeSymbol Then
Dim tempBuilder As ArrayBuilder(Of Symbol) = ArrayBuilder(Of Symbol).GetInstance()
AddSymbolsFromDiagnosticInfo(tempBuilder, DirectCast(s, ErrorTypeSymbol).ErrorInfo)
For Each sym In tempBuilder
symbolSet.Add(sym)
Next
tempBuilder.Free()
Else
symbolSet.Add(s)
End If
Next
Dim result = ImmutableArray.CreateRange(symbolSet)
symbolSet.Free()
Return result
End If
End Function
' Given the lower and upper bound expressions, get the type, converted type, and conversion.
Private Function GetSemanticType(boundNodes As BoundNodeSummary,
ByRef convertedType As TypeSymbol,
ByRef conversion As Conversion) As TypeSymbol
convertedType = Nothing
conversion = New Conversion(Conversions.Identity)
Dim lowestExpr = TryCast(boundNodes.LowestBoundNode, BoundExpression)
Dim highestExpr = TryCast(boundNodes.HighestBoundNode, BoundExpression)
If lowestExpr Is Nothing Then
' Only BoundExpressions have a type.
Return Nothing
End If
' Do not return any type information for a ObjectCreationExpressionSyntax.Type node.
If boundNodes.LowestBoundNodeOfSyntacticParent IsNot Nothing AndAlso
boundNodes.LowestBoundNodeOfSyntacticParent.Syntax.Kind = SyntaxKind.ObjectCreationExpression AndAlso
DirectCast(boundNodes.LowestBoundNodeOfSyntacticParent.Syntax, ObjectCreationExpressionSyntax).Type Is lowestExpr.Syntax Then
Return Nothing
End If
Dim type As TypeSymbol
' Similar to a lambda expression, array literal doesn't have a type.
' However, during binding we create BoundArrayCreation node that has type the literal got converted to.
' Let's account for that.
If lowestExpr.Kind = BoundKind.ArrayCreation AndAlso DirectCast(lowestExpr, BoundArrayCreation).ArrayLiteralOpt IsNot Nothing Then
type = Nothing
conversion = New Conversion(New KeyValuePair(Of ConversionKind, MethodSymbol)(DirectCast(lowestExpr, BoundArrayCreation).ArrayLiteralConversion, Nothing))
ElseIf lowestExpr.Kind = BoundKind.ConvertedTupleLiteral Then
type = DirectCast(lowestExpr, BoundConvertedTupleLiteral).NaturalTypeOpt
Else
type = lowestExpr.Type
End If
Dim useOfLocalBeforeDeclaration As Boolean = False
' Use of local before declaration requires some additional fixup.
' Due complications around implicit locals and type inference, we do not
' try to obtain a type of a local when it is used before declaration, we use
' a special error type symbol. However, semantic model should return the same
' type information for usage of a local before and after its declaration.
' We will detect the use before declaration cases and replace the error type
' symbol with the one obtained from the local. It is safe to get the type
' from the local at this point because we have already bound the whole method
' body if implicit locals were allowed.
If type Is LocalSymbol.UseBeforeDeclarationResultType AndAlso
lowestExpr.Kind = BoundKind.Local Then
useOfLocalBeforeDeclaration = True
type = DirectCast(lowestExpr, BoundLocal).LocalSymbol.Type
End If
' See if the node is being implicitly converted to another type. If so, there would
' be a higher conversion node associated to the same syntax node.
If highestExpr IsNot Nothing Then
If highestExpr.Type IsNot Nothing AndAlso highestExpr.Type.TypeKind <> TypeKind.Error Then
convertedType = highestExpr.Type
If (type Is Nothing OrElse Not type.IsSameTypeIgnoringAll(convertedType)) Then
' If the upper expression is of a different type, we want to return
' a conversion. Hopefully we have a conversion node.
' TODO: Understand cases where we don't have a conversion node better.
If highestExpr.Kind = BoundKind.Conversion Then
Dim conversionNode = DirectCast(highestExpr, BoundConversion)
If useOfLocalBeforeDeclaration AndAlso Not type.IsErrorType() Then
conversion = New Conversion(Conversions.ClassifyConversion(type, convertedType, CompoundUseSiteInfo(Of AssemblySymbol).Discarded))
Else
conversion = New Conversion(KeyValuePairUtil.Create(conversionNode.ConversionKind,
TryCast(conversionNode.ExpressionSymbol, MethodSymbol)))
End If
End If
End If
End If
End If
If type Is Nothing AndAlso TypeOf boundNodes.LowestBoundNodeOfSyntacticParent Is BoundBadExpression Then
' Special case: overload failure on X in New X(...), where overload resolution failed.
' Binds to method group which can't have a type.
Dim parentSyntax As SyntaxNode = boundNodes.LowestBoundNodeOfSyntacticParent.Syntax
If parentSyntax IsNot Nothing AndAlso
parentSyntax Is boundNodes.LowestBoundNode.Syntax.Parent AndAlso
((parentSyntax.Kind = SyntaxKind.ObjectCreationExpression AndAlso (DirectCast(parentSyntax, ObjectCreationExpressionSyntax).Type Is boundNodes.LowestBoundNode.Syntax))) Then
type = DirectCast(boundNodes.LowestBoundNodeOfSyntacticParent, BoundBadExpression).Type
End If
End If
' If we didn't have a converted type, then use the type.
If convertedType Is Nothing Then
convertedType = type
End If
Return type
End Function
' Given the lower and upper bound expressions, get the symbols, resultkind, and member group.
Private Function GetSemanticSymbols(boundNodes As BoundNodeSummary,
binderOpt As Binder,
options As SymbolInfoOptions,
ByRef resultKind As LookupResultKind,
ByRef memberGroup As ImmutableArray(Of Symbol)) As ImmutableArray(Of Symbol)
' TODO: Understand the case patched by TODO in GetSemanticInfoForNode and create a better fix.
Dim symbolsBuilder = ArrayBuilder(Of Symbol).GetInstance()
Dim memberGroupBuilder = ArrayBuilder(Of Symbol).GetInstance()
resultKind = LookupResultKind.Good ' assume good unless we find out otherwise.
If boundNodes.LowestBoundNode IsNot Nothing Then
Select Case boundNodes.LowestBoundNode.Kind
Case BoundKind.MethodGroup
' Complex enough to split out into its own function.
GetSemanticSymbolsForMethodGroup(boundNodes, symbolsBuilder, memberGroupBuilder, resultKind)
Case BoundKind.PropertyGroup
' Complex enough to split out into its own function.
GetSemanticSymbolsForPropertyGroup(boundNodes, symbolsBuilder, memberGroupBuilder, resultKind)
Case BoundKind.TypeExpression
' Watch out for not creatable types within object creation syntax
If boundNodes.LowestBoundNodeOfSyntacticParent IsNot Nothing AndAlso
boundNodes.LowestBoundNodeOfSyntacticParent.Syntax.Kind = SyntaxKind.ObjectCreationExpression AndAlso
DirectCast(boundNodes.LowestBoundNodeOfSyntacticParent.Syntax, ObjectCreationExpressionSyntax).Type Is boundNodes.LowestBoundNode.Syntax AndAlso
boundNodes.LowestBoundNodeOfSyntacticParent.Kind = BoundKind.BadExpression AndAlso
DirectCast(boundNodes.LowestBoundNodeOfSyntacticParent, BoundBadExpression).ResultKind = LookupResultKind.NotCreatable Then
resultKind = LookupResultKind.NotCreatable
End If
' We want to return the alias symbol if one exists, otherwise the type symbol.
' If its an error type look at underlying symbols and kind.
' The alias symbol is latter mapped to its target depending on options in RemoveErrorTypesAndDuplicates.
Dim boundType = DirectCast(boundNodes.LowestBoundNode, BoundTypeExpression)
If boundType.AliasOpt IsNot Nothing Then
symbolsBuilder.Add(boundType.AliasOpt)
Else
Dim typeSymbol As TypeSymbol = boundType.Type
Dim originalErrorType = TryCast(typeSymbol.OriginalDefinition, ErrorTypeSymbol)
If originalErrorType IsNot Nothing Then
resultKind = originalErrorType.ResultKind
symbolsBuilder.AddRange(originalErrorType.CandidateSymbols)
Else
symbolsBuilder.Add(typeSymbol)
End If
End If
Case BoundKind.Attribute
Debug.Assert(boundNodes.LowestBoundNodeOfSyntacticParent Is Nothing)
Dim attribute = DirectCast(boundNodes.LowestBoundNode, BoundAttribute)
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.
Dim namedType = DirectCast(attribute.Type, NamedTypeSymbol)
If namedType.IsErrorType() Then
Debug.Assert(resultKind <> LookupResultKind.Good)
Dim errorType = DirectCast(namedType, ErrorTypeSymbol)
Dim 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 AndAlso candidateSymbols(0).Kind = SymbolKind.NamedType Then
namedType = DirectCast(errorType.CandidateSymbols(0), NamedTypeSymbol)
Else
symbolsBuilder.AddRange(candidateSymbols)
Exit Select
End If
End If
Dim symbols = ImmutableArray(Of Symbol).Empty
AdjustSymbolsForObjectCreation(attribute, namedType, attribute.Constructor, binderOpt, symbols, memberGroupBuilder, resultKind)
symbolsBuilder.AddRange(symbols)
Case BoundKind.ObjectCreationExpression
Dim creation = DirectCast(boundNodes.LowestBoundNode, BoundObjectCreationExpression)
If creation.MethodGroupOpt IsNot Nothing Then
creation.MethodGroupOpt.GetExpressionSymbols(memberGroupBuilder)
resultKind = creation.MethodGroupOpt.ResultKind
End If
If creation.ConstructorOpt IsNot Nothing Then
symbolsBuilder.Add(creation.ConstructorOpt)
Else
symbolsBuilder.AddRange(memberGroupBuilder)
End If
Case BoundKind.LateMemberAccess
GetSemanticSymbolsForLateBoundMemberAccess(boundNodes, symbolsBuilder, memberGroupBuilder, resultKind)
Case BoundKind.LateInvocation
Dim lateInvocation = DirectCast(boundNodes.LowestBoundNode, BoundLateInvocation)
GetSemanticSymbolsForLateBoundInvocation(lateInvocation, symbolsBuilder, memberGroupBuilder, resultKind)
Case BoundKind.MyBaseReference,
BoundKind.MeReference,
BoundKind.MyClassReference
Dim meReference = DirectCast(boundNodes.LowestBoundNode, BoundExpression)
Dim binder As Binder = If(binderOpt, GetEnclosingBinder(boundNodes.LowestBoundNode.Syntax.SpanStart))
Dim containingType As NamedTypeSymbol = binder.ContainingType
Dim containingMember = binder.ContainingMember
Dim meParam As ParameterSymbol = GetMeParameter(meReference.Type, containingType, containingMember, resultKind)
symbolsBuilder.Add(meParam)
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.
Dim boundTypeOrValue = DirectCast(boundNodes.LowestBoundNode, BoundTypeOrValueExpression)
Dim valueBoundNodes = New BoundNodeSummary(boundTypeOrValue.Data.ValueExpression, boundNodes.HighestBoundNode, boundNodes.LowestBoundNodeOfSyntacticParent)
Return GetSemanticSymbols(valueBoundNodes, binderOpt, options, resultKind, memberGroup)
Case Else
_Default:
' Currently, only nodes deriving from BoundExpression have symbols or
' resultkind. If this turns out to be too restrictive, we can move them up
' the hierarchy.
Dim lowestExpr = TryCast(boundNodes.LowestBoundNode, BoundExpression)
If lowestExpr IsNot Nothing Then
lowestExpr.GetExpressionSymbols(symbolsBuilder)
resultKind = lowestExpr.ResultKind
If lowestExpr.Kind = BoundKind.BadExpression AndAlso lowestExpr.Syntax.Kind = SyntaxKind.ObjectCreationExpression Then
' Look for a method group under this bad node
Dim typeSyntax = DirectCast(lowestExpr.Syntax, ObjectCreationExpressionSyntax).Type
For Each child In DirectCast(lowestExpr, BoundBadExpression).ChildBoundNodes
If child.Kind = BoundKind.MethodGroup AndAlso child.Syntax Is typeSyntax Then
Dim group = DirectCast(child, BoundMethodGroup)
group.GetExpressionSymbols(memberGroupBuilder)
If resultKind = LookupResultKind.NotCreatable Then
resultKind = group.ResultKind
Else
resultKind = LookupResult.WorseResultKind(resultKind, group.ResultKind)
End If
Exit For
End If
Next
End If
End If
End Select
End If
Dim bindingSymbols As ImmutableArray(Of Symbol) = RemoveErrorTypesAndDuplicates(symbolsBuilder, options)
symbolsBuilder.Free()
If boundNodes.LowestBoundNodeOfSyntacticParent IsNot Nothing AndAlso (options And SymbolInfoOptions.PreferConstructorsToType) <> 0 Then
' Adjust symbols to get the constructors if we're T in a "New T(...)".
AdjustSymbolsForObjectCreation(boundNodes, binderOpt, bindingSymbols, memberGroupBuilder, resultKind)
End If
memberGroup = memberGroupBuilder.ToImmutableAndFree()
' We have a different highest bound node than lowest bound node. If it has a result kind less good than the
' one we already determined, use that. This is typically the case where a BoundBadExpression or BoundBadValue
' is created around another expression.
' CONSIDER: Can it arise that the highest node has associated symbols but the lowest node doesn't? In that case,
' we may wish to use the symbols from the highest.
Dim highestBoundNodeExpr = TryCast(boundNodes.HighestBoundNode, BoundExpression)
If highestBoundNodeExpr IsNot Nothing AndAlso boundNodes.HighestBoundNode IsNot boundNodes.LowestBoundNode Then
If highestBoundNodeExpr.ResultKind <> LookupResultKind.Empty AndAlso highestBoundNodeExpr.ResultKind < resultKind Then
resultKind = highestBoundNodeExpr.ResultKind
End If
If highestBoundNodeExpr.Kind = BoundKind.BadExpression AndAlso bindingSymbols.Length = 0 Then
' If we didn't have symbols from the lowest, maybe the bad expression has symbols.
bindingSymbols = DirectCast(highestBoundNodeExpr, BoundBadExpression).Symbols
End If
End If
Return bindingSymbols
End Function
Private Shared Function GetMeParameter(referenceType As TypeSymbol,
containingType As TypeSymbol,
containingMember As Symbol,
ByRef resultKind As LookupResultKind) As ParameterSymbol
If containingMember Is Nothing OrElse containingType Is Nothing Then
' not in a member of a type (can happen when speculating)
resultKind = LookupResultKind.NotReferencable
Return New MeParameterSymbol(containingMember, referenceType)
End If
Dim meParam As ParameterSymbol
Select Case containingMember.Kind
Case SymbolKind.Method, SymbolKind.Field, SymbolKind.Property
If containingMember.IsShared Then
' in a static member
resultKind = LookupResultKind.MustNotBeInstance
meParam = New MeParameterSymbol(containingMember, containingType)
Else
If TypeSymbol.Equals(referenceType, ErrorTypeSymbol.UnknownResultType, TypeCompareKind.ConsiderEverything) Then
' in an instance member, but binder considered Me/MyBase/MyClass unreferenceable
meParam = New MeParameterSymbol(containingMember, containingType)
resultKind = LookupResultKind.NotReferencable
Else
' should be good
resultKind = LookupResultKind.Good
meParam = containingMember.GetMeParameter()
End If
End If
Case Else
meParam = New MeParameterSymbol(containingMember, referenceType)
resultKind = LookupResultKind.NotReferencable
End Select
Return meParam
End Function
Private Sub GetSemanticSymbolsForLateBoundInvocation(lateInvocation As BoundLateInvocation,
symbolsBuilder As ArrayBuilder(Of Symbol),
memberGroupBuilder As ArrayBuilder(Of Symbol),
ByRef resultKind As LookupResultKind)
resultKind = LookupResultKind.LateBound
Dim group = lateInvocation.MethodOrPropertyGroupOpt
If group IsNot Nothing Then
group.GetExpressionSymbols(memberGroupBuilder)
group.GetExpressionSymbols(symbolsBuilder)
End If
End Sub
Private Sub GetSemanticSymbolsForLateBoundMemberAccess(boundNodes As BoundNodeSummary,
symbolsBuilder As ArrayBuilder(Of Symbol),
memberGroupBuilder As ArrayBuilder(Of Symbol),
ByRef resultKind As LookupResultKind)
If boundNodes.LowestBoundNodeOfSyntacticParent IsNot Nothing AndAlso
boundNodes.LowestBoundNodeOfSyntacticParent.Kind = BoundKind.LateInvocation Then
GetSemanticSymbolsForLateBoundInvocation(DirectCast(boundNodes.LowestBoundNodeOfSyntacticParent, BoundLateInvocation),
symbolsBuilder,
memberGroupBuilder,
resultKind)
Return
End If
resultKind = LookupResultKind.LateBound
End Sub
' Get the semantic symbols for a BoundMethodGroup. These are somewhat complex, as we want to get the result
' of overload resolution even though that result is associated with the parent node.
Private Sub GetSemanticSymbolsForMethodGroup(boundNodes As BoundNodeSummary,
symbolsBuilder As ArrayBuilder(Of Symbol),
memberGroupBuilder As ArrayBuilder(Of Symbol),
ByRef resultKind As LookupResultKind)
' Get the method group.
Dim methodGroup = DirectCast(boundNodes.LowestBoundNode, BoundMethodGroup)
resultKind = methodGroup.ResultKind
methodGroup.GetExpressionSymbols(memberGroupBuilder)
' Try to figure out what method this resolved to from the parent node.
Dim foundResolution As Boolean = False
'TODO: Will the below work correctly even in the case where M is a parameterless method that returns
'something with a default parameter (e.g. Item) on it?
If boundNodes.LowestBoundNodeOfSyntacticParent IsNot Nothing Then
Select Case boundNodes.LowestBoundNodeOfSyntacticParent.Kind
Case BoundKind.Call
' If we are looking for info on M in M(args), we want the symbol that overload resolution chose for M.
Dim parentCall = DirectCast(boundNodes.LowestBoundNodeOfSyntacticParent, BoundCall)
symbolsBuilder.Add(parentCall.Method)
If parentCall.ResultKind < resultKind Then
resultKind = parentCall.ResultKind
End If
foundResolution = True
Case BoundKind.DelegateCreationExpression
' If we are looking for info on M in AddressOf M, we want the symbol that overload resolution chose for M. This
' should be a BoundDelegateCreation.
Dim parentDelegateCreation = DirectCast(boundNodes.LowestBoundNodeOfSyntacticParent, BoundDelegateCreationExpression)
symbolsBuilder.Add(parentDelegateCreation.Method)
If parentDelegateCreation.ResultKind < resultKind Then
resultKind = parentDelegateCreation.ResultKind
End If
foundResolution = True
Case BoundKind.BadExpression
Dim badExpression = DirectCast(boundNodes.LowestBoundNodeOfSyntacticParent, BoundBadExpression)
' If the bad expressions has symbols(s) from the method group, it better
' indicates the problem.
symbolsBuilder.AddRange(badExpression.Symbols.Where(Function(sym) memberGroupBuilder.Contains(sym)))
If symbolsBuilder.Count > 0 Then
resultKind = badExpression.ResultKind
foundResolution = True
End If
Case BoundKind.NameOfOperator
symbolsBuilder.AddRange(memberGroupBuilder)
resultKind = LookupResultKind.MemberGroup
foundResolution = True
End Select
End If
If Not foundResolution Then
' If we didn't find a resolution, then use what we had as the member group.
symbolsBuilder.AddRange(memberGroupBuilder)
resultKind = LookupResultKind.OverloadResolutionFailure
End If
If methodGroup.ResultKind < resultKind Then
resultKind = methodGroup.ResultKind
End If
End Sub
' Get the semantic symbols for a BoundPropertyGroup. These are somewhat complex, as we want to get the result
' of overload resolution even though that result is associated with the parent node.
Private Sub GetSemanticSymbolsForPropertyGroup(boundNodes As BoundNodeSummary,
symbolsBuilder As ArrayBuilder(Of Symbol),
memberGroupBuilder As ArrayBuilder(Of Symbol),
ByRef resultKind As LookupResultKind)
' Get the property group.
Dim propertyGroup = DirectCast(boundNodes.LowestBoundNode, BoundPropertyGroup)
resultKind = propertyGroup.ResultKind
memberGroupBuilder.AddRange(propertyGroup.Properties)
' Try to figure out what property this resolved to from the parent node.
Dim foundResolution As Boolean = False
If boundNodes.LowestBoundNodeOfSyntacticParent IsNot Nothing Then
Select Case boundNodes.LowestBoundNodeOfSyntacticParent.Kind
Case BoundKind.PropertyAccess
' If we are looking for info on M in M(args), we want the symbol that overload resolution chose for M.
Dim parentPropAccess = TryCast(boundNodes.LowestBoundNodeOfSyntacticParent, BoundPropertyAccess)
If parentPropAccess IsNot Nothing Then
symbolsBuilder.Add(parentPropAccess.PropertySymbol)
If parentPropAccess.ResultKind < resultKind Then
resultKind = parentPropAccess.ResultKind
End If
foundResolution = True
End If
Case BoundKind.BadExpression
Dim badExpression = DirectCast(boundNodes.LowestBoundNodeOfSyntacticParent, BoundBadExpression)
' If the bad expressions has symbols(s) from the property group, it better
' indicates the problem.
symbolsBuilder.AddRange(badExpression.Symbols.Where(Function(sym) memberGroupBuilder.Contains(sym)))
If symbolsBuilder.Count > 0 Then
resultKind = badExpression.ResultKind
foundResolution = True
End If
Case BoundKind.NameOfOperator
symbolsBuilder.AddRange(memberGroupBuilder)
resultKind = LookupResultKind.MemberGroup
foundResolution = True
End Select
End If
If Not foundResolution Then
' If we didn't find a resolution, then use what we had as the member group.
symbolsBuilder.AddRange(memberGroupBuilder)
resultKind = LookupResultKind.OverloadResolutionFailure
End If
If propertyGroup.ResultKind < resultKind Then
resultKind = propertyGroup.ResultKind
End If
End Sub
Private Shared Function UnwrapAliases(symbols As ImmutableArray(Of Symbol)) As ImmutableArray(Of Symbol)
Dim anyAliases As Boolean = symbols.Any(Function(sym) sym.Kind = SymbolKind.Alias)
If Not anyAliases Then
Return symbols
End If
Dim builder As ArrayBuilder(Of Symbol) = ArrayBuilder(Of Symbol).GetInstance()
For Each sym In symbols
builder.Add(UnwrapAlias(sym))
Next
Return builder.ToImmutableAndFree()
End Function
''' <summary>
''' In cases where we are binding C in "[C(...)]", the bound nodes return the symbol for the type. However, we've
''' decided that we want this case to return the constructor of the type instead (based on the SemanticInfoOptions. This
''' affects only attributes. This method checks for this situation and adjusts the syntax and method group.
''' </summary>
Private Sub AdjustSymbolsForObjectCreation(boundNodes As BoundNodeSummary,
binderOpt As Binder,
ByRef bindingSymbols As ImmutableArray(Of Symbol),
memberGroupBuilder As ArrayBuilder(Of Symbol),
ByRef resultKind As LookupResultKind)
Dim constructor As MethodSymbol = Nothing
Dim lowestBoundNode = boundNodes.LowestBoundNode
Dim boundNodeOfSyntacticParent = boundNodes.LowestBoundNodeOfSyntacticParent
Debug.Assert(boundNodeOfSyntacticParent IsNot Nothing)
' Check if boundNode.Syntax is the type-name child of an ObjectCreationExpression or Attribute.
Dim parentSyntax As SyntaxNode = boundNodeOfSyntacticParent.Syntax
If parentSyntax IsNot Nothing AndAlso
lowestBoundNode IsNot Nothing AndAlso
parentSyntax Is lowestBoundNode.Syntax.Parent AndAlso
parentSyntax.Kind = SyntaxKind.Attribute AndAlso
(DirectCast(parentSyntax, AttributeSyntax).Name Is lowestBoundNode.Syntax) Then
Dim unwrappedSymbols = UnwrapAliases(bindingSymbols)
' We must have bound to a single named type
If unwrappedSymbols.Length = 1 AndAlso TypeOf unwrappedSymbols(0) Is TypeSymbol Then
Dim typeSymbol As TypeSymbol = DirectCast(unwrappedSymbols(0), TypeSymbol)
Dim namedTypeSymbol As NamedTypeSymbol = TryCast(typeSymbol, NamedTypeSymbol)
' Figure out which constructor was selected.
Select Case boundNodeOfSyntacticParent.Kind
Case BoundKind.Attribute
Dim boundAttribute As BoundAttribute = DirectCast(boundNodeOfSyntacticParent, BoundAttribute)
Debug.Assert(resultKind <> LookupResultKind.Good OrElse TypeSymbol.Equals(namedTypeSymbol, boundAttribute.Type, TypeCompareKind.ConsiderEverything))
constructor = boundAttribute.Constructor
resultKind = LookupResult.WorseResultKind(resultKind, boundAttribute.ResultKind)
Case BoundKind.BadExpression
' Note that namedTypeSymbol might be null here; e.g., a type parameter.
Dim boundBadExpression As BoundBadExpression = DirectCast(boundNodeOfSyntacticParent, BoundBadExpression)
resultKind = LookupResult.WorseResultKind(resultKind, boundBadExpression.ResultKind)
Case Else
Throw ExceptionUtilities.UnexpectedValue(boundNodeOfSyntacticParent.Kind)
End Select
AdjustSymbolsForObjectCreation(lowestBoundNode, namedTypeSymbol, constructor, binderOpt, bindingSymbols, memberGroupBuilder, resultKind)
End If
End If
End Sub
Private Sub AdjustSymbolsForObjectCreation(
lowestBoundNode As BoundNode,
namedTypeSymbol As NamedTypeSymbol,
constructor As MethodSymbol,
binderOpt As Binder,
ByRef bindingSymbols As ImmutableArray(Of Symbol),
memberGroupBuilder As ArrayBuilder(Of Symbol),
ByRef resultKind As LookupResultKind)
Debug.Assert(memberGroupBuilder IsNot Nothing)
Debug.Assert(lowestBoundNode IsNot Nothing)
Debug.Assert(binderOpt IsNot Nothing OrElse IsInTree(lowestBoundNode.Syntax))
If namedTypeSymbol IsNot Nothing Then
Debug.Assert(lowestBoundNode.Syntax IsNot Nothing)
' Filter namedTypeSymbol's instance constructors by accessibility.
' If all the instance constructors are inaccessible, we retain
' all the instance constructors.
Dim binder As Binder = If(binderOpt, GetEnclosingBinder(lowestBoundNode.Syntax.SpanStart))
Dim candidateConstructors As ImmutableArray(Of MethodSymbol)
If binder IsNot Nothing Then
Dim interfaceCoClass As NamedTypeSymbol = If(namedTypeSymbol.IsInterface,
TryCast(namedTypeSymbol.CoClassType, NamedTypeSymbol), Nothing)
candidateConstructors = binder.GetAccessibleConstructors(If(interfaceCoClass, namedTypeSymbol), useSiteInfo:=CompoundUseSiteInfo(Of AssemblySymbol).Discarded)
Dim instanceConstructors = namedTypeSymbol.InstanceConstructors
If Not candidateConstructors.Any() AndAlso instanceConstructors.Any() Then
Debug.Assert(resultKind <> LookupResultKind.Good)
candidateConstructors = instanceConstructors
End If
Else
candidateConstructors = ImmutableArray(Of MethodSymbol).Empty
End If
If constructor IsNot Nothing Then
Debug.Assert(candidateConstructors.Contains(constructor))
bindingSymbols = ImmutableArray.Create(Of Symbol)(constructor)
ElseIf candidateConstructors.Length <> 0 Then
bindingSymbols = StaticCast(Of Symbol).From(candidateConstructors)
resultKind = LookupResult.WorseResultKind(resultKind, LookupResultKind.OverloadResolutionFailure)
End If
memberGroupBuilder.AddRange(candidateConstructors)
End If
End Sub
' Gets SymbolInfo for a type or namespace or alias reference or implemented method.
Friend Function GetSymbolInfoForSymbol(
symbol As Symbol,
options As SymbolInfoOptions
) As SymbolInfo
' 1. Determine type, dig through alias if needed.
Dim type = TryCast(UnwrapAlias(symbol), TypeSymbol)
' 2. Determine symbols.
' We never return error symbols in the SemanticInfo.
' Error types carry along other symbols and result kinds in error cases.
' Getting the set of symbols is a bit involved. We use the union of the symbol with
' any symbols from the diagnostics, but error symbols are not included.\
Dim resultKind As LookupResultKind
Dim symbolsBuilder = ArrayBuilder(Of Symbol).GetInstance()
Dim originalErrorSymbol = If(type IsNot Nothing, TryCast(type.OriginalDefinition, ErrorTypeSymbol), Nothing)
If originalErrorSymbol IsNot Nothing Then
' Error case.
resultKind = originalErrorSymbol.ResultKind
If resultKind <> LookupResultKind.Empty Then
symbolsBuilder.AddRange(originalErrorSymbol.CandidateSymbols)
End If
ElseIf symbol.Kind = SymbolKind.Namespace AndAlso DirectCast(symbol, NamespaceSymbol).NamespaceKind = NamespaceKindNamespaceGroup Then
symbolsBuilder.AddRange(DirectCast(symbol, NamespaceSymbol).ConstituentNamespaces)
resultKind = LookupResultKind.Ambiguous
Else
symbolsBuilder.Add(symbol)
resultKind = LookupResultKind.Good
End If
Dim symbols As ImmutableArray(Of Symbol) = RemoveErrorTypesAndDuplicates(symbolsBuilder, options)
symbolsBuilder.Free()
Return SymbolInfoFactory.Create(symbols, resultKind)
End Function
' Gets TypeInfo for a type or namespace or alias reference or implemented method.
Friend Function GetTypeInfoForSymbol(
symbol As Symbol
) As VisualBasicTypeInfo
' 1. Determine type, dig through alias if needed.
Dim type = TryCast(UnwrapAlias(symbol), TypeSymbol)
Return New VisualBasicTypeInfo(type, type, New Conversion(Conversions.Identity))
End Function
' This is used by other binding API's to invoke the right binder API
Friend Overridable Function Bind(binder As Binder, node As SyntaxNode, diagnostics As BindingDiagnosticBag) As BoundNode
Dim expr = TryCast(node, ExpressionSyntax)
If expr IsNot Nothing Then
Return binder.BindNamespaceOrTypeOrExpressionSyntaxForSemanticModel(expr, diagnostics)
Else
Dim statement = TryCast(node, StatementSyntax)
If statement IsNot Nothing Then
Return binder.BindStatement(statement, diagnostics)
End If
End If
Return Nothing
End Function
''' <summary>
''' Gets the available named symbols in the context of the specified location And optional container. Only
''' symbols that are accessible And visible from the given location are returned.
''' </summary>
''' <param name="position">The character position for determining the enclosing declaration scope And
''' accessibility.</param>
''' <param name="container">The container to search for symbols within. If null then the enclosing declaration
''' scope around position Is used.</param>
''' <param name="name">The name of the symbol to find. If null Is specified then symbols
''' with any names are returned.</param>
''' <param name="includeReducedExtensionMethods">Consider (reduced) extension methods.</param>
''' <returns>A list of symbols that were found. If no symbols were found, an empty list Is returned.</returns>
''' <remarks>
''' The "position" Is used to determine what variables are visible And accessible. Even if "container" Is
''' specified, the "position" location Is significant for determining which members of "containing" are
''' accessible.
'''
''' Labels are Not considered (see <see cref="LookupLabels"/>).
'''
''' Non-reduced extension methods are considered regardless of the value of <paramref name="includeReducedExtensionMethods"/>.
''' </remarks>
Public Shadows Function LookupSymbols(
position As Integer,
Optional container As INamespaceOrTypeSymbol = Nothing,
Optional name As String = Nothing,
Optional includeReducedExtensionMethods As Boolean = False
) As ImmutableArray(Of ISymbol)
Dim options = If(includeReducedExtensionMethods, LookupOptions.Default, LookupOptions.IgnoreExtensionMethods)
Dim result = LookupSymbolsInternal(position, ToLanguageSpecific(container), name, options, useBaseReferenceAccessibility:=False)
#If DEBUG Then
For Each item In result
Debug.Assert(item.Kind <> SymbolKind.Namespace OrElse DirectCast(item, NamespaceSymbol).NamespaceKind <> NamespaceKindNamespaceGroup)
Next
#End If
Return StaticCast(Of ISymbol).From(result)
End Function
''' <summary>
''' Gets the available base type members in the context of the specified location. Akin to
''' calling <see cref="LookupSymbols"/> with the container set to the immediate base type of
''' the type in which <paramref name="position"/> occurs. However, the accessibility rules
''' are different: protected members of the base type will be visible.
'''
''' Consider the following example:
'''
''' Public Class Base
''' Protected Sub M()
''' End Sub
''' End Class
'''
''' Public Class Derived : Inherits Base
''' Sub Test(b as Base)
''' b.M() ' Error - cannot access protected member.
''' MyBase.M()
''' End Sub
''' End Class
'''
''' Protected members of an instance of another type are only accessible if the instance is known
''' to be "this" instance (as indicated by the "MyBase" keyword).
''' </summary>
''' <param name="position">The character position for determining the enclosing declaration scope and
''' accessibility.</param>
''' <param name="name">The name of the symbol to find. If null is specified then symbols
''' with any names are returned.</param>
''' <returns>A list of symbols that were found. If no symbols were found, an empty list is returned.</returns>
''' <remarks>
''' The "position" is used to determine what variables are visible and accessible.
'''
''' Non-reduced extension methods are considered, but reduced extension methods are not.
''' </remarks>
Public Shadows Function LookupBaseMembers(
position As Integer,
Optional name As String = Nothing
) As ImmutableArray(Of ISymbol)
Dim result = LookupSymbolsInternal(position, Nothing, name, LookupOptions.Default, useBaseReferenceAccessibility:=True)
#If DEBUG Then
For Each item In result
Debug.Assert(item.Kind <> SymbolKind.Namespace)
Next
#End If
Return StaticCast(Of ISymbol).From(result)
End Function
''' <summary>
''' Gets the available named static member symbols in the context of the specified location And optional container.
''' Only members that are accessible And visible from the given location are returned.
'''
''' Non-reduced extension methods are considered, since they are static methods.
''' </summary>
''' <param name="position">The character position for determining the enclosing declaration scope And
''' accessibility.</param>
''' <param name="container">The container to search for symbols within. If null then the enclosing declaration
''' scope around position Is used.</param>
''' <param name="name">The name of the symbol to find. If null Is specified then symbols
''' with any names are returned.</param>
''' <returns>A list of symbols that were found. If no symbols were found, an empty list Is returned.</returns>
''' <remarks>
''' The "position" Is used to determine what variables are visible And accessible. Even if "container" Is
''' specified, the "position" location Is significant for determining which members of "containing" are
''' accessible.
''' </remarks>
Public Shadows Function LookupStaticMembers(
position As Integer,
Optional container As INamespaceOrTypeSymbol = Nothing,
Optional name As String = Nothing
) As ImmutableArray(Of ISymbol)
Dim result = LookupSymbolsInternal(position, ToLanguageSpecific(container), name, LookupOptions.MustNotBeInstance Or LookupOptions.IgnoreExtensionMethods, useBaseReferenceAccessibility:=False)
#If DEBUG Then
For Each item In result
Debug.Assert(item.Kind <> SymbolKind.Namespace OrElse DirectCast(item, NamespaceSymbol).NamespaceKind <> NamespaceKindNamespaceGroup)
Next
#End If
Return StaticCast(Of ISymbol).From(result)
End Function
''' <summary>
''' Gets the available named namespace And type symbols in the context of the specified location And optional container.
''' Only members that are accessible And visible from the given location are returned.
''' </summary>
''' <param name="position">The character position for determining the enclosing declaration scope And
''' accessibility.</param>
''' <param name="container">The container to search for symbols within. If null then the enclosing declaration
''' scope around position Is used.</param>
''' <param name="name">The name of the symbol to find. If null Is specified then symbols
''' with any names are returned.</param>
''' <returns>A list of symbols that were found. If no symbols were found, an empty list Is returned.</returns>
''' <remarks>
''' The "position" Is used to determine what variables are visible And accessible. Even if "container" Is
''' specified, the "position" location Is significant for determining which members of "containing" are
''' accessible.
'''
''' Does Not return INamespaceOrTypeSymbol, because there could be aliases.
''' </remarks>
Public Shadows Function LookupNamespacesAndTypes(
position As Integer,
Optional container As INamespaceOrTypeSymbol = Nothing,
Optional name As String = Nothing
) As ImmutableArray(Of ISymbol)
Dim result = LookupSymbolsInternal(position, ToLanguageSpecific(container), name, LookupOptions.NamespacesOrTypesOnly, useBaseReferenceAccessibility:=False)
#If DEBUG Then
For Each item In result
Debug.Assert(item.Kind <> SymbolKind.Namespace OrElse DirectCast(item, NamespaceSymbol).NamespaceKind <> NamespaceKindNamespaceGroup)
Next
#End If
Return StaticCast(Of ISymbol).From(result)
End Function
''' <summary>
''' Gets the available named label symbols in the context of the specified location And optional container.
''' Only members that are accessible And visible from the given location are returned.
''' </summary>
''' <param name="position">The character position for determining the enclosing declaration scope And
''' accessibility.</param>
''' <param name="name">The name of the symbol to find. If null Is specified then symbols
''' with any names are returned.</param>
''' <returns>A list of symbols that were found. If no symbols were found, an empty list Is returned.</returns>
''' <remarks>
''' The "position" Is used to determine what variables are visible And accessible. Even if "container" Is
''' specified, the "position" location Is significant for determining which members of "containing" are
''' accessible.
''' </remarks>
Public Shadows Function LookupLabels(
position As Integer,
Optional name As String = Nothing
) As ImmutableArray(Of ISymbol)
Dim result = LookupSymbolsInternal(position, container:=Nothing, name:=name, options:=LookupOptions.LabelsOnly, useBaseReferenceAccessibility:=False)
#If DEBUG Then
For Each item In result
Debug.Assert(item.Kind <> SymbolKind.Namespace)
Next
#End If
Return StaticCast(Of ISymbol).From(result)
End Function
''' <summary>
''' Gets the available named symbols in the context of the specified location and optional
''' container. Only symbols that are accessible and visible from the given location are
''' returned.
''' </summary>
''' <param name="position">The character position for determining the enclosing declaration
''' scope and accessibility.</param>
''' <param name="container">The container to search for symbols within. If null then the
''' enclosing declaration scope around position is used.</param>
''' <param name="name">The name of the symbol to find. If null is specified then symbols
''' with any names are returned.</param>
''' <param name="options">Additional options that affect the lookup process.</param>
''' <param name="useBaseReferenceAccessibility">Ignore 'throughType' in accessibility checking.
''' Used in checking accessibility of symbols accessed via 'MyBase' or 'base'.</param>
''' <returns>A list of symbols that were found. If no symbols were found, an empty list is
''' returned.</returns>
''' <remarks>
''' The "position" is used to determine what variables are visible and accessible. Even if
''' "container" is specified, the "position" location is significant for determining which
''' members of "containing" are accessible.
'''
''' Locations are character locations, just as used as the Syntax APIs such as FindToken, or
''' returned from the Span property on tokens and syntax node.
'''
''' The text of the program is divided into scopes, which nest but don't otherwise
''' intersect. When doing an operation such as LookupSymbols, the code first determines the
''' smallest scope containing the position, and from there all containing scopes.
'''
''' Scopes that span an entire block statement start at the beginning of the first token of
''' the block header, and end immediately before the statement terminator token following
''' the end statement of the block. If the end statement of the block is missing, it ends
''' immediately before the next token. Examples of these include members and type parameters
''' of a type, type parameters of a method, and variables declared in a For statement.
'''
''' Scopes that span the interior of a block statement start at the statement terminator of
''' the block header statement, and end immediately before the first token of the end
''' statement of the block. If the end statement of the block is missing, it ends
''' immediately before the next statement. Examples of these include local variables, method
''' parameters, and members of a namespace.
'''
''' Scopes of variables declared in a single-line If statement start at the beginning of the
''' "Then" token, and end immediately before the Else token or statement terminator.
'''
''' Scopes of variables declared in the Else part of a single-line If start at the beginning
''' of the "Else" token, and end immediately before the statement terminator.
'''
''' Some specialized binding rules are in place for a single statement, like Imports or
''' Inherits. These specialized binding rules begin at the start of the first token of the
''' statement, and end immediately before the statement terminator of that statement.
'''
''' In all of the above, the "start" means the start of a token without considering leading
''' trivia. In other words, Span.Start, not FullSpan.Start. With the exception of
''' documentation comments, all scopes begin at the start of a token, and end immediately
''' before the start of a token.
'''
''' The scope of the default namespace, and all symbols introduced via Imports statements,
''' is the entire file.
'''
''' Positions within a documentation comment that is correctly attached to a symbol take on
''' the binding scope of that symbol.
''' </remarks>
''' <exception cref="ArgumentException">Throws an argument exception if the passed lookup options are invalid.</exception>
Private Function LookupSymbolsInternal(position As Integer,
container As NamespaceOrTypeSymbol,
name As String,
options As LookupOptions,
useBaseReferenceAccessibility As Boolean) As ImmutableArray(Of Symbol)
Debug.Assert((options And LookupOptions.UseBaseReferenceAccessibility) = 0, "Use the useBaseReferenceAccessibility parameter.")
If useBaseReferenceAccessibility Then
options = options Or LookupOptions.UseBaseReferenceAccessibility
End If
Debug.Assert(options.IsValid())
CheckPosition(position)
Dim binder = Me.GetEnclosingBinder(position)
If binder Is Nothing Then
Return ImmutableArray(Of Symbol).Empty
End If
If useBaseReferenceAccessibility Then
Debug.Assert(container Is Nothing)
Dim containingType = binder.ContainingType
Dim baseType = If(containingType Is Nothing, Nothing, containingType.BaseTypeNoUseSiteDiagnostics)
If baseType Is Nothing Then
Throw New ArgumentException(NameOf(position),
"Not a valid position for a call to LookupBaseMembers (must be in a type with a base type)")
End If
container = baseType
End If
If name Is Nothing Then
' If they didn't provide a name, then look up all names and associated arities
' and find all the corresponding symbols.
Dim info = LookupSymbolsInfo.GetInstance()
Me.AddLookupSymbolsInfo(position, info, container, options)
Dim results = ArrayBuilder(Of Symbol).GetInstance(info.Count)
For Each foundName In info.Names
AppendSymbolsWithName(results, foundName, binder, container, options, info)
Next
info.Free()
Dim sealedResults = results.ToImmutableAndFree()
Dim builder As ArrayBuilder(Of Symbol) = Nothing
Dim pos = 0
For Each result In sealedResults
' Special case: we want to see constructors, even though they can't be referenced by name.
If result.CanBeReferencedByName OrElse
(result.Kind = SymbolKind.Method AndAlso DirectCast(result, MethodSymbol).MethodKind = MethodKind.Constructor) Then
If builder IsNot Nothing Then
builder.Add(result)
End If
ElseIf builder Is Nothing Then
builder = ArrayBuilder(Of Symbol).GetInstance()
builder.AddRange(sealedResults, pos)
End If
pos = pos + 1
Next
Return If(builder Is Nothing, sealedResults, builder.ToImmutableAndFree())
Else
' They provided a name. Find all the arities for that name, and then look all of those up.
Dim info = LookupSymbolsInfo.GetInstance()
info.FilterName = name
Me.AddLookupSymbolsInfo(position, info, container, options)
Dim results = ArrayBuilder(Of Symbol).GetInstance(info.Count)
AppendSymbolsWithName(results, name, binder, container, options, info)
info.Free()
' If the name was specified, we don't have to do additional filtering - this is what they asked for.
Return results.ToImmutableAndFree()
End If
End Function
Private Sub AppendSymbolsWithName(results As ArrayBuilder(Of Symbol), name As String, binder As Binder, container As NamespaceOrTypeSymbol, options As LookupOptions, info As LookupSymbolsInfo)
Dim arities As LookupSymbolsInfo.IArityEnumerable = Nothing
Dim uniqueSymbol As Symbol = Nothing
If info.TryGetAritiesAndUniqueSymbol(name, arities, uniqueSymbol) Then
If uniqueSymbol IsNot Nothing Then
' This name mapped to something unique. We don't need to proceed
' with a costly lookup. Just add it straight to the results.
results.Add(uniqueSymbol)
Else
' The name maps to multiple symbols. Actually do a real lookup so
' that we will properly figure out hiding and whatnot.
If arities IsNot Nothing Then
Me.LookupSymbols(binder, container, name, arities, options, results)
Else
' If there's no unique symbol, then there won't have been a non-zero arity
Me.LookupSymbols(binder, container, name, 0, options, results)
End If
End If
End If
End Sub
' Lookup symbol using a given binding. Options has already had the ByLocation and AllNames
' flags taken off appropriately.
Private Shadows Sub LookupSymbols(binder As Binder,
container As NamespaceOrTypeSymbol,
name As String,
arities As LookupSymbolsInfo.IArityEnumerable,
options As LookupOptions,
results As ArrayBuilder(Of Symbol))
Debug.Assert(results IsNot Nothing)
Dim uniqueSymbols = PooledHashSet(Of Symbol).GetInstance()
Dim tempResults = ArrayBuilder(Of Symbol).GetInstance(arities.Count)
For Each knownArity In arities
' TODO: What happens here if options has LookupOptions.AllMethodsOfAnyArity bit set?
' It looks like we will be dealing with a lot of duplicate methods. Should we optimize this
' by clearing the bit?
Me.LookupSymbols(binder, container, name, knownArity, options, tempResults)
uniqueSymbols.UnionWith(tempResults)
tempResults.Clear()
Next
tempResults.Free()
results.AddRange(uniqueSymbols)
uniqueSymbols.Free()
End Sub
Private Shadows Sub LookupSymbols(binder As Binder,
container As NamespaceOrTypeSymbol,
name As String,
arity As Integer,
options As LookupOptions,
results As ArrayBuilder(Of Symbol))
If name = WellKnownMemberNames.InstanceConstructorName Then ' intentionally case sensitive; constructors always exactly ".ctor".
' Constructors have very different lookup rules.
LookupInstanceConstructors(binder, container, options, results)
Return
End If
Dim result = LookupResult.GetInstance()
Dim realArity = arity
options = CType(options Or LookupOptions.EagerlyLookupExtensionMethods, LookupOptions)
If options.IsAttributeTypeLookup Then
binder.LookupAttributeType(result, container, name, options, useSiteInfo:=CompoundUseSiteInfo(Of AssemblySymbol).Discarded)
ElseIf container Is Nothing Then
binder.Lookup(result, name, realArity, options, useSiteInfo:=CompoundUseSiteInfo(Of AssemblySymbol).Discarded)
Else
binder.LookupMember(result, container, name, realArity, options, useSiteInfo:=CompoundUseSiteInfo(Of AssemblySymbol).Discarded)
End If
If result.IsGoodOrAmbiguous Then
If result.HasDiagnostic Then
' In the ambiguous symbol case, we have a good symbol with a diagnostics that
' mentions the other symbols. Union everything together with a set to prevent dups.
Dim symbolSet = PooledHashSet(Of Symbol).GetInstance()
Dim symBuilder = ArrayBuilder(Of Symbol).GetInstance()
AddSymbolsFromDiagnosticInfo(symBuilder, result.Diagnostic)
symbolSet.UnionWith(symBuilder)
symbolSet.UnionWith(result.Symbols)
symBuilder.Free()
results.AddRange(symbolSet)
symbolSet.Free()
ElseIf result.HasSingleSymbol AndAlso result.SingleSymbol.Kind = SymbolKind.Namespace AndAlso
DirectCast(result.SingleSymbol, NamespaceSymbol).NamespaceKind = NamespaceKindNamespaceGroup Then
results.AddRange(DirectCast(result.SingleSymbol, NamespaceSymbol).ConstituentNamespaces)
Else
results.AddRange(result.Symbols)
End If
End If
result.Free()
End Sub
' Do a lookup of instance constructors, taking LookupOptions into account.
Private Sub LookupInstanceConstructors(
binder As Binder,
container As NamespaceOrTypeSymbol,
options As LookupOptions,
results As ArrayBuilder(Of Symbol)
)
Debug.Assert(results IsNot Nothing)
Dim constructors As ImmutableArray(Of MethodSymbol) = ImmutableArray(Of MethodSymbol).Empty
Dim type As NamedTypeSymbol = TryCast(container, NamedTypeSymbol)
If type IsNot Nothing AndAlso
(options And (LookupOptions.LabelsOnly Or LookupOptions.NamespacesOrTypesOnly Or LookupOptions.MustNotBeInstance)) = 0 Then
If (options And LookupOptions.IgnoreAccessibility) <> 0 Then
constructors = type.InstanceConstructors
Else
constructors = binder.GetAccessibleConstructors(type, useSiteInfo:=CompoundUseSiteInfo(Of AssemblySymbol).Discarded)
End If
End If
results.AddRange(constructors)
End Sub
''' <summary>
''' Gets the names of the available named symbols in the context of the specified location
''' and optional container. Only symbols that are accessible and visible from the given
''' location are returned.
''' </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.
''' </param>
''' <param name="container">The container to search for symbols within. If null then the
''' enclosing declaration scope around position is used.</param>
''' <param name="options">Additional options that affect the lookup process.</param>
''' <remarks>
''' The "position" is used to determine what variables are visible and accessible. Even if
''' "container" is specified, the "position" location is significant for determining which
''' members of "containing" are accessible.
''' </remarks>
Private Sub AddLookupSymbolsInfo(position As Integer,
info As LookupSymbolsInfo,
Optional container As NamespaceOrTypeSymbol = Nothing,
Optional options As LookupOptions = LookupOptions.Default)
CheckPosition(position)
Dim binder = Me.GetEnclosingBinder(position)
If binder IsNot Nothing Then
If container Is Nothing Then
binder.AddLookupSymbolsInfo(info, options)
Else
binder.AddMemberLookupSymbolsInfo(info, container, options)
End If
End If
End Sub
''' <summary>
''' Determines if the symbol is accessible from the specified location.
''' </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.
''' </param>
''' <param name="symbol">The symbol that we are checking to see if it accessible.</param>
''' <returns>
''' True if "symbol is accessible, false otherwise.</returns>
''' <remarks>
''' This method only checks accessibility from the point of view of the accessibility
''' modifiers on symbol and its containing types. Even if true is returned, the given symbol
''' may not be able to be referenced for other reasons, such as name hiding.
''' </remarks>
Public Shadows Function IsAccessible(position As Integer, symbol As ISymbol) As Boolean
CheckPosition(position)
If symbol Is Nothing Then
Throw New ArgumentNullException(NameOf(symbol))
End If
Dim vbsymbol = symbol.EnsureVbSymbolOrNothing(Of Symbol)(NameOf(symbol))
Dim binder = Me.GetEnclosingBinder(position)
If binder IsNot Nothing Then
Return binder.IsAccessible(vbsymbol, CompoundUseSiteInfo(Of AssemblySymbol).Discarded)
End If
Return False
End Function
''' <summary>
''' Analyze control-flow within a part of a method body.
''' </summary>
''' <param name="firstStatement">The first statement to be included in the analysis.</param>
''' <param name="lastStatement">The last statement to be included in the analysis.</param>
''' <returns>An object that can be used to obtain the result of the control flow analysis.</returns>
''' <exception cref="ArgumentException">The two statements are not contained within the same statement list.</exception>
Public Overridable Shadows Function AnalyzeControlFlow(firstStatement As StatementSyntax, lastStatement As StatementSyntax) As ControlFlowAnalysis
Throw New NotSupportedException()
End Function
''' <summary>
''' Analyze control-flow within a part of a method body.
''' </summary>
''' <param name="statement">The statement to be included in the analysis.</param>
''' <returns>An object that can be used to obtain the result of the control flow analysis.</returns>
Public Overridable Shadows Function AnalyzeControlFlow(statement As StatementSyntax) As ControlFlowAnalysis
Return AnalyzeControlFlow(statement, statement)
End Function
''' <summary>
''' Analyze data-flow within an expression.
''' </summary>
''' <param name="expression">The expression within the associated SyntaxTree to analyze.</param>
''' <returns>An object that can be used to obtain the result of the data flow analysis.</returns>
Public Overridable Shadows Function AnalyzeDataFlow(expression As ExpressionSyntax) As DataFlowAnalysis
Throw New NotSupportedException()
End Function
''' <summary>
''' Analyze data-flow within a set of contiguous statements.
''' </summary>
''' <param name="firstStatement">The first statement to be included in the analysis.</param>
''' <param name="lastStatement">The last statement to be included in the analysis.</param>
''' <returns>An object that can be used to obtain the result of the data flow analysis.</returns>
''' <exception cref="ArgumentException">The two statements are not contained within the same statement list.</exception>
Public Overridable Shadows Function AnalyzeDataFlow(firstStatement As StatementSyntax, lastStatement As StatementSyntax) As DataFlowAnalysis
Throw New NotSupportedException()
End Function
''' <summary>
''' Analyze data-flow within a statement.
''' </summary>
''' <param name="statement">The statement to be included in the analysis.</param>
''' <returns>An object that can be used to obtain the result of the data flow analysis.</returns>
Public Overridable Shadows Function AnalyzeDataFlow(statement As StatementSyntax) As DataFlowAnalysis
Return AnalyzeDataFlow(statement, statement)
End Function
''' <summary>
''' Get a SemanticModel object that is associated with a method body that did not appear in this source code.
''' Given <paramref name="position"/> must lie within an existing method body of the Root syntax node for this SemanticModel.
''' Locals and labels declared within this existing method body are not considered to be in scope of the speculated method body.
''' </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 and must be
''' within the FullSpan of a Method body within the Root syntax node.</param>
''' <param name="method">A syntax node that represents a parsed method declaration. This method should not be
''' present in the syntax tree associated with this object, but must have identical signature to the method containing
''' the given <paramref name="position"/> in this SemanticModel.</param>
''' <param name="speculativeModel">A SemanticModel object that can be used to inquire about the semantic
''' information associated with syntax nodes within <paramref name="method"/>.</param>
''' <returns>Flag indicating whether a speculative semantic model was created.</returns>
''' <exception cref="ArgumentException">Throws this exception if the <paramref name="method"/> node is contained any SyntaxTree in the current Compilation.</exception>
''' <exception cref="ArgumentNullException">Throws this exception if <paramref name="method"/> is null.</exception>
''' <exception cref="InvalidOperationException">Throws this exception if this model is a speculative semantic model, i.e. <see cref="IsSpeculativeSemanticModel"/> is True.
''' Chaining of speculative semantic model is not supported.</exception>
Public Function TryGetSpeculativeSemanticModelForMethodBody(position As Integer, method As MethodBlockBaseSyntax, <Out> ByRef speculativeModel As SemanticModel) As Boolean
CheckPosition(position)
CheckModelAndSyntaxNodeToSpeculate(method)
Dim speculativePublicModel As PublicSemanticModel = Nothing
Dim result = TryGetSpeculativeSemanticModelForMethodBodyCore(DirectCast(Me, SyntaxTreeSemanticModel), position, method, speculativePublicModel)
speculativeModel = speculativePublicModel
Return result
End Function
Friend MustOverride Function TryGetSpeculativeSemanticModelForMethodBodyCore(parentModel As SyntaxTreeSemanticModel, position As Integer, method As MethodBlockBaseSyntax, <Out> ByRef speculativeModel As PublicSemanticModel) As Boolean
''' <summary>
''' Get a SemanticModel object that is associated with a range argument syntax that did not appear in
''' this source code. This can be used to get detailed semantic information about sub-parts
''' of this node that did not appear in 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.
''' </param>
''' <param name="rangeArgument">A syntax node that represents a parsed RangeArgumentSyntax node. This node should not be
''' present in the syntax tree associated with this object.</param>
''' <param name="speculativeModel">A SemanticModel object that can be used to inquire about the semantic
''' information associated with syntax nodes within <paramref name="rangeArgument"/>.</param>
''' <returns>Flag indicating whether a speculative semantic model was created.</returns>
''' <exception cref="ArgumentException">Throws this exception if the <paramref name="rangeArgument"/> node is contained any SyntaxTree in the current Compilation.</exception>
''' <exception cref="ArgumentNullException">Throws this exception if <paramref name="rangeArgument"/> is null.</exception>
''' <exception cref="InvalidOperationException">Throws this exception if this model is a speculative semantic model, i.e. <see cref="IsSpeculativeSemanticModel"/> is True.
''' Chaining of speculative semantic model is not supported.</exception>
Public Function TryGetSpeculativeSemanticModel(position As Integer, rangeArgument As RangeArgumentSyntax, <Out> ByRef speculativeModel As SemanticModel) As Boolean
CheckPosition(position)
CheckModelAndSyntaxNodeToSpeculate(rangeArgument)
Dim speculativePublicModel As PublicSemanticModel = Nothing
Dim result = TryGetSpeculativeSemanticModelCore(DirectCast(Me, SyntaxTreeSemanticModel), position, rangeArgument, speculativePublicModel)
speculativeModel = speculativePublicModel
Return result
End Function
Friend MustOverride Function TryGetSpeculativeSemanticModelCore(parentModel As SyntaxTreeSemanticModel, position As Integer, rangeArgument As RangeArgumentSyntax, <Out> ByRef speculativeModel As PublicSemanticModel) As Boolean
''' <summary>
''' Get a SemanticModel object that is associated with an executable statement that did not appear in
''' this source code. This can be used to get detailed semantic information about sub-parts
''' of a statement that did not appear in 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.</param>
''' <param name="statement">A syntax node that represents a parsed statement. This statement should not be
''' present in the syntax tree associated with this object.</param>
''' <param name="speculativeModel">A SemanticModel object that can be used to inquire about the semantic
''' information associated with syntax nodes within <paramref name="statement"/>.</param>
''' <returns>Flag indicating whether a speculative semantic model was created.</returns>
''' <exception cref="ArgumentException">Throws this exception if the <paramref name="statement"/> node is contained any SyntaxTree in the current Compilation.</exception>
''' <exception cref="ArgumentNullException">Throws this exception if <paramref name="statement"/> is null.</exception>
''' <exception cref="InvalidOperationException">Throws this exception if this model is a speculative semantic model, i.e. <see cref="IsSpeculativeSemanticModel"/> is True.
''' Chaining of speculative semantic model is not supported.</exception>
Public Function TryGetSpeculativeSemanticModel(position As Integer, statement As ExecutableStatementSyntax, <Out> ByRef speculativeModel As SemanticModel) As Boolean
CheckPosition(position)
CheckModelAndSyntaxNodeToSpeculate(statement)
Dim speculativePublicModel As PublicSemanticModel = Nothing
Dim result = TryGetSpeculativeSemanticModelCore(DirectCast(Me, SyntaxTreeSemanticModel), position, statement, speculativePublicModel)
speculativeModel = speculativePublicModel
Return result
End Function
Friend MustOverride Function TryGetSpeculativeSemanticModelCore(parentModel As SyntaxTreeSemanticModel, position As Integer, statement As ExecutableStatementSyntax, <Out> ByRef speculativeModel As PublicSemanticModel) As Boolean
''' <summary>
''' Get a SemanticModel object that is associated with an initializer that did not appear in
''' this source code. This can be used to get detailed semantic information about sub-parts
''' of a field initializer, property initializer or default parameter value that did not appear in 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.
''' </param>
''' <param name="initializer">A syntax node that represents a parsed initializer. This initializer should not be
''' present in the syntax tree associated with this object.</param>
''' <param name="speculativeModel">A SemanticModel object that can be used to inquire about the semantic
''' information associated with syntax nodes within <paramref name="initializer"/>.</param>
''' <returns>Flag indicating whether a speculative semantic model was created.</returns>
''' <exception cref="ArgumentException">Throws this exception if the <paramref name="initializer"/> node is contained any SyntaxTree in the current Compilation.</exception>
''' <exception cref="ArgumentNullException">Throws this exception if <paramref name="initializer"/> is null.</exception>
''' <exception cref="InvalidOperationException">Throws this exception if this model is a speculative semantic model, i.e. <see cref="IsSpeculativeSemanticModel"/> is True.
''' Chaining of speculative semantic model is not supported.</exception>
Public Function TryGetSpeculativeSemanticModel(position As Integer, initializer As EqualsValueSyntax, <Out> ByRef speculativeModel As SemanticModel) As Boolean
CheckPosition(position)
CheckModelAndSyntaxNodeToSpeculate(initializer)
Dim speculativePublicModel As PublicSemanticModel = Nothing
Dim result = TryGetSpeculativeSemanticModelCore(DirectCast(Me, SyntaxTreeSemanticModel), position, initializer, speculativePublicModel)
speculativeModel = speculativePublicModel
Return result
End Function
Friend MustOverride Function TryGetSpeculativeSemanticModelCore(parentModel As SyntaxTreeSemanticModel, position As Integer, initializer As EqualsValueSyntax, <Out> ByRef speculativeModel As PublicSemanticModel) As Boolean
''' <summary>
''' Get a SemanticModel object that is associated with an attribute that did not appear in
''' this source code. This can be used to get detailed semantic information about sub-parts
''' of an attribute that did not appear in 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.</param>
''' <param name="attribute">A syntax node that represents a parsed attribute. This attribute should not be
''' present in the syntax tree associated with this object.</param>
''' <param name="speculativeModel">A SemanticModel object that can be used to inquire about the semantic
''' information associated with syntax nodes within <paramref name="attribute"/>.</param>
''' <returns>Flag indicating whether a speculative semantic model was created.</returns>
''' <exception cref="ArgumentException">Throws this exception if the <paramref name="attribute"/> node is contained any SyntaxTree in the current Compilation.</exception>
''' <exception cref="ArgumentNullException">Throws this exception if <paramref name="attribute"/> is null.</exception>
''' <exception cref="InvalidOperationException">Throws this exception if this model is a speculative semantic model, i.e. <see cref="IsSpeculativeSemanticModel"/> is True.
''' Chaining of speculative semantic model is not supported.</exception>
Public Function TryGetSpeculativeSemanticModel(position As Integer, attribute As AttributeSyntax, <Out> ByRef speculativeModel As SemanticModel) As Boolean
CheckPosition(position)
CheckModelAndSyntaxNodeToSpeculate(attribute)
Dim binder As Binder = Me.GetSpeculativeAttributeBinder(position, attribute)
If binder Is Nothing Then
speculativeModel = Nothing
Return False
End If
speculativeModel = AttributeSemanticModel.CreateSpeculative(DirectCast(Me, SyntaxTreeSemanticModel), attribute, binder, position)
Return True
End Function
''' <summary>
''' Get a SemanticModel object that is associated with a type syntax that did not appear in
''' this source code. This can be used to get detailed semantic information about sub-parts
''' of a type syntax that did not appear in 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.
''' </param>
''' <param name="type">A syntax node that represents a parsed type syntax. This expression should not be
''' present in the syntax tree associated with this object.</param>
''' <param name="bindingOption">Indicates whether to bind the expression as a full expression,
''' or as a type or namespace.</param>
''' <param name="speculativeModel">A SemanticModel object that can be used to inquire about the semantic
''' information associated with syntax nodes within <paramref name="type"/>.</param>
''' <returns>Flag indicating whether a speculative semantic model was created.</returns>
''' <exception cref="ArgumentException">Throws this exception if the <paramref name="type"/> node is contained any SyntaxTree in the current Compilation.</exception>
''' <exception cref="InvalidOperationException">Throws this exception if this model is a speculative semantic model, i.e. <see cref="IsSpeculativeSemanticModel"/> is True.
''' Chaining of speculative semantic model is not supported.</exception>
Public Function TryGetSpeculativeSemanticModel(position As Integer, type As TypeSyntax, <Out> ByRef speculativeModel As SemanticModel, Optional bindingOption As SpeculativeBindingOption = SpeculativeBindingOption.BindAsExpression) As Boolean
CheckPosition(position)
CheckModelAndSyntaxNodeToSpeculate(type)
Dim speculativePublicModel As PublicSemanticModel = Nothing
Dim result = TryGetSpeculativeSemanticModelCore(DirectCast(Me, SyntaxTreeSemanticModel), position, type, bindingOption, speculativePublicModel)
speculativeModel = speculativePublicModel
Return result
End Function
Friend MustOverride Function TryGetSpeculativeSemanticModelCore(parentModel As SyntaxTreeSemanticModel, position As Integer, type As TypeSyntax, bindingOption As SpeculativeBindingOption, <Out> ByRef speculativeModel As PublicSemanticModel) As Boolean
''' <summary>
''' If this is a speculative semantic model, then returns its parent semantic model.
''' Otherwise, returns null.
''' </summary>
Public MustOverride Shadows ReadOnly Property ParentModel As SemanticModel
''' <summary>
''' Determines what type of conversion, if any, would be used if a given expression was
''' converted to a given type.
''' </summary>
''' <param name="expression">An expression which must occur within the syntax tree
''' associated with this object.</param>
''' <param name="destination">The type to attempt conversion to.</param>
''' <returns>Returns a Conversion object that summarizes whether the conversion was
''' possible, and if so, what kind of conversion it was. If no conversion was possible, a
''' Conversion object with a false "Exists " property is returned.</returns>
''' <remarks>To determine the conversion between two types (instead of an expression and a
''' type), use Compilation.ClassifyConversion.</remarks>
Public MustOverride Shadows Function ClassifyConversion(expression As ExpressionSyntax, destination As ITypeSymbol) As Conversion
''' <summary>
''' Determines what type of conversion, if any, would be used if a given expression was
''' converted to a given type.
''' </summary>
''' <param name="position">The character position for determining the enclosing declaration scope and accessibility.</param>
''' <param name="expression">An expression to classify. This expression does not need to be
''' present in the syntax tree associated with this object.</param>
''' <param name="destination">The type to attempt conversion to.</param>
''' <returns>Returns a Conversion object that summarizes whether the conversion was
''' possible, and if so, what kind of conversion it was. If no conversion was possible, a
''' Conversion object with a false "Exists " property is returned.</returns>
''' <remarks>To determine the conversion between two types (instead of an expression and a
''' type), use Compilation.ClassifyConversion.</remarks>
Public Shadows Function ClassifyConversion(position As Integer, expression As ExpressionSyntax, destination As ITypeSymbol) As Conversion
If destination Is Nothing Then
Throw New ArgumentNullException(NameOf(destination))
End If
Dim vbdestination = destination.EnsureVbSymbolOrNothing(Of TypeSymbol)(NameOf(destination))
CheckPosition(position)
Dim binder = Me.GetEnclosingBinder(position)
If binder IsNot Nothing Then
' Add speculative binder to bind speculatively.
binder = SpeculativeBinder.Create(binder)
Dim bnode = binder.BindValue(expression, BindingDiagnosticBag.Discarded)
If bnode IsNot Nothing AndAlso Not vbdestination.IsErrorType() Then
Return New Conversion(Conversions.ClassifyConversion(bnode, vbdestination, binder, CompoundUseSiteInfo(Of AssemblySymbol).Discarded))
End If
End If
Return New Conversion(Nothing) ' NoConversion
End Function
''' <summary>
''' Given a modified identifier that is part of a variable declaration, get the
''' corresponding symbol.
''' </summary>
''' <param name="identifierSyntax">The modified identifier that declares a variable.</param>
''' <returns>The symbol that was declared, or Nothing if no such symbol exists.</returns>
Public Overridable Overloads Function GetDeclaredSymbol(identifierSyntax As ModifiedIdentifierSyntax, Optional cancellationToken As CancellationToken = Nothing) As ISymbol
If identifierSyntax Is Nothing Then
Throw New ArgumentNullException(NameOf(identifierSyntax))
End If
If Not IsInTree(identifierSyntax) Then
Throw New ArgumentException(VBResources.IdentifierSyntaxNotWithinSyntaxTree)
End If
Dim binder As Binder = Me.GetEnclosingBinder(identifierSyntax.SpanStart)
Dim blockBinder = TryCast(StripSemanticModelBinder(binder), BlockBaseBinder)
If blockBinder IsNot Nothing Then
' Most of the time, we should be able to find the identifier by name.
Dim lookupResult As LookupResult = LookupResult.GetInstance()
Try
' NB: "binder", not "blockBinder", so that we don't incorrectly mark imports as used.
binder.Lookup(lookupResult, identifierSyntax.Identifier.ValueText, 0, Nothing, useSiteInfo:=CompoundUseSiteInfo(Of AssemblySymbol).Discarded)
If lookupResult.IsGood Then
Dim sym As LocalSymbol = TryCast(lookupResult.Symbols(0), LocalSymbol)
If sym IsNot Nothing AndAlso sym.IdentifierToken = identifierSyntax.Identifier Then
Return sym
End If
End If
Finally
lookupResult.Free()
End Try
' In some error cases, like multiple symbols of the same name in the same scope, we
' need to do a linear search instead.
For Each local In blockBinder.Locals
If local.IdentifierToken = identifierSyntax.Identifier Then
Return local
End If
Next
End If
Return Nothing
End Function
''' <summary>
''' Gets the corresponding symbol for a specified tuple element.
''' </summary>
''' <param name="elementSyntax">A TupleElementSyntax object.</param>
''' <param name="cancellationToken">A cancellation token.</param>
''' <returns>A symbol, for the specified element; otherwise Nothing. </returns>
Public Overloads Function GetDeclaredSymbol(elementSyntax As TupleElementSyntax, Optional cancellationToken As CancellationToken = Nothing) As ISymbol
CheckSyntaxNode(elementSyntax)
Dim tupleTypeSyntax = TryCast(elementSyntax.Parent, TupleTypeSyntax)
If tupleTypeSyntax IsNot Nothing Then
Return TryCast(GetSymbolInfo(tupleTypeSyntax, cancellationToken).Symbol, TupleTypeSymbol)?.TupleElements.ElementAtOrDefault(tupleTypeSyntax.Elements.IndexOf(elementSyntax))
End If
Return Nothing
End Function
''' <summary>
''' Given a FieldInitializerSyntax, get the corresponding symbol of anonymous type property.
''' </summary>
''' <param name="fieldInitializerSyntax">The anonymous object creation field initializer syntax.</param>
''' <returns>The symbol that was declared, or Nothing if no such symbol exists or
''' if the field initializer was not part of an anonymous type creation.</returns>
Public Overridable Overloads Function GetDeclaredSymbol(fieldInitializerSyntax As FieldInitializerSyntax, Optional cancellationToken As CancellationToken = Nothing) As IPropertySymbol
If fieldInitializerSyntax Is Nothing Then
Throw New ArgumentNullException(NameOf(fieldInitializerSyntax))
End If
If Not IsInTree(fieldInitializerSyntax) Then
Throw New ArgumentException(VBResources.FieldInitializerSyntaxNotWithinSyntaxTree)
End If
Return Nothing
End Function
''' <summary>
''' Given an AnonymousObjectCreationExpressionSyntax, get the corresponding symbol of anonymous type.
''' </summary>
''' <param name="anonymousObjectCreationExpressionSyntax">The anonymous object creation syntax.</param>
''' <returns>The symbol that was declared, or Nothing if no such symbol exists.</returns>
Public Overridable Overloads Function GetDeclaredSymbol(anonymousObjectCreationExpressionSyntax As AnonymousObjectCreationExpressionSyntax, Optional cancellationToken As CancellationToken = Nothing) As INamedTypeSymbol
If anonymousObjectCreationExpressionSyntax Is Nothing Then
Throw New ArgumentNullException(NameOf(anonymousObjectCreationExpressionSyntax))
End If
If Not IsInTree(anonymousObjectCreationExpressionSyntax) Then
Throw New ArgumentException(VBResources.AnonymousObjectCreationExpressionSyntaxNotWithinTree)
End If
Return Nothing
End Function
''' <summary>
''' Given an ExpressionRangeVariableSyntax, get the corresponding symbol.
''' </summary>
''' <param name="rangeVariableSyntax">The range variable syntax that declares a variable.</param>
''' <returns>The symbol that was declared, or Nothing if no such symbol exists.</returns>
Public Overridable Overloads Function GetDeclaredSymbol(rangeVariableSyntax As ExpressionRangeVariableSyntax, Optional cancellationToken As CancellationToken = Nothing) As IRangeVariableSymbol
If rangeVariableSyntax Is Nothing Then
Throw New ArgumentNullException(NameOf(rangeVariableSyntax))
End If
If Not IsInTree(rangeVariableSyntax) Then
Throw New ArgumentException(VBResources.RangeVariableSyntaxNotWithinSyntaxTree)
End If
Return Nothing
End Function
''' <summary>
''' Given a CollectionRangeVariableSyntax, get the corresponding symbol.
''' </summary>
''' <param name="rangeVariableSyntax">The range variable syntax that declares a variable.</param>
''' <returns>The symbol that was declared, or Nothing if no such symbol exists.</returns>
Public Overridable Overloads Function GetDeclaredSymbol(rangeVariableSyntax As CollectionRangeVariableSyntax, Optional cancellationToken As CancellationToken = Nothing) As IRangeVariableSymbol
If rangeVariableSyntax Is Nothing Then
Throw New ArgumentNullException(NameOf(rangeVariableSyntax))
End If
If Not IsInTree(rangeVariableSyntax) Then
Throw New ArgumentException(VBResources.RangeVariableSyntaxNotWithinSyntaxTree)
End If
Return Nothing
End Function
''' <summary>
''' Given an AggregationRangeVariableSyntax, get the corresponding symbol.
''' </summary>
''' <param name="rangeVariableSyntax">The range variable syntax that declares a variable.</param>
''' <returns>The symbol that was declared, or Nothing if no such symbol exists.</returns>
Public Overridable Overloads Function GetDeclaredSymbol(rangeVariableSyntax As AggregationRangeVariableSyntax, Optional cancellationToken As CancellationToken = Nothing) As IRangeVariableSymbol
If rangeVariableSyntax Is Nothing Then
Throw New ArgumentNullException(NameOf(rangeVariableSyntax))
End If
If Not IsInTree(rangeVariableSyntax) Then
Throw New ArgumentException(VBResources.RangeVariableSyntaxNotWithinSyntaxTree)
End If
Return Nothing
End Function
''' <summary>
''' Given a label statement, get the corresponding label symbol.
''' </summary>
''' <param name="declarationSyntax">The label statement.</param>
''' <returns>The label symbol, or Nothing if no such symbol exists.</returns>
Public Overridable Overloads Function GetDeclaredSymbol(declarationSyntax As LabelStatementSyntax, Optional cancellationToken As CancellationToken = Nothing) As ILabelSymbol
If declarationSyntax Is Nothing Then
Throw New ArgumentNullException(NameOf(declarationSyntax))
End If
If Not IsInTree(declarationSyntax) Then
Throw New ArgumentException(VBResources.DeclarationSyntaxNotWithinSyntaxTree)
End If
Dim binder = TryCast(StripSemanticModelBinder(Me.GetEnclosingBinder(declarationSyntax.SpanStart)), BlockBaseBinder)
If binder IsNot Nothing Then
Dim label As LabelSymbol = binder.LookupLabelByNameToken(declarationSyntax.LabelToken)
If label IsNot Nothing Then
Return label
End If
End If
Return Nothing
End Function
''' <summary>
''' Given a declarationSyntax that is part of a enum constant declaration, get the
''' corresponding symbol.
''' </summary>
''' <param name="declarationSyntax">The declarationSyntax that declares a variable.</param>
''' <returns>The symbol that was declared, or Nothing if no such symbol exists.</returns>
Public MustOverride Overloads Function GetDeclaredSymbol(declarationSyntax As EnumMemberDeclarationSyntax, Optional cancellationToken As CancellationToken = Nothing) As IFieldSymbol
''' <summary>
''' Given a type declaration, get the corresponding type symbol.
''' </summary>
''' <param name="declarationSyntax">The syntax node that declares a type.</param>
''' <returns>The type symbol that was declared.</returns>
Public MustOverride Overloads Function GetDeclaredSymbol(declarationSyntax As TypeStatementSyntax, Optional cancellationToken As CancellationToken = Nothing) As INamedTypeSymbol
''' <summary>
''' Given a type block, get the corresponding type symbol.
''' </summary>
''' <param name="declarationSyntax">The syntax node that declares a type block.</param>
''' <returns>The type symbol that was declared.</returns>
Public Overloads Function GetDeclaredSymbol(declarationSyntax As TypeBlockSyntax, Optional cancellationToken As CancellationToken = Nothing) As INamedTypeSymbol
Return GetDeclaredSymbol(declarationSyntax.BlockStatement, cancellationToken)
End Function
''' <summary>
''' Given a enum declaration, get the corresponding type symbol.
''' </summary>
''' <param name="declarationSyntax">The syntax node that declares an enum.</param>
''' <returns>The type symbol that was declared.</returns>
Public MustOverride Overloads Function GetDeclaredSymbol(declarationSyntax As EnumStatementSyntax, Optional cancellationToken As CancellationToken = Nothing) As INamedTypeSymbol
''' <summary>
''' Given a enum block, get the corresponding type symbol.
''' </summary>
''' <param name="declarationSyntax">The syntax node that declares an enum block.</param>
''' <returns>The type symbol that was declared.</returns>
Public Overloads Function GetDeclaredSymbol(declarationSyntax As EnumBlockSyntax, Optional cancellationToken As CancellationToken = Nothing) As INamedTypeSymbol
Return GetDeclaredSymbol(declarationSyntax.EnumStatement, cancellationToken)
End Function
''' <summary>
''' Given a namespace declaration, get the corresponding type symbol.
''' </summary>
''' <param name="declarationSyntax">The syntax node that declares a namespace.</param>
''' <returns>The namespace symbol that was declared.</returns>
Public MustOverride Overloads Function GetDeclaredSymbol(declarationSyntax As NamespaceStatementSyntax, Optional cancellationToken As CancellationToken = Nothing) As INamespaceSymbol
''' <summary>
''' Given a namespace block, get the corresponding type symbol.
''' </summary>
''' <param name="declarationSyntax">The syntax node that declares a namespace block.</param>
''' <returns>The namespace symbol that was declared.</returns>
Public Overloads Function GetDeclaredSymbol(declarationSyntax As NamespaceBlockSyntax, Optional cancellationToken As CancellationToken = Nothing) As INamespaceSymbol
Return GetDeclaredSymbol(declarationSyntax.NamespaceStatement, cancellationToken)
End Function
''' <summary>
''' Given a method, property, or event declaration, get the corresponding symbol.
''' </summary>
''' <param name="declarationSyntax">The syntax node that declares a method, property, or event.</param>
''' <returns>The method, property, or event symbol that was declared.</returns>
Friend MustOverride Overloads Function GetDeclaredSymbol(declarationSyntax As MethodBaseSyntax, Optional cancellationToken As CancellationToken = Nothing) As ISymbol
''' <summary>
''' Given a parameter declaration, get the corresponding parameter symbol.
''' </summary>
''' <param name="parameter">The syntax node that declares a parameter.</param>
''' <returns>The parameter symbol that was declared.</returns>
Public MustOverride Overloads Function GetDeclaredSymbol(parameter As ParameterSyntax, Optional cancellationToken As CancellationToken = Nothing) As IParameterSymbol
''' <summary>
''' Given a type parameter declaration, get the corresponding type parameter symbol.
''' </summary>
''' <param name="typeParameter">The syntax node that declares a type parameter.</param>
''' <returns>The type parameter symbol that was declared.</returns>
Public MustOverride Overloads Function GetDeclaredSymbol(typeParameter As TypeParameterSyntax, Optional cancellationToken As CancellationToken = Nothing) As ITypeParameterSymbol
''' <summary>
''' Given a delegate statement syntax get the corresponding named type symbol.
''' </summary>
''' <param name="declarationSyntax">The syntax node that declares a delegate.</param>
''' <returns>The named type that was declared.</returns>
Public Overloads Function GetDeclaredSymbol(declarationSyntax As DelegateStatementSyntax, Optional cancellationToken As CancellationToken = Nothing) As NamedTypeSymbol
Return DirectCast(GetDeclaredSymbol(DirectCast(declarationSyntax, MethodBaseSyntax), cancellationToken), NamedTypeSymbol)
End Function
''' <summary>
''' Given a constructor statement syntax get the corresponding method symbol.
''' </summary>
''' <param name="declarationSyntax">The syntax node that declares a constructor.</param>
''' <returns>The method symbol that was declared.</returns>
Public Overloads Function GetDeclaredSymbol(declarationSyntax As SubNewStatementSyntax, Optional cancellationToken As CancellationToken = Nothing) As IMethodSymbol
Return DirectCast(GetDeclaredSymbol(DirectCast(declarationSyntax, MethodBaseSyntax), cancellationToken), MethodSymbol)
End Function
''' <summary>
''' Given a method statement syntax get the corresponding method symbol.
''' </summary>
''' <param name="declarationSyntax">The syntax node that declares a method.</param>
''' <returns>The method symbol that was declared.</returns>
Public Overloads Function GetDeclaredSymbol(declarationSyntax As MethodStatementSyntax, Optional cancellationToken As CancellationToken = Nothing) As IMethodSymbol
Return DirectCast(GetDeclaredSymbol(DirectCast(declarationSyntax, MethodBaseSyntax), cancellationToken), MethodSymbol)
End Function
''' <summary>
''' Given a method statement syntax get the corresponding method symbol.
''' </summary>
''' <param name="declarationSyntax">The syntax node that declares a method.</param>
''' <returns>The method symbol that was declared.</returns>
Public Overloads Function GetDeclaredSymbol(declarationSyntax As DeclareStatementSyntax, Optional cancellationToken As CancellationToken = Nothing) As IMethodSymbol
Return DirectCast(GetDeclaredSymbol(DirectCast(declarationSyntax, MethodBaseSyntax), cancellationToken), MethodSymbol)
End Function
''' <summary>
''' Given a operator statement syntax get the corresponding method symbol.
''' </summary>
''' <param name="declarationSyntax">The syntax node that declares an operator.</param>
''' <returns>The method symbol that was declared.</returns>
Public Overloads Function GetDeclaredSymbol(declarationSyntax As OperatorStatementSyntax, Optional cancellationToken As CancellationToken = Nothing) As IMethodSymbol
Return DirectCast(GetDeclaredSymbol(DirectCast(declarationSyntax, MethodBaseSyntax), cancellationToken), MethodSymbol)
End Function
''' <summary>
''' Given a method block syntax get the corresponding method, property or event symbol.
''' </summary>
''' <param name="declarationSyntax">The syntax node that declares method, property or event.</param>
''' <returns>The method, property or event symbol that was declared.</returns>
Public Overloads Function GetDeclaredSymbol(declarationSyntax As MethodBlockBaseSyntax, Optional cancellationToken As CancellationToken = Nothing) As IMethodSymbol
Return DirectCast(GetDeclaredSymbol(declarationSyntax.BlockStatement, cancellationToken), MethodSymbol)
End Function
''' <summary>
''' Given a property statement syntax get the corresponding property symbol.
''' </summary>
''' <param name="declarationSyntax">The syntax node that declares a property.</param>
''' <returns>The property symbol that was declared.</returns>
Public Overloads Function GetDeclaredSymbol(declarationSyntax As PropertyStatementSyntax, Optional cancellationToken As CancellationToken = Nothing) As IPropertySymbol
Return DirectCast(GetDeclaredSymbol(DirectCast(declarationSyntax, MethodBaseSyntax), cancellationToken), PropertySymbol)
End Function
''' <summary>
''' Given an event statement syntax get the corresponding event symbol.
''' </summary>
''' <param name="declarationSyntax">The syntax node that declares an event.</param>
''' <returns>The event symbol that was declared.</returns>
Public Overloads Function GetDeclaredSymbol(declarationSyntax As EventStatementSyntax, Optional cancellationToken As CancellationToken = Nothing) As IEventSymbol
Return DirectCast(GetDeclaredSymbol(DirectCast(declarationSyntax, MethodBaseSyntax), cancellationToken), EventSymbol)
End Function
''' <summary>
''' Given a property block syntax get the corresponding property symbol.
''' </summary>
''' <param name="declarationSyntax">The syntax node that declares property.</param>
''' <returns>The property symbol that was declared.</returns>
Public Overloads Function GetDeclaredSymbol(declarationSyntax As PropertyBlockSyntax, Optional cancellationToken As CancellationToken = Nothing) As IPropertySymbol
Return GetDeclaredSymbol(declarationSyntax.PropertyStatement, cancellationToken)
End Function
''' <summary>
''' Given a custom event block syntax get the corresponding event symbol.
''' </summary>
''' <param name="declarationSyntax">The syntax node that declares the custom event.</param>
''' <returns>The event symbol that was declared.</returns>
Public Overloads Function GetDeclaredSymbol(declarationSyntax As EventBlockSyntax, Optional cancellationToken As CancellationToken = Nothing) As IEventSymbol
Return GetDeclaredSymbol(declarationSyntax.EventStatement, cancellationToken)
End Function
''' <summary>
''' Given a catch statement syntax get the corresponding local symbol.
''' </summary>
''' <param name="declarationSyntax">The catch statement syntax node.</param>
''' <returns>The local symbol that was declared by the Catch statement or Nothing if statement does not declare a local variable.</returns>
Public Overloads Function GetDeclaredSymbol(declarationSyntax As CatchStatementSyntax, Optional cancellationToken As CancellationToken = Nothing) As ILocalSymbol
Dim enclosingBinder = StripSemanticModelBinder(Me.GetEnclosingBinder(declarationSyntax.SpanStart))
Dim catchBinder = TryCast(enclosingBinder, CatchBlockBinder)
If catchBinder IsNot Nothing Then
Return catchBinder.Locals.FirstOrDefault
End If
Return Nothing
End Function
''' <summary>
''' Given a property block syntax get the corresponding property symbol.
''' </summary>
''' <param name="declarationSyntax">The syntax node that declares property.</param>
''' <returns>The property symbol that was declared.</returns>
Public Overloads Function GetDeclaredSymbol(declarationSyntax As AccessorStatementSyntax, Optional cancellationToken As CancellationToken = Nothing) As IMethodSymbol
Return DirectCast(GetDeclaredSymbol(DirectCast(declarationSyntax, MethodBaseSyntax), cancellationToken), MethodSymbol)
End Function
''' <summary>
''' Given an import clause get the corresponding symbol for the import alias that was introduced.
''' </summary>
''' <param name="declarationSyntax">The import statement syntax node.</param>
''' <returns>The alias symbol that was declared or Nothing if no alias symbol was declared.</returns>
Public MustOverride Overloads Function GetDeclaredSymbol(declarationSyntax As SimpleImportsClauseSyntax, Optional cancellationToken As CancellationToken = Nothing) As IAliasSymbol
''' <summary>
''' Given a field declaration syntax, get the corresponding symbols.
''' </summary>
''' <param name="declarationSyntax">The syntax node that declares one or more fields.</param>
''' <returns>The field symbols that were declared.</returns>
Friend MustOverride Function GetDeclaredSymbols(declarationSyntax As FieldDeclarationSyntax, Optional cancellationToken As CancellationToken = Nothing) As ImmutableArray(Of ISymbol)
''' <summary>
''' Gets bound node summary of the underlying invocation in a case of RaiseEvent
''' </summary>
Friend MustOverride Function GetInvokeSummaryForRaiseEvent(node As RaiseEventStatementSyntax) As BoundNodeSummary
' Get the symbol info of a named argument in an invocation-like expression.
Private Function GetNamedArgumentSymbolInfo(identifierNameSyntax As IdentifierNameSyntax, cancellationToken As CancellationToken) As SymbolInfo
Debug.Assert(SyntaxFacts.IsNamedArgumentName(identifierNameSyntax))
' Argument names do not have bound nodes associated with them, so we cannot use the usual
' GetSemanticInfo mechanism. Instead, we just do the following:
' 1. Find the containing invocation.
' 2. Call GetSemanticInfo on that.
' 3. For each method or indexer in the return semantic info, find the argument
' with the given name (if any).
' 4. Use the ResultKind in that semantic info and any symbols to create the semantic info
' for the named argument.
' 5. Type is always null, as is constant value.
Dim argumentName As String = identifierNameSyntax.Identifier.ValueText
If argumentName.Length = 0 Then
Return SymbolInfo.None
End If
' RaiseEvent Invocation(SimpleArgument(((Identifier):=)(Expression))
' check for RaiseEvent here, it is not an expression.
If identifierNameSyntax.Parent.Parent.Parent.Parent.Kind = SyntaxKind.RaiseEventStatement Then
Dim asRaiseEvent = DirectCast(identifierNameSyntax.Parent.Parent.Parent.Parent, RaiseEventStatementSyntax)
Return GetNamedArgumentSymbolInfoInRaiseEvent(argumentName, asRaiseEvent)
End If
' Invocation(SimpleArgument(((Identifier):=)(Expression))
Dim containingInvocation = DirectCast(identifierNameSyntax.Parent.Parent.Parent.Parent, ExpressionSyntax)
Dim containingInvocationInfo As SymbolInfo = GetExpressionSymbolInfo(containingInvocation, SymbolInfoOptions.PreferConstructorsToType Or SymbolInfoOptions.ResolveAliases, cancellationToken)
Return FindNameParameterInfo(containingInvocationInfo.GetAllSymbols().Cast(Of Symbol).ToImmutableArray(),
argumentName,
containingInvocationInfo.CandidateReason)
End Function
''' <summary>
''' RaiseEvent situation is very special:
''' 1) Unlike other syntaxes that take named arguments, RaiseEvent is a statement.
''' 2) RaiseEvent is essentially a wrapper around underlying call to the event rising method.
''' Note that while event itself may have named parameters in its syntax, their names could be irrelevant
''' For the purpose of fetching named parameters, it is the target of the call that we are interested in.
'''
''' === Example:
'''
''' Interface I1
''' Event E(qwer As Integer)
''' End Interface
'''
''' Class cls1 : Implements I1
''' Event E3(bar As Integer) Implements I1.E ' "bar" means nothing here. Only type matters.
'''
''' Sub moo()
''' RaiseEvent E3(qwer:=123) ' qwer binds to parameter on I1.EEventhandler.invoke(goo)
''' End Sub
'''End Class
'''
'''
''' </summary>
Private Function GetNamedArgumentSymbolInfoInRaiseEvent(argumentName As String,
containingRaiseEvent As RaiseEventStatementSyntax) As SymbolInfo
Dim summary = GetInvokeSummaryForRaiseEvent(containingRaiseEvent)
' Determine the symbols, resultKind, and member group.
Dim resultKind As LookupResultKind = LookupResultKind.Empty
Dim memberGroup As ImmutableArray(Of Symbol) = Nothing
Dim containingInvocationInfosymbols As ImmutableArray(Of Symbol) = GetSemanticSymbols(summary,
Nothing,
SymbolInfoOptions.PreferConstructorsToType Or SymbolInfoOptions.ResolveAliases,
resultKind,
memberGroup)
Return FindNameParameterInfo(containingInvocationInfosymbols,
argumentName,
If(resultKind = LookupResultKind.Good, CandidateReason.None, resultKind.ToCandidateReason()))
End Function
Private Function FindNameParameterInfo(invocationInfosymbols As ImmutableArray(Of Symbol),
arGumentName As String,
reason As CandidateReason) As SymbolInfo
Dim symbols As ArrayBuilder(Of Symbol) = ArrayBuilder(Of Symbol).GetInstance()
For Each invocationSym In invocationInfosymbols
Dim param As ParameterSymbol = FindNamedParameter(invocationSym, arGumentName)
If param IsNot Nothing Then
symbols.Add(param)
End If
Next
If symbols.Count = 0 Then
symbols.Free()
Return SymbolInfo.None
Else
Return SymbolInfoFactory.Create(StaticCast(Of ISymbol).From(symbols.ToImmutableAndFree()), reason)
End If
End Function
' Find the first parameter, if any, on method or property symbol named "argumentName"
Private Function FindNamedParameter(symbol As Symbol, argumentName As String) As ParameterSymbol
Dim params As ImmutableArray(Of ParameterSymbol)
If symbol.Kind = SymbolKind.Method Then
params = DirectCast(symbol, MethodSymbol).Parameters
ElseIf symbol.Kind = SymbolKind.Property Then
params = DirectCast(symbol, PropertySymbol).Parameters
Else
Return Nothing
End If
For Each param In params
If CaseInsensitiveComparison.Equals(param.Name, argumentName) Then
Return param
End If
Next
Return Nothing
End Function
''' <summary>
''' The SyntaxTree that is bound
''' </summary>
Public MustOverride Shadows ReadOnly Property SyntaxTree As SyntaxTree
''' <summary>
''' Gets the semantic information of a for each statement.
''' </summary>
''' <param name="node">The for each syntax node.</param>
Public Shadows Function GetForEachStatementInfo(node As ForEachStatementSyntax) As ForEachStatementInfo
If node.Parent IsNot Nothing AndAlso node.Parent.Kind = SyntaxKind.ForEachBlock Then
Return GetForEachStatementInfoWorker(DirectCast(node.Parent, ForEachBlockSyntax))
End If
Return Nothing
End Function
''' <summary>
''' Gets the semantic information of a for each statement.
''' </summary>
''' <param name="node">The for block syntax node.</param>
Public Shadows Function GetForEachStatementInfo(node As ForEachBlockSyntax) As ForEachStatementInfo
If node.Kind = SyntaxKind.ForEachBlock Then
Return GetForEachStatementInfoWorker(node)
End If
Return Nothing
End Function
''' <summary>
''' Gets the semantic information of a for each statement.
''' </summary>
''' <param name="node">The for each syntax node.</param>
Friend MustOverride Function GetForEachStatementInfoWorker(node As ForEachBlockSyntax) As ForEachStatementInfo
''' <summary>
''' Gets the semantic information of an Await expression.
''' </summary>
Public Function GetAwaitExpressionInfo(awaitExpression As AwaitExpressionSyntax, Optional cancellationToken As CancellationToken = Nothing) As AwaitExpressionInfo
CheckSyntaxNode(awaitExpression)
If CanGetSemanticInfo(awaitExpression) Then
Return GetAwaitExpressionInfoWorker(awaitExpression, cancellationToken)
Else
Return Nothing
End If
End Function
Friend MustOverride Function GetAwaitExpressionInfoWorker(awaitExpression As AwaitExpressionSyntax, Optional cancellationToken As CancellationToken = Nothing) As AwaitExpressionInfo
''' <summary>
''' If the given node is within a preprocessing directive, gets the preprocessing symbol info for it.
''' </summary>
''' <param name="node">Preprocessing symbol identifier node.</param>
Public Shadows Function GetPreprocessingSymbolInfo(node As IdentifierNameSyntax) As VisualBasicPreprocessingSymbolInfo
CheckSyntaxNode(node)
If SyntaxFacts.IsWithinPreprocessorConditionalExpression(node) Then
Dim symbolInfo As VisualBasicPreprocessingSymbolInfo = node.SyntaxTree.GetPreprocessingSymbolInfo(node)
If symbolInfo.Symbol IsNot Nothing Then
Debug.Assert(CaseInsensitiveComparison.Equals(symbolInfo.Symbol.Name, node.Identifier.ValueText))
Return symbolInfo
End If
Return New VisualBasicPreprocessingSymbolInfo(New PreprocessingSymbol(node.Identifier.ValueText), constantValueOpt:=Nothing, isDefined:=False)
End If
Return VisualBasicPreprocessingSymbolInfo.None
End Function
''' <summary>
''' Options to control the internal working of GetSemanticInfoWorker. Not currently exposed
''' to public clients, but could be if desired.
''' </summary>
Friend Enum SymbolInfoOptions
''' <summary>
''' When binding "C" new C(...), return the type C and do not return information about
''' which constructor was bound to. Bind "new C(...)" to get information about which constructor
''' was chosen.
''' </summary>
PreferTypeToConstructors = &H1
''' <summary>
''' When binding "C" new C(...), return the constructor of C that was bound to, if C unambiguously
''' binds to a single type with at least one constructor.
''' </summary>
PreferConstructorsToType = &H2
''' <summary>
''' When binding a name X that was declared with a "using X=OtherTypeOrNamespace", return OtherTypeOrNamespace.
''' </summary>
ResolveAliases = &H4
''' <summary>
''' When binding a name X that was declared with a "using X=OtherTypeOrNamespace", return the alias symbol X.
''' </summary>
PreserveAliases = &H8
' Default options
DefaultOptions = PreferConstructorsToType Or ResolveAliases
End Enum
Friend Sub ValidateSymbolInfoOptions(options As SymbolInfoOptions)
Debug.Assert(((options And SymbolInfoOptions.PreferConstructorsToType) <> 0) <> ((options And SymbolInfoOptions.PreferTypeToConstructors) <> 0), "Options are mutually exclusive")
Debug.Assert(((options And SymbolInfoOptions.ResolveAliases) <> 0) <> ((options And SymbolInfoOptions.PreserveAliases) <> 0), "Options are mutually exclusive")
End Sub
''' <summary>
''' Given a position in the SyntaxTree for this SemanticModel returns the innermost Symbol
''' that the position is considered inside of.
''' </summary>
Public Shadows Function GetEnclosingSymbol(position As Integer, Optional cancellationToken As CancellationToken = Nothing) As ISymbol
CheckPosition(position)
Dim binder = Me.GetEnclosingBinder(position)
Return If(binder Is Nothing, Nothing, binder.ContainingMember)
End Function
''' <summary>
''' Get the state of Option Strict for the code covered by this semantic model.
''' This takes into effect both file-level "Option Strict" statements and the project-level
''' defaults.
''' </summary>
Public ReadOnly Property OptionStrict As VisualBasic.OptionStrict
Get
' Since options never change within a file, we can just use the start location.
Dim binder = Me.GetEnclosingBinder(Root.SpanStart) ' should never return null.
Return binder.OptionStrict
End Get
End Property
''' <summary>
''' Get the state of Option Infer for the code covered by this semantic model.
''' This takes into effect both file-level "Option Infer" statements and the project-level
''' defaults.
''' </summary>
''' <value>True if Option Infer On, False if Option Infer Off.</value>
Public ReadOnly Property OptionInfer As Boolean
Get
' Since options never change within a file, we can just use the start location.
Dim binder = Me.GetEnclosingBinder(Root.SpanStart) ' should never return null.
Return binder.OptionInfer
End Get
End Property
''' <summary>
''' Get the state of Option Explicit for the code covered by this semantic model.
''' This takes into effect both file-level "Option Explicit" statements and the project-level
''' defaults.
''' </summary>
''' <value>True if Option Explicit On, False if Option Explicit Off.</value>
Public ReadOnly Property OptionExplicit As Boolean
Get
' Since options never change within a file, we can just use the start location.
Dim binder = Me.GetEnclosingBinder(Root.SpanStart) ' should never return null.
Return binder.OptionExplicit
End Get
End Property
''' <summary>
''' Get the state of Option Compare for the code covered by this semantic model.
''' This takes into effect both file-level "Option Compare" statements and the project-level
''' defaults.
''' </summary>
''' <value>True if Option Compare Text, False if Option Compare Binary.</value>
Public ReadOnly Property OptionCompareText As Boolean
Get
' Since options never change within a file, we can just use the start location.
Dim binder = Me.GetEnclosingBinder(Root.SpanStart) ' should never return null.
Return binder.OptionCompareText
End Get
End Property
Friend Shared Function StripSemanticModelBinder(binder As Binder) As Binder
If binder Is Nothing OrElse Not binder.IsSemanticModelBinder Then
Return binder
End If
Return If(TypeOf binder Is SemanticModelBinder, binder.ContainingBinder, binder)
End Function
#Region "SemanticModel"
Public NotOverridable Overrides ReadOnly Property Language As String
Get
Return LanguageNames.VisualBasic
End Get
End Property
Protected NotOverridable Overrides ReadOnly Property ParentModelCore As SemanticModel
Get
Return Me.ParentModel
End Get
End Property
Protected NotOverridable Overrides ReadOnly Property SyntaxTreeCore As SyntaxTree
Get
Return Me.SyntaxTree
End Get
End Property
Protected NotOverridable Overrides ReadOnly Property CompilationCore As Compilation
Get
Return Me.Compilation
End Get
End Property
Protected NotOverridable Overrides ReadOnly Property RootCore As SyntaxNode
Get
Return Me.Root
End Get
End Property
Private Function GetSymbolInfoForNode(node As SyntaxNode, Optional cancellationToken As CancellationToken = Nothing) As SymbolInfo
If node Is Nothing Then
Throw New ArgumentNullException(NameOf(node))
End If
Dim expressionSyntax = TryCast(node, ExpressionSyntax)
If expressionSyntax IsNot Nothing Then
Return Me.GetSymbolInfo(expressionSyntax, cancellationToken)
End If
Dim attributeSyntax = TryCast(node, AttributeSyntax)
If attributeSyntax IsNot Nothing Then
Return Me.GetSymbolInfo(attributeSyntax, cancellationToken)
End If
Dim clauseSyntax = TryCast(node, QueryClauseSyntax)
If clauseSyntax IsNot Nothing Then
Return Me.GetSymbolInfo(clauseSyntax, cancellationToken)
End If
Dim letVariable = TryCast(node, ExpressionRangeVariableSyntax)
If letVariable IsNot Nothing Then
Return Me.GetSymbolInfo(letVariable, cancellationToken)
End If
Dim ordering = TryCast(node, OrderingSyntax)
If ordering IsNot Nothing Then
Return Me.GetSymbolInfo(ordering, cancellationToken)
End If
Dim [function] = TryCast(node, FunctionAggregationSyntax)
If [function] IsNot Nothing Then
Return Me.GetSymbolInfo([function], cancellationToken)
End If
Dim cref = TryCast(node, CrefReferenceSyntax)
If cref IsNot Nothing Then
Return Me.GetSymbolInfo(cref, cancellationToken)
End If
Return SymbolInfo.None
End Function
Private Function GetTypeInfoForNode(node As SyntaxNode, Optional cancellationToken As CancellationToken = Nothing) As VisualBasicTypeInfo
If node Is Nothing Then
Throw New ArgumentNullException(NameOf(node))
End If
Dim expressionSyntax = TryCast(node, ExpressionSyntax)
If expressionSyntax IsNot Nothing Then
Return Me.GetTypeInfoWorker(expressionSyntax, cancellationToken)
End If
Dim attributeSyntax = TryCast(node, AttributeSyntax)
If attributeSyntax IsNot Nothing Then
Return Me.GetTypeInfoWorker(attributeSyntax, cancellationToken)
End If
Return VisualBasicTypeInfo.None
End Function
Private Function GetMemberGroupForNode(node As SyntaxNode, Optional cancellationToken As CancellationToken = Nothing) As ImmutableArray(Of ISymbol)
If node Is Nothing Then
Throw New ArgumentNullException(NameOf(node))
End If
Dim expressionSyntax = TryCast(node, ExpressionSyntax)
If expressionSyntax IsNot Nothing Then
Return Me.GetMemberGroup(expressionSyntax, cancellationToken)
End If
Dim attributeSyntax = TryCast(node, AttributeSyntax)
If attributeSyntax IsNot Nothing Then
Return Me.GetMemberGroup(attributeSyntax, cancellationToken)
End If
Return ImmutableArray(Of ISymbol).Empty
End Function
Protected NotOverridable Overrides Function GetSpeculativeTypeInfoCore(position As Integer, expression As SyntaxNode, bindingOption As SpeculativeBindingOption) As TypeInfo
Return If(TypeOf expression Is ExpressionSyntax,
Me.GetSpeculativeTypeInfo(position, DirectCast(expression, ExpressionSyntax), bindingOption),
Nothing)
End Function
Protected NotOverridable Overrides Function GetSpeculativeSymbolInfoCore(position As Integer, expression As SyntaxNode, bindingOption As SpeculativeBindingOption) As SymbolInfo
Return If(TypeOf expression Is ExpressionSyntax,
GetSpeculativeSymbolInfo(position, DirectCast(expression, ExpressionSyntax), bindingOption),
Nothing)
End Function
Protected NotOverridable Overrides Function GetSpeculativeAliasInfoCore(position As Integer, nameSyntax As SyntaxNode, bindingOption As SpeculativeBindingOption) As IAliasSymbol
Return If(TypeOf nameSyntax Is IdentifierNameSyntax,
GetSpeculativeAliasInfo(position, DirectCast(nameSyntax, IdentifierNameSyntax), bindingOption),
Nothing)
End Function
Protected NotOverridable Overrides Function GetSymbolInfoCore(node As SyntaxNode, Optional cancellationToken As CancellationToken = Nothing) As SymbolInfo
Return GetSymbolInfoForNode(node, cancellationToken)
End Function
Protected NotOverridable Overrides Function GetTypeInfoCore(node As SyntaxNode, Optional cancellationToken As CancellationToken = Nothing) As TypeInfo
Return GetTypeInfoForNode(node, cancellationToken)
End Function
Protected NotOverridable Overrides Function GetAliasInfoCore(node As SyntaxNode, Optional cancellationToken As CancellationToken = Nothing) As IAliasSymbol
If node Is Nothing Then
Throw New ArgumentNullException(NameOf(node))
End If
Dim nameSyntax = TryCast(node, IdentifierNameSyntax)
If nameSyntax IsNot Nothing Then
Return GetAliasInfo(nameSyntax, cancellationToken)
End If
Return Nothing
End Function
Protected NotOverridable Overrides Function GetPreprocessingSymbolInfoCore(node As SyntaxNode) As PreprocessingSymbolInfo
Dim nameSyntax = TryCast(node, IdentifierNameSyntax)
If nameSyntax IsNot Nothing Then
Return GetPreprocessingSymbolInfo(nameSyntax)
End If
Return Nothing
End Function
Protected NotOverridable Overrides Function GetMemberGroupCore(node As SyntaxNode, Optional cancellationToken As CancellationToken = Nothing) As ImmutableArray(Of ISymbol)
Return GetMemberGroupForNode(node, cancellationToken)
End Function
Protected NotOverridable Overrides Function LookupSymbolsCore(position As Integer, container As INamespaceOrTypeSymbol, name As String, includeReducedExtensionMethods As Boolean) As ImmutableArray(Of ISymbol)
Return LookupSymbols(position, ToLanguageSpecific(container), name, includeReducedExtensionMethods)
End Function
Protected NotOverridable Overrides Function LookupBaseMembersCore(position As Integer, name As String) As ImmutableArray(Of ISymbol)
Return LookupBaseMembers(position, name)
End Function
Protected NotOverridable Overrides Function LookupStaticMembersCore(position As Integer, container As INamespaceOrTypeSymbol, name As String) As ImmutableArray(Of ISymbol)
Return LookupStaticMembers(position, ToLanguageSpecific(container), name)
End Function
Protected NotOverridable Overrides Function LookupNamespacesAndTypesCore(position As Integer, container As INamespaceOrTypeSymbol, name As String) As ImmutableArray(Of ISymbol)
Return LookupNamespacesAndTypes(position, ToLanguageSpecific(container), name)
End Function
Protected NotOverridable Overrides Function LookupLabelsCore(position As Integer, name As String) As ImmutableArray(Of ISymbol)
Return LookupLabels(position, name)
End Function
Private Shared Function ToLanguageSpecific(container As INamespaceOrTypeSymbol) As NamespaceOrTypeSymbol
If container Is Nothing Then
Return Nothing
End If
Dim result = TryCast(container, NamespaceOrTypeSymbol)
If result Is Nothing Then
Throw New ArgumentException(VBResources.NotAVbSymbol, NameOf(container))
End If
Return result
End Function
Protected NotOverridable Overrides Function GetDeclaredSymbolCore(declaration As SyntaxNode, Optional cancellationToken As CancellationToken = Nothing) As ISymbol
cancellationToken.ThrowIfCancellationRequested()
Dim node = DirectCast(declaration, VisualBasicSyntaxNode)
Select Case node.Kind
Case SyntaxKind.SimpleImportsClause
Return Me.GetDeclaredSymbol(DirectCast(node, SimpleImportsClauseSyntax), cancellationToken)
Case SyntaxKind.TypedTupleElement,
SyntaxKind.NamedTupleElement
Return Me.GetDeclaredSymbol(DirectCast(node, TupleElementSyntax), cancellationToken)
Case SyntaxKind.ModifiedIdentifier
Return Me.GetDeclaredSymbol(DirectCast(node, ModifiedIdentifierSyntax), cancellationToken)
Case SyntaxKind.EnumMemberDeclaration
Return Me.GetDeclaredSymbol(DirectCast(node, EnumMemberDeclarationSyntax), cancellationToken)
Case SyntaxKind.Parameter
Return Me.GetDeclaredSymbol(DirectCast(node, ParameterSyntax), cancellationToken)
Case SyntaxKind.TypeParameter
Return Me.GetDeclaredSymbol(DirectCast(node, TypeParameterSyntax), cancellationToken)
Case SyntaxKind.LabelStatement
Return Me.GetDeclaredSymbol(DirectCast(node, LabelStatementSyntax), cancellationToken)
Case SyntaxKind.NamespaceStatement
Return Me.GetDeclaredSymbol(DirectCast(node, NamespaceStatementSyntax), cancellationToken)
Case SyntaxKind.ClassStatement, SyntaxKind.StructureStatement, SyntaxKind.InterfaceStatement, SyntaxKind.ModuleStatement
Return Me.GetDeclaredSymbol(DirectCast(node, TypeStatementSyntax), cancellationToken)
Case SyntaxKind.EnumStatement
Return Me.GetDeclaredSymbol(DirectCast(node, EnumStatementSyntax), cancellationToken)
Case SyntaxKind.DelegateSubStatement, SyntaxKind.DelegateFunctionStatement
Return Me.GetDeclaredSymbol(DirectCast(node, DelegateStatementSyntax), cancellationToken)
Case SyntaxKind.SubStatement, SyntaxKind.FunctionStatement
Return Me.GetDeclaredSymbol(DirectCast(node, MethodStatementSyntax), cancellationToken)
Case SyntaxKind.PropertyStatement
Return Me.GetDeclaredSymbol(DirectCast(node, PropertyStatementSyntax), cancellationToken)
Case SyntaxKind.EventStatement
Return Me.GetDeclaredSymbol(DirectCast(node, EventStatementSyntax), cancellationToken)
Case SyntaxKind.SubNewStatement
Return Me.GetDeclaredSymbol(DirectCast(node, SubNewStatementSyntax), cancellationToken)
Case SyntaxKind.GetAccessorStatement, SyntaxKind.SetAccessorStatement,
SyntaxKind.AddHandlerAccessorStatement, SyntaxKind.RemoveHandlerAccessorStatement, SyntaxKind.RaiseEventAccessorStatement
Return Me.GetDeclaredSymbol(DirectCast(node, AccessorStatementSyntax), cancellationToken)
Case SyntaxKind.OperatorStatement,
SyntaxKind.DeclareSubStatement, SyntaxKind.DeclareFunctionStatement
Return Me.GetDeclaredSymbol(DirectCast(node, MethodBaseSyntax), cancellationToken)
Case SyntaxKind.NamespaceBlock
Return Me.GetDeclaredSymbol(DirectCast(node, NamespaceBlockSyntax), cancellationToken)
Case SyntaxKind.ClassBlock, SyntaxKind.StructureBlock, SyntaxKind.InterfaceBlock, SyntaxKind.ModuleBlock
Return Me.GetDeclaredSymbol(DirectCast(node, TypeBlockSyntax), cancellationToken)
Case SyntaxKind.EnumBlock
Return Me.GetDeclaredSymbol(DirectCast(node, EnumBlockSyntax), cancellationToken)
Case SyntaxKind.SubBlock, SyntaxKind.FunctionBlock, SyntaxKind.ConstructorBlock, SyntaxKind.OperatorBlock,
SyntaxKind.GetAccessorBlock, SyntaxKind.SetAccessorBlock,
SyntaxKind.AddHandlerAccessorBlock, SyntaxKind.RemoveHandlerAccessorBlock, SyntaxKind.RaiseEventAccessorBlock
Return Me.GetDeclaredSymbol(DirectCast(node, MethodBlockBaseSyntax), cancellationToken)
Case SyntaxKind.PropertyBlock
Return Me.GetDeclaredSymbol(DirectCast(node, PropertyBlockSyntax), cancellationToken)
Case SyntaxKind.EventBlock
Return Me.GetDeclaredSymbol(DirectCast(node, EventBlockSyntax), cancellationToken)
Case SyntaxKind.CollectionRangeVariable
Return Me.GetDeclaredSymbol(DirectCast(node, CollectionRangeVariableSyntax), cancellationToken)
Case SyntaxKind.ExpressionRangeVariable
Return Me.GetDeclaredSymbol(DirectCast(node, ExpressionRangeVariableSyntax), cancellationToken)
Case SyntaxKind.AggregationRangeVariable
Return Me.GetDeclaredSymbol(DirectCast(node, AggregationRangeVariableSyntax), cancellationToken)
Case SyntaxKind.CatchStatement
Return Me.GetDeclaredSymbol(DirectCast(node, CatchStatementSyntax), cancellationToken)
Case SyntaxKind.InferredFieldInitializer, SyntaxKind.NamedFieldInitializer
Return Me.GetDeclaredSymbol(DirectCast(node, FieldInitializerSyntax), cancellationToken)
Case SyntaxKind.AnonymousObjectCreationExpression
Return Me.GetDeclaredSymbol(DirectCast(node, AnonymousObjectCreationExpressionSyntax), cancellationToken)
End Select
Dim td = TryCast(node, TypeStatementSyntax)
If td IsNot Nothing Then
Return Me.GetDeclaredSymbol(td, cancellationToken)
End If
Dim md = TryCast(node, MethodBaseSyntax)
If md IsNot Nothing Then
Return Me.GetDeclaredSymbol(md, cancellationToken)
End If
Return Nothing
End Function
Protected NotOverridable Overrides Function GetDeclaredSymbolsCore(declaration As SyntaxNode, Optional cancellationToken As CancellationToken = Nothing) As ImmutableArray(Of ISymbol)
cancellationToken.ThrowIfCancellationRequested()
Dim field = TryCast(declaration, FieldDeclarationSyntax)
If field IsNot Nothing Then
Return Me.GetDeclaredSymbols(field, cancellationToken)
End If
Dim symbol = GetDeclaredSymbolCore(declaration, cancellationToken)
If symbol IsNot Nothing Then
Return ImmutableArray.Create(symbol)
End If
Return ImmutableArray.Create(Of ISymbol)()
End Function
Protected NotOverridable Overrides Function AnalyzeDataFlowCore(firstStatement As SyntaxNode, lastStatement As SyntaxNode) As DataFlowAnalysis
Return Me.AnalyzeDataFlow(SafeCastArgument(Of StatementSyntax)(firstStatement, NameOf(firstStatement)),
SafeCastArgument(Of StatementSyntax)(lastStatement, NameOf(lastStatement)))
End Function
Protected NotOverridable Overrides Function AnalyzeDataFlowCore(statementOrExpression As SyntaxNode) As DataFlowAnalysis
If statementOrExpression Is Nothing Then
Throw New ArgumentNullException(NameOf(statementOrExpression))
End If
If TypeOf statementOrExpression Is ExecutableStatementSyntax Then
Return Me.AnalyzeDataFlow(DirectCast(statementOrExpression, StatementSyntax))
ElseIf TypeOf statementOrExpression Is ExpressionSyntax Then
Return Me.AnalyzeDataFlow(DirectCast(statementOrExpression, ExpressionSyntax))
Else
Throw New ArgumentException(VBResources.StatementOrExpressionIsNotAValidType)
End If
End Function
Protected NotOverridable Overrides Function AnalyzeControlFlowCore(firstStatement As SyntaxNode, lastStatement As SyntaxNode) As ControlFlowAnalysis
Return Me.AnalyzeControlFlow(SafeCastArgument(Of StatementSyntax)(firstStatement, NameOf(firstStatement)),
SafeCastArgument(Of StatementSyntax)(lastStatement, NameOf(lastStatement)))
End Function
Protected NotOverridable Overrides Function AnalyzeControlFlowCore(statement As SyntaxNode) As ControlFlowAnalysis
Return Me.AnalyzeControlFlow(SafeCastArgument(Of StatementSyntax)(statement, NameOf(statement)))
End Function
Private Shared Function SafeCastArgument(Of T As Class)(node As SyntaxNode, argName As String) As T
If node Is Nothing Then
Throw New ArgumentNullException(argName)
End If
Dim casted = TryCast(node, T)
If casted Is Nothing Then
Throw New ArgumentException(argName & " is not an " & GetType(T).Name)
End If
Return casted
End Function
Protected NotOverridable Overrides Function GetConstantValueCore(node As SyntaxNode, Optional cancellationToken As CancellationToken = Nothing) As [Optional](Of Object)
If node Is Nothing Then
Throw New ArgumentNullException(NameOf(node))
End If
If TypeOf node Is ExpressionSyntax Then
Return GetConstantValue(DirectCast(node, ExpressionSyntax), cancellationToken)
End If
Return Nothing
End Function
Protected NotOverridable Overrides Function GetEnclosingSymbolCore(position As Integer, Optional cancellationToken As System.Threading.CancellationToken = Nothing) As ISymbol
Return GetEnclosingSymbol(position, cancellationToken)
End Function
Private Protected NotOverridable Overrides Function GetImportScopesCore(position As Integer, cancellationToken As CancellationToken) As ImmutableArray(Of IImportScope)
CheckPosition(position)
Dim binder = Me.GetEnclosingBinder(position)
Dim importScopes = ArrayBuilder(Of IImportScope).GetInstance()
AddImportScopes(binder, importScopes)
Return importScopes.ToImmutableAndFree()
End Function
Private Shared Sub AddImportScopes(binder As Binder, scopes As ArrayBuilder(Of IImportScope))
' The binder chain has the following in it (walking from the innermost level outwards)
'
' 1. Optional binders for the compilation unit of the present source file.
' 2. SourceFileBinder. Required.
' 3. Optional binders for the imports brought in by the compilation options.
'
' Both '1' and '3' are the same binders. Specifically:
'
' a. XmlNamespaceImportsBinder. Optional. Present if source file has xml imports present.
' b. ImportAliasesBinder. Optional. Present if source file has import aliases present.
' c. TypesOfImportedNamespacesMembersBinder. Optional. Present if source file has type or namespace imports present.
'
' As such, we can walk upwards looking for any of these binders if present until we hit the end of the
' binder chain. We know which set we're in depending on if we've seen the SourceFileBinder or not.
'
' This also means that in VB the max length of the import chain is two, while in C# it can be unbounded
' in length.
Dim typesOfImportedNamespacesMembers As TypesOfImportedNamespacesMembersBinder = Nothing
Dim importAliases As ImportAliasesBinder = Nothing
Dim xmlNamespaceImports As XmlNamespaceImportsBinder = Nothing
While binder IsNot Nothing
If TypeOf binder Is SourceFileBinder Then
' We hit the source file binder. That means anything we found up till now were the imports for this
' file. Recurse and try to create the outer optional node, and then create a potential node for
' this level to chain onto that.
AddImportScopeNode(
typesOfImportedNamespacesMembers, importAliases, xmlNamespaceImports, scopes)
AddImportScopes(binder.ContainingBinder, scopes)
Return
End If
typesOfImportedNamespacesMembers = If(typesOfImportedNamespacesMembers, TryCast(binder, TypesOfImportedNamespacesMembersBinder))
importAliases = If(importAliases, TryCast(binder, ImportAliasesBinder))
xmlNamespaceImports = If(xmlNamespaceImports, TryCast(binder, XmlNamespaceImportsBinder))
binder = binder.ContainingBinder
End While
' We hit the end of the binder chain. Anything we found up till now are the compilation option imports
AddImportScopeNode(
typesOfImportedNamespacesMembers, importAliases, xmlNamespaceImports, scopes)
End Sub
Private Shared Sub AddImportScopeNode(
typesOfImportedNamespacesMembers As TypesOfImportedNamespacesMembersBinder,
importAliases As ImportAliasesBinder,
xmlNamespaceImports As XmlNamespaceImportsBinder,
scopes As ArrayBuilder(Of IImportScope))
Dim aliases = If(importAliases?.GetImportChainData(), ImmutableArray(Of IAliasSymbol).Empty)
Dim [imports] = If(typesOfImportedNamespacesMembers?.GetImportChainData(), ImmutableArray(Of ImportedNamespaceOrType).Empty)
Dim xmlNamespaces = If(xmlNamespaceImports?.GetImportChainData(), ImmutableArray(Of ImportedXmlNamespace).Empty)
If aliases.Length = 0 AndAlso [imports].Length = 0 AndAlso xmlNamespaces.Length = 0 Then
Return
End If
scopes.Add(New SimpleImportScope(aliases, ExternAliases:=ImmutableArray(Of IAliasSymbol).Empty, [imports], xmlNamespaces))
End Sub
Protected NotOverridable Overrides Function IsAccessibleCore(position As Integer, symbol As ISymbol) As Boolean
Return Me.IsAccessible(position, symbol.EnsureVbSymbolOrNothing(Of Symbol)(NameOf(symbol)))
End Function
Protected NotOverridable Overrides Function IsEventUsableAsFieldCore(position As Integer, symbol As IEventSymbol) As Boolean
Return False
End Function
Friend Overrides Sub ComputeDeclarationsInSpan(span As TextSpan, getSymbol As Boolean, builder As ArrayBuilder(Of DeclarationInfo), cancellationToken As CancellationToken)
VisualBasicDeclarationComputer.ComputeDeclarationsInSpan(Me, span, getSymbol, builder, cancellationToken)
End Sub
Friend Overrides Sub ComputeDeclarationsInNode(node As SyntaxNode, associatedSymbol As ISymbol, getSymbol As Boolean, builder As ArrayBuilder(Of DeclarationInfo), cancellationToken As CancellationToken, Optional levelsToCompute As Integer? = Nothing)
VisualBasicDeclarationComputer.ComputeDeclarationsInNode(Me, node, getSymbol, builder, cancellationToken)
End Sub
Protected Overrides Function GetTopmostNodeForDiagnosticAnalysis(symbol As ISymbol, declaringSyntax As SyntaxNode) As SyntaxNode
Select Case symbol.Kind
Case SymbolKind.Namespace
If TypeOf declaringSyntax Is NamespaceStatementSyntax Then
If declaringSyntax.Parent IsNot Nothing AndAlso TypeOf declaringSyntax.Parent Is NamespaceBlockSyntax Then
Return declaringSyntax.Parent
End If
End If
Case SymbolKind.NamedType
If TypeOf declaringSyntax Is TypeStatementSyntax Then
If declaringSyntax.Parent IsNot Nothing AndAlso TypeOf declaringSyntax.Parent Is TypeBlockSyntax Then
Return declaringSyntax.Parent
End If
ElseIf TypeOf declaringSyntax Is EnumStatementSyntax Then
If declaringSyntax.Parent IsNot Nothing AndAlso TypeOf declaringSyntax.Parent Is EnumBlockSyntax Then
Return declaringSyntax.Parent
End If
End If
Case SymbolKind.Method
If TypeOf declaringSyntax Is MethodBaseSyntax Then
If declaringSyntax.Parent IsNot Nothing AndAlso TypeOf declaringSyntax.Parent Is MethodBlockBaseSyntax Then
Return declaringSyntax.Parent
End If
End If
Case SymbolKind.Event
If TypeOf declaringSyntax Is EventStatementSyntax Then
If declaringSyntax.Parent IsNot Nothing AndAlso TypeOf declaringSyntax.Parent Is EventBlockSyntax Then
Return declaringSyntax.Parent
End If
End If
Case SymbolKind.Property
If TypeOf declaringSyntax Is PropertyStatementSyntax Then
If declaringSyntax.Parent IsNot Nothing AndAlso TypeOf declaringSyntax.Parent Is PropertyBlockSyntax Then
Return declaringSyntax.Parent
End If
End If
Case SymbolKind.Field
Dim fieldDecl = declaringSyntax.FirstAncestorOrSelf(Of FieldDeclarationSyntax)()
If fieldDecl IsNot Nothing Then
Return fieldDecl
End If
End Select
Return declaringSyntax
End Function
Public NotOverridable Overrides Function GetNullableContext(position As Integer) As NullableContext
Return NullableContext.Disabled Or NullableContext.ContextInherited
End Function
#End Region
#Region "Logging Helpers"
' Following helpers are used when logging ETW events. These helpers are invoked only if we are running
' under an ETW listener that has requested 'verbose' logging. In other words, these helpers will never
' be invoked in the 'normal' case (i.e. when the code is running on user's machine and no ETW listener
' is involved).
' Note: Most of the below helpers are unused at the moment - but we would like to keep them around in
' case we decide we need more verbose logging in certain cases for debugging.
Friend Function GetMessage(position As Integer) As String
Return String.Format("{0}: at {1}", Me.SyntaxTree.FilePath, position)
End Function
Friend Function GetMessage(node As VisualBasicSyntaxNode) As String
If node Is Nothing Then Return Me.SyntaxTree.FilePath
Return String.Format("{0}: {1} ({2})", Me.SyntaxTree.FilePath, node.Kind.ToString(), node.Position)
End Function
Friend Function GetMessage(node As VisualBasicSyntaxNode, position As Integer) As String
If node Is Nothing Then Return Me.SyntaxTree.FilePath
Return String.Format("{0}: {1} ({2}) at {3}", Me.SyntaxTree.FilePath, node.Kind.ToString(), node.Position, position)
End Function
Friend Function GetMessage(firstStatement As StatementSyntax, lastStatement As StatementSyntax) As String
If firstStatement Is Nothing OrElse lastStatement Is Nothing Then Return Me.SyntaxTree.FilePath
Return String.Format("{0}: {1} to {2}", Me.SyntaxTree.FilePath, firstStatement.Position, lastStatement.EndPosition)
End Function
Friend Function GetMessage(expression As ExpressionSyntax, type As TypeSymbol) As String
If expression Is Nothing OrElse type Is Nothing Then Return Me.SyntaxTree.FilePath
Return String.Format("{0}: {1} ({2}) -> {3} {4}", Me.SyntaxTree.FilePath, expression.Kind.ToString(), expression.Position, type.TypeKind.ToString(), type.Name)
End Function
Friend Function GetMessage(expression As ExpressionSyntax, type As TypeSymbol, position As Integer) As String
If expression Is Nothing OrElse type Is Nothing Then Return Me.SyntaxTree.FilePath
Return String.Format("{0}: {1} ({2}) -> {3} {4} at {5}", Me.SyntaxTree.FilePath, expression.Kind.ToString(), expression.Position, type.TypeKind.ToString(), type.Name, position)
End Function
Friend Function GetMessage(expression As ExpressionSyntax, [option] As SpeculativeBindingOption, position As Integer) As String
If expression Is Nothing Then Return Me.SyntaxTree.FilePath
Return String.Format("{0}: {1} ({2}) at {3} ({4})", Me.SyntaxTree.FilePath, expression.Kind.ToString(), expression.Position, position, [option].ToString())
End Function
Friend Function GetMessage(name As String, [option] As LookupOptions, position As Integer) As String
Return String.Format("{0}: {1} at {2} ({3})", Me.SyntaxTree.FilePath, name, position, [option].ToString())
End Function
Friend Function GetMessage(symbol As Symbol, position As Integer) As String
If symbol Is Nothing Then Return Me.SyntaxTree.FilePath
Return String.Format("{0}: {1} {2} at {3}", Me.SyntaxTree.FilePath, symbol.Kind.ToString(), symbol.Name, position)
End Function
Friend Function GetMessage(stage As CompilationStage) As String
Return String.Format("{0} ({1})", Me.SyntaxTree.FilePath, stage.ToString())
End Function
#End Region
End Class
End Namespace
|