File: Binding\BinderFactory.BinderFactoryVisitor.vb
Web Access
Project: src\src\Compilers\VisualBasic\Portable\Microsoft.CodeAnalysis.VisualBasic.vbproj (Microsoft.CodeAnalysis.VisualBasic)
' 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 Microsoft.CodeAnalysis.VisualBasic.Syntax
 
Namespace Microsoft.CodeAnalysis.VisualBasic
    Partial Friend Class BinderFactory
 
        Friend NotInheritable Class BinderFactoryVisitor
            Inherits VisualBasicSyntaxVisitor(Of Binder)
 
            Private _position As Integer
            Private _factory As BinderFactory
 
            Public Sub Initialize(factory As BinderFactory, position As Integer)
                Me._factory = factory
                Me._position = position
            End Sub
 
            Public Sub Clear()
                _factory = Nothing
                _position = 0
            End Sub
 
            Public Overrides Function VisitXmlCrefAttribute(node As XmlCrefAttributeSyntax) As Binder
                Dim trivia As StructuredTriviaSyntax = node.EnclosingStructuredTrivia
 
                If trivia IsNot Nothing AndAlso trivia.Kind = SyntaxKind.DocumentationCommentTrivia Then
                    Return _factory.CreateDocumentationCommentBinder(DirectCast(trivia, DocumentationCommentTriviaSyntax), DocumentationCommentBinder.BinderType.Cref)
                End If
 
                Return MyBase.VisitXmlCrefAttribute(node)
            End Function
 
            Public Overrides Function VisitXmlNameAttribute(node As XmlNameAttributeSyntax) As Binder
                Dim trivia As StructuredTriviaSyntax = node.EnclosingStructuredTrivia
 
                If trivia IsNot Nothing AndAlso trivia.Kind = SyntaxKind.DocumentationCommentTrivia Then
                    Dim binderType As DocumentationCommentBinder.BinderType =
                        DocumentationCommentBinder.GetBinderTypeForNameAttribute(node)
                    If binderType <> DocumentationCommentBinder.BinderType.None Then
                        Return _factory.CreateDocumentationCommentBinder(DirectCast(trivia, DocumentationCommentTriviaSyntax), binderType)
                    End If
                End If
 
                Return MyBase.VisitXmlNameAttribute(node)
            End Function
 
            Public Overrides Function VisitXmlAttribute(node As XmlAttributeSyntax) As Binder
                If node.Name.Kind = SyntaxKind.XmlName Then
                    Dim attrName = DirectCast(node.Name, XmlNameSyntax).LocalName.ValueText
 
                    If DocumentationCommentXmlNames.AttributeEquals(attrName, DocumentationCommentXmlNames.CrefAttributeName) Then
                        Dim trivia As StructuredTriviaSyntax = node.EnclosingStructuredTrivia
                        If trivia IsNot Nothing AndAlso trivia.Kind = SyntaxKind.DocumentationCommentTrivia Then
                            Return _factory.CreateDocumentationCommentBinder(DirectCast(trivia, DocumentationCommentTriviaSyntax), DocumentationCommentBinder.BinderType.Cref)
                        End If
 
                    ElseIf DocumentationCommentXmlNames.AttributeEquals(attrName, DocumentationCommentXmlNames.NameAttributeName) Then
                        Dim trivia As StructuredTriviaSyntax = node.EnclosingStructuredTrivia
                        If trivia IsNot Nothing AndAlso trivia.Kind = SyntaxKind.DocumentationCommentTrivia Then
                            Dim binderType As DocumentationCommentBinder.BinderType =
                                DocumentationCommentBinder.GetBinderTypeForNameAttribute(node)
                            If binderType <> DocumentationCommentBinder.BinderType.None Then
                                Return _factory.CreateDocumentationCommentBinder(DirectCast(trivia, DocumentationCommentTriviaSyntax), binderType)
                            End If
                        End If
                    End If
                End If
 
                Return MyBase.VisitXmlAttribute(node)
            End Function
 
            ' Visitors for different kinds of nodes.
 
            Private Function VisitMethodBaseDeclaration(methodBaseSyntax As MethodBaseSyntax) As Binder
                Dim possibleParentBlock = TryCast(methodBaseSyntax.Parent, MethodBlockBaseSyntax)
                Dim parentForEnclosingBinder As VisualBasicSyntaxNode = If(possibleParentBlock IsNot Nothing, possibleParentBlock.Parent, methodBaseSyntax.Parent)
 
                Return GetBinderForNodeAndUsage(methodBaseSyntax, NodeUsage.MethodFull, parentForEnclosingBinder, _position)
            End Function
 
            Public Overrides Function DefaultVisit(node As SyntaxNode) As Binder
                If _factory.InScript AndAlso node.Parent.Kind = SyntaxKind.CompilationUnit Then
                    ' Use CompilationUnitSyntax as a key to the cache for all statements to get a single shared instance of TopLeveCodeBinder
                    Return GetBinderForNodeAndUsage(DirectCast(node.Parent, VisualBasicSyntaxNode), NodeUsage.TopLevelExecutableStatement, DirectCast(node.Parent, VisualBasicSyntaxNode), _position)
                End If
 
                Return Nothing
            End Function
 
            Public Overrides Function VisitCompilationUnit(node As CompilationUnitSyntax) As Binder
                Return GetBinderForNodeAndUsage(node, If(_factory.InScript, NodeUsage.ScriptCompilationUnit, NodeUsage.CompilationUnit))
            End Function
 
            Public Overrides Function VisitNamespaceBlock(nsBlockSyntax As NamespaceBlockSyntax) As Binder
                ' The binder should be used only within the interior of the namespace block. The interior is from
                ' the end of Begin to the beginning of End (unless End is missing)
                If SyntaxFacts.InBlockInterior(nsBlockSyntax, _position) Then
                    Return GetBinderForNodeAndUsage(nsBlockSyntax, NodeUsage.NamespaceBlockInterior, nsBlockSyntax.Parent, _position)
                Else
                    Return Nothing
                End If
            End Function
 
            Public Overrides Function VisitEnumMemberDeclaration(node As EnumMemberDeclarationSyntax) As Binder
                If IsNotNothingAndContains(node.Initializer, _position) Then
                    Return GetBinderForNodeAndUsage(node, NodeUsage.FieldOrPropertyInitializer, node.Parent, _position)
                Else
                    Return Nothing
                End If
            End Function
 
            Public Overrides Function VisitVariableDeclarator(node As VariableDeclaratorSyntax) As Binder
                If IsNotNothingAndContains(node.Initializer, _position) OrElse IsNotNothingAndContains(TryCast(node.AsClause, AsNewClauseSyntax), _position) Then
                    Return GetBinderForNodeAndUsage(node, NodeUsage.FieldOrPropertyInitializer, node.Parent, _position)
                End If
 
                For Each name In node.Names
                    If IsNotNothingAndContains(name.ArrayBounds, _position) Then
                        Return GetBinderForNodeAndUsage(name, NodeUsage.FieldArrayBounds, node.Parent, _position)
                    End If
                Next
 
                Return Nothing
            End Function
 
            Public Overrides Function VisitPropertyStatement(node As PropertyStatementSyntax) As Binder
                If IsNotNothingAndContains(node.Initializer, _position) OrElse IsNotNothingAndContains(TryCast(node.AsClause, AsNewClauseSyntax), _position) Then
                    Return GetBinderForNodeAndUsage(node, NodeUsage.FieldOrPropertyInitializer, node.Parent, _position)
                Else
                    Return Nothing
                End If
            End Function
 
            Public Overrides Function VisitModuleBlock(ByVal moduleSyntax As ModuleBlockSyntax) As Binder
                Return GetBinderForNodeAndUsage(moduleSyntax.BlockStatement, NodeUsage.TypeBlockFull, moduleSyntax.Parent, _position)
            End Function
 
            Public Overrides Function VisitClassBlock(ByVal classSyntax As ClassBlockSyntax) As Binder
                Return GetBinderForNodeAndUsage(classSyntax.BlockStatement, NodeUsage.TypeBlockFull, classSyntax.Parent, _position)
            End Function
 
            Public Overrides Function VisitStructureBlock(ByVal structureSyntax As StructureBlockSyntax) As Binder
                Return GetBinderForNodeAndUsage(structureSyntax.BlockStatement, NodeUsage.TypeBlockFull, structureSyntax.Parent, _position)
            End Function
 
            Public Overrides Function VisitAttribute(node As AttributeSyntax) As Binder
                Return GetBinderForNodeAndUsage(node, NodeUsage.Attribute, node.Parent, _position)
            End Function
 
            Public Overrides Function VisitInterfaceBlock(ByVal interfaceSyntax As InterfaceBlockSyntax) As Binder
                Return GetBinderForNodeAndUsage(interfaceSyntax.BlockStatement, NodeUsage.TypeBlockFull, interfaceSyntax.Parent, _position)
            End Function
 
            Public Overrides Function VisitEnumBlock(enumBlockSyntax As EnumBlockSyntax) As Binder
                Return GetBinderForNodeAndUsage(enumBlockSyntax.EnumStatement, NodeUsage.EnumBlockFull, enumBlockSyntax.Parent, _position)
            End Function
 
            Public Overrides Function VisitDelegateStatement(delegateSyntax As DelegateStatementSyntax) As Binder
                Return GetBinderForNodeAndUsage(delegateSyntax, NodeUsage.DelegateDeclaration, delegateSyntax.Parent, _position)
            End Function
 
            Public Overrides Function VisitInheritsStatement(inheritsSyntax As InheritsStatementSyntax) As Binder
                Return GetBinderForNodeAndUsage(inheritsSyntax, NodeUsage.InheritsStatement, inheritsSyntax.Parent, _position)
            End Function
 
            Public Overrides Function VisitImplementsStatement(implementsSyntax As ImplementsStatementSyntax) As Binder
                Return GetBinderForNodeAndUsage(implementsSyntax, NodeUsage.ImplementsStatement, implementsSyntax.Parent, _position)
            End Function
 
            ' All of these kinds of syntax nodes declare method symbols.
 
            Public Overrides Function VisitMethodStatement(node As MethodStatementSyntax) As Binder
                ' We might get here for an error scenario when 'Sub' or 'Function' keyword starts the body of a single-line statement lambda.
                ' We should not be treating it as a valid method declaration.
                If node.ContainsDiagnostics AndAlso node.Parent.Kind = SyntaxKind.SingleLineSubLambdaExpression Then
                    Return DefaultVisit(node)
                End If
 
                Return VisitMethodBaseDeclaration(node)
            End Function
 
            Public Overrides Function VisitSubNewStatement(node As SubNewStatementSyntax) As Binder
                Return VisitMethodBaseDeclaration(node)
            End Function
 
            Public Overrides Function VisitOperatorStatement(node As OperatorStatementSyntax) As Binder
                Return VisitMethodBaseDeclaration(node)
            End Function
 
            Public Overrides Function VisitDeclareStatement(node As DeclareStatementSyntax) As Binder
                Return VisitMethodBaseDeclaration(node)
            End Function
 
            Public Overrides Function VisitAccessorStatement(node As AccessorStatementSyntax) As Binder
                Return VisitMethodBaseDeclaration(node)
            End Function
 
            Public Overrides Function VisitParameter(node As ParameterSyntax) As Binder
                If IsNotNothingAndContains(node.Default, _position) Then
                    Return GetBinderForNodeAndUsage(node, NodeUsage.ParameterDefaultValue, node.Parent, _position)
                End If
                Return Nothing
            End Function
 
            Private Function VisitMethodBlockBase(methodBlockSyntax As MethodBlockBaseSyntax, begin As MethodBaseSyntax) As Binder
                Dim usage As NodeUsage
                If SyntaxFacts.InBlockInterior(methodBlockSyntax, _position) Then
                    ' We're in the interior from end of Begin to the beginning of End (unless the End is missing...)
                    usage = NodeUsage.MethodInterior
                Else
                    usage = NodeUsage.MethodFull
                End If
 
                Return GetBinderForNodeAndUsage(begin, usage, methodBlockSyntax.Parent, _position)
            End Function
 
            Public Overrides Function VisitMethodBlock(node As MethodBlockSyntax) As Binder
                Return VisitMethodBlockBase(node, node.BlockStatement)
            End Function
 
            Public Overrides Function VisitConstructorBlock(node As ConstructorBlockSyntax) As Binder
                Return VisitMethodBlockBase(node, node.BlockStatement)
            End Function
 
            Public Overrides Function VisitOperatorBlock(node As OperatorBlockSyntax) As Binder
                Return VisitMethodBlockBase(node, node.BlockStatement)
            End Function
 
            Public Overrides Function VisitAccessorBlock(node As AccessorBlockSyntax) As Binder
                Return VisitMethodBlockBase(node, node.BlockStatement)
            End Function
 
            Public Overrides Function VisitPropertyBlock(node As PropertyBlockSyntax) As Binder
                Return GetBinderForNodeAndUsage(node.PropertyStatement, NodeUsage.PropertyFull, node.Parent, _position)
            End Function
 
            Public Overrides Function VisitImportsStatement(node As ImportsStatementSyntax) As Binder
                Return BinderBuilder.CreateBinderForSourceFileImports(_factory._sourceModule, _factory._tree)
            End Function
 
            ' Given a node and usage, find the correct binder to use. Use the cache first, if not in the cache, then
            ' create a new binder. The parent node and position are used if we need to find an enclosing binder unless specified explicitly.
            Private Function GetBinderForNodeAndUsage(node As VisualBasicSyntaxNode,
                                                      usage As NodeUsage,
                                                      Optional parentNode As VisualBasicSyntaxNode = Nothing,
                                                      Optional position As Integer = -1
                                                      ) As Binder
 
                Return _factory.GetBinderForNodeAndUsage(node, usage, parentNode, position)
            End Function
 
            Private Shared Function IsNotNothingAndContains(nodeOpt As VisualBasicSyntaxNode, position As Integer) As Boolean
                Return (nodeOpt IsNot Nothing) AndAlso SyntaxFacts.InSpanOrEffectiveTrailingOfNode(nodeOpt, position)
            End Function
        End Class
 
    End Class
 
End Namespace