File: Binding\InitializerSemanticModel.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 System.Collections.Immutable
Imports System.Runtime.InteropServices
Imports Microsoft.CodeAnalysis.PooledObjects
Imports Microsoft.CodeAnalysis.VisualBasic.Symbols
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
 
Namespace Microsoft.CodeAnalysis.VisualBasic
 
    Friend NotInheritable Class InitializerSemanticModel
        Inherits MemberSemanticModel
 
        Friend Sub New(root As VisualBasicSyntaxNode,
                        binder As Binder,
                        containingPublicSemanticModel As PublicSemanticModel)
            MyBase.New(root, binder, containingPublicSemanticModel)
        End Sub
 
        ''' <summary>
        ''' Creates an InitializerSemanticModel that allows asking semantic questions about an initializer node.
        ''' </summary>
        Friend Shared Function Create(containingSemanticModel As SyntaxTreeSemanticModel, binder As DeclarationInitializerBinder) As InitializerSemanticModel
            Debug.Assert(containingSemanticModel IsNot Nothing)
            Return New InitializerSemanticModel(binder.Root, binder, containingSemanticModel)
        End Function
 
        ''' <summary>
        ''' Creates a speculative semantic model that allows asking semantic questions about an initializer node that did not appear in the original source code.
        ''' </summary>
        Friend Shared Function CreateSpeculative(parentSemanticModel As SyntaxTreeSemanticModel, root As EqualsValueSyntax, binder As Binder, position As Integer) As SpeculativeSemanticModelWithMemberModel
            Return New SpeculativeSemanticModelWithMemberModel(parentSemanticModel, position, root, binder)
        End Function
 
        Friend Overrides Function Bind(binder As Binder, node As SyntaxNode, diagnostics As BindingDiagnosticBag) As BoundNode
            Debug.Assert(binder.IsSemanticModelBinder)
 
            Dim boundInitializer As BoundNode = Nothing
 
            Select Case node.Kind
                Case SyntaxKind.FieldDeclaration
                    '  get field symbol
                    If Me.MemberSymbol.Kind = SymbolKind.Field Then
                        Dim fieldSymbol = DirectCast(Me.MemberSymbol, SourceFieldSymbol)
                        boundInitializer = BindInitializer(binder, fieldSymbol.EqualsValueOrAsNewInitOpt, diagnostics)
                    Else
                        Dim propertySymbol = DirectCast(Me.MemberSymbol, SourcePropertySymbol)
                        Dim declSyntax As ModifiedIdentifierSyntax = DirectCast(propertySymbol.Syntax, ModifiedIdentifierSyntax)
                        Dim declarator = DirectCast(declSyntax.Parent, VariableDeclaratorSyntax)
 
                        Dim initSyntax As VisualBasicSyntaxNode = declarator.AsClause
                        If initSyntax Is Nothing OrElse initSyntax.Kind <> SyntaxKind.AsNewClause Then
                            initSyntax = declarator.Initializer
                        End If
 
                        boundInitializer = BindInitializer(binder, initSyntax, diagnostics)
                    End If
 
                Case SyntaxKind.PropertyStatement
                    '  get property symbol
                    Dim propertySymbol = DirectCast(Me.MemberSymbol, SourcePropertySymbol)
                    Dim declSyntax As PropertyStatementSyntax = DirectCast(propertySymbol.DeclarationSyntax, PropertyStatementSyntax)
                    Dim initSyntax As VisualBasicSyntaxNode = declSyntax.AsClause
                    If initSyntax Is Nothing OrElse initSyntax.Kind <> SyntaxKind.AsNewClause Then
                        initSyntax = declSyntax.Initializer
                    End If
 
                    boundInitializer = BindInitializer(binder, initSyntax, diagnostics)
                Case SyntaxKind.Parameter
                    Dim parameterSyntax = DirectCast(node, ParameterSyntax)
                    boundInitializer = BindInitializer(binder, parameterSyntax.Default, diagnostics)
 
                Case SyntaxKind.EnumMemberDeclaration
                    Dim enumSyntax = DirectCast(node, EnumMemberDeclarationSyntax)
                    boundInitializer = BindInitializer(binder, enumSyntax.Initializer, diagnostics)
 
                Case SyntaxKind.EqualsValue, SyntaxKind.AsNewClause
                    boundInitializer = BindInitializer(binder, node, diagnostics)
            End Select
 
            If boundInitializer IsNot Nothing Then
                Return boundInitializer
            Else
                Return MyBase.Bind(binder, node, diagnostics)
            End If
        End Function
 
        Private Iterator Function GetInitializedFieldsOrProperties(binder As Binder) As IEnumerable(Of Symbol)
            Yield Me.MemberSymbol
 
            For Each additionalSymbol In binder.AdditionalContainingMembers
                Yield additionalSymbol
            Next
        End Function
 
        Private Function BindInitializer(binder As Binder, initializer As SyntaxNode, diagnostics As BindingDiagnosticBag) As BoundNode
            Dim boundInitializer As BoundNode = Nothing
 
            Select Case Me.MemberSymbol.Kind
                Case SymbolKind.Field
                    '  try to get enum field symbol
                    Dim enumFieldSymbol = TryCast(Me.MemberSymbol, SourceEnumConstantSymbol)
                    If enumFieldSymbol IsNot Nothing Then
                        Debug.Assert(initializer IsNot Nothing)
                        If initializer.Kind = SyntaxKind.EqualsValue Then
                            Dim enumSymbol = DirectCast(Me.MemberSymbol, SourceEnumConstantSymbol)
                            boundInitializer = binder.BindFieldAndEnumConstantInitializer(enumSymbol, DirectCast(initializer, EqualsValueSyntax), isEnum:=True, diagnostics:=diagnostics, constValue:=Nothing)
                        End If
                    Else
                        '  get field symbol
                        Dim fieldSymbol = DirectCast(Me.MemberSymbol, SourceFieldSymbol)
                        Dim boundInitializers = ArrayBuilder(Of BoundInitializer).GetInstance
                        If initializer IsNot Nothing Then
                            ' bind const and non const field initializers the same to get a bound expression back and not a constant value.
                            Dim fields = ImmutableArray.CreateRange(GetInitializedFieldsOrProperties(binder).Cast(Of FieldSymbol))
                            binder.BindFieldInitializer(fields, initializer, boundInitializers, diagnostics, bindingForSemanticModel:=True)
                        Else
                            binder.BindArrayFieldImplicitInitializer(fieldSymbol, boundInitializers, diagnostics)
                        End If
 
                        boundInitializer = boundInitializers.First
                        boundInitializers.Free()
                    End If
 
                    Dim expressionInitializer = TryCast(boundInitializer, BoundExpression)
                    If expressionInitializer IsNot Nothing Then
                        Return New BoundFieldInitializer(initializer, ImmutableArray.Create(DirectCast(Me.MemberSymbol, FieldSymbol)), Nothing, expressionInitializer, binderOpt:=Nothing)
                    End If
 
                Case SymbolKind.Property
                    '  get property symbol
                    Dim propertySymbols = ImmutableArray.CreateRange(GetInitializedFieldsOrProperties(binder).Cast(Of PropertySymbol))
                    Dim boundInitializers = ArrayBuilder(Of BoundInitializer).GetInstance
                    binder.BindPropertyInitializer(propertySymbols, initializer, boundInitializers, diagnostics)
                    boundInitializer = boundInitializers.First
                    boundInitializers.Free()
 
                    Dim expressionInitializer = TryCast(boundInitializer, BoundExpression)
                    If expressionInitializer IsNot Nothing Then
                        Return New BoundPropertyInitializer(initializer, propertySymbols, Nothing, expressionInitializer, binderOpt:=Nothing)
                    End If
 
                Case SymbolKind.Parameter
                    Debug.Assert(initializer IsNot Nothing)
                    If initializer.Kind = SyntaxKind.EqualsValue Then
                        Dim parameterSymbol = DirectCast(Me.RootBinder.ContainingMember, SourceComplexParameterSymbol)
                        boundInitializer = binder.BindParameterDefaultValue(parameterSymbol.Type, DirectCast(initializer, EqualsValueSyntax), diagnostics, constValue:=Nothing)
 
                        Dim expressionInitializer = TryCast(boundInitializer, BoundExpression)
                        If expressionInitializer IsNot Nothing Then
                            Return New BoundParameterEqualsValue(initializer, parameterSymbol, expressionInitializer)
                        End If
                    End If
 
                Case Else
                    Throw ExceptionUtilities.UnexpectedValue(Me.MemberSymbol.Kind)
            End Select
 
            Return boundInitializer
        End Function
 
        Friend Overrides Function GetBoundRoot() As BoundNode
            ' In initializer the root bound node is sometimes not associated with Me.Root. Get the
            ' syntax that the root bound node should be associated with.
            Dim rootSyntax = Me.Root
 
            If rootSyntax.Kind = SyntaxKind.FieldDeclaration Then
                Dim fieldSymbol = TryCast(Me.RootBinder.ContainingMember, SourceFieldSymbol)
                If fieldSymbol IsNot Nothing Then
                    rootSyntax = If(fieldSymbol.EqualsValueOrAsNewInitOpt, fieldSymbol.Syntax)
                Else
                    ' 'WithEvents x As Y = ...'
                    Dim propertySymbol = TryCast(Me.RootBinder.ContainingMember, SourcePropertySymbol)
                    Debug.Assert(rootSyntax Is propertySymbol.DeclarationSyntax)
 
                    Dim propertyNameId = DirectCast(propertySymbol.Syntax, ModifiedIdentifierSyntax) ' serves as an assert
                    Dim declarator = DirectCast(propertyNameId.Parent, VariableDeclaratorSyntax) ' serves as an assert
 
                    Dim initSyntax As VisualBasicSyntaxNode = declarator.AsClause
                    If initSyntax Is Nothing OrElse initSyntax.Kind <> SyntaxKind.AsNewClause Then
                        initSyntax = declarator.Initializer
                    End If
                    If initSyntax IsNot Nothing Then
                        rootSyntax = initSyntax
                    End If
                End If
            ElseIf rootSyntax.Kind = SyntaxKind.PropertyStatement Then
                Dim declSyntax As PropertyStatementSyntax = DirectCast(rootSyntax, PropertyStatementSyntax)
                Dim initSyntax As VisualBasicSyntaxNode = declSyntax.AsClause
                If initSyntax Is Nothing OrElse initSyntax.Kind <> SyntaxKind.AsNewClause Then
                    initSyntax = declSyntax.Initializer
                End If
                If initSyntax IsNot Nothing Then
                    rootSyntax = initSyntax
                End If
            End If
 
            'TODO - Do parameters need to do anything here?
 
            Return GetUpperBoundNode(rootSyntax)
        End Function
 
        Friend Overrides Function TryGetSpeculativeSemanticModelCore(parentModel As SyntaxTreeSemanticModel, position As Integer, initializer As EqualsValueSyntax, <Out> ByRef speculativeModel As PublicSemanticModel) As Boolean
            Dim binder = Me.GetEnclosingBinder(position)
            If binder Is Nothing Then
                speculativeModel = Nothing
                Return False
            End If
 
            ' wrap the binder with a Speculative binder
            binder = SpeculativeBinder.Create(binder)
 
            speculativeModel = CreateSpeculative(parentModel, initializer, binder, position)
            Return True
        End Function
 
        Friend Overrides Function TryGetSpeculativeSemanticModelCore(parentModel As SyntaxTreeSemanticModel, position As Integer, statement As ExecutableStatementSyntax, <Out> ByRef speculativeModel As PublicSemanticModel) As Boolean
            speculativeModel = Nothing
            Return False
        End Function
 
        Friend Overrides Function TryGetSpeculativeSemanticModelForMethodBodyCore(parentModel As SyntaxTreeSemanticModel, position As Integer, body As MethodBlockBaseSyntax, <Out> ByRef speculativeModel As PublicSemanticModel) As Boolean
            speculativeModel = Nothing
            Return False
        End Function
    End Class
 
End Namespace