File: Symbols\Source\SourceComplexParameterSymbol.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.Threading
Imports Microsoft.CodeAnalysis.Text
Imports Microsoft.CodeAnalysis.VisualBasic.Binder
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
 
Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
    ''' <summary>
    ''' Represents a parameter symbol defined in source.
    ''' </summary>
    Friend Class SourceComplexParameterSymbol
        Inherits SourceParameterSymbol
 
        Private ReadOnly _syntaxRef As SyntaxReference
        Private ReadOnly _flags As SourceParameterFlags
 
        ' m_lazyDefaultValue is not readonly because it is lazily computed
        Private _lazyDefaultValue As ConstantValue
        Private _lazyCustomAttributesBag As CustomAttributesBag(Of VisualBasicAttributeData)
 
#If DEBUG Then
        Friend Sub AssertAttributesNotValidatedYet()
            Debug.Assert(_lazyCustomAttributesBag Is Nothing)
        End Sub
#End If
        ''' <summary>
        ''' Symbol to copy bound attributes from, or null if the attributes are not shared among multiple source method symbols.
        ''' </summary>
        ''' <remarks>
        ''' Used for partial method parameters: 
        ''' Implementation parameter always copies its attributes from the corresponding definition parameter.
        ''' Definition is always complex parameter and so it stores the attribute bag.
        ''' </remarks>
        Private ReadOnly Property BoundAttributesSource As SourceParameterSymbol
            Get
                Dim sourceMethod = TryCast(Me.ContainingSymbol, SourceMemberMethodSymbol)
                If sourceMethod Is Nothing Then
                    Return Nothing
                End If
 
                Dim impl = sourceMethod.SourcePartialDefinition
                If impl Is Nothing Then
                    Return Nothing
                End If
 
                Return DirectCast(impl.Parameters(Me.Ordinal), SourceParameterSymbol)
            End Get
        End Property
 
        Friend Overrides ReadOnly Property AttributeDeclarationList As SyntaxList(Of AttributeListSyntax)
            Get
                Return If(Me._syntaxRef Is Nothing, Nothing,
                          DirectCast(Me._syntaxRef.GetSyntax, ParameterSyntax).AttributeLists())
            End Get
        End Property
 
        Private Function GetAttributeDeclarations() As OneOrMany(Of SyntaxList(Of AttributeListSyntax))
            Dim attributes = AttributeDeclarationList
 
            Dim sourceMethod = TryCast(Me.ContainingSymbol, SourceMemberMethodSymbol)
            If sourceMethod Is Nothing Then
                Return OneOrMany.Create(attributes)
            End If
 
            Dim otherAttributes As SyntaxList(Of AttributeListSyntax)
 
            ' combine attributes with the corresponding parameter of a partial implementation:
            Dim otherPart As SourceMemberMethodSymbol = sourceMethod.SourcePartialImplementation
            If otherPart IsNot Nothing Then
                otherAttributes = DirectCast(otherPart.Parameters(Me.Ordinal), SourceParameterSymbol).AttributeDeclarationList
            Else
                otherAttributes = Nothing
            End If
 
            If attributes.Equals(Nothing) Then
                Return OneOrMany.Create(otherAttributes)
            ElseIf otherAttributes.Equals(Nothing) Then
                Return OneOrMany.Create(attributes)
            Else
                Return OneOrMany.Create(ImmutableArray.Create(attributes, otherAttributes))
            End If
        End Function
 
        Friend Overrides Function GetAttributesBag() As CustomAttributesBag(Of VisualBasicAttributeData)
            If _lazyCustomAttributesBag Is Nothing OrElse Not _lazyCustomAttributesBag.IsSealed Then
 
                Dim copyFrom As SourceParameterSymbol = Me.BoundAttributesSource
 
                ' prevent infinite recursion:
                Debug.Assert(copyFrom IsNot Me)
 
                If copyFrom IsNot Nothing Then
                    Dim attributesBag = copyFrom.GetAttributesBag()
                    Interlocked.CompareExchange(_lazyCustomAttributesBag, attributesBag, Nothing)
                Else
                    Dim attributeSyntax = Me.GetAttributeDeclarations()
                    LoadAndValidateAttributes(attributeSyntax, _lazyCustomAttributesBag)
                End If
            End If
 
            Return _lazyCustomAttributesBag
        End Function
 
        Friend Overrides Function GetEarlyDecodedWellKnownAttributeData() As ParameterEarlyWellKnownAttributeData
            Dim attributesBag As CustomAttributesBag(Of VisualBasicAttributeData) = Me._lazyCustomAttributesBag
            If attributesBag Is Nothing OrElse Not attributesBag.IsEarlyDecodedWellKnownAttributeDataComputed Then
                attributesBag = Me.GetAttributesBag()
            End If
 
            Return DirectCast(attributesBag.EarlyDecodedWellKnownAttributeData, ParameterEarlyWellKnownAttributeData)
        End Function
 
        Friend Overrides Function GetDecodedWellKnownAttributeData() As CommonParameterWellKnownAttributeData
            Dim attributesBag As CustomAttributesBag(Of VisualBasicAttributeData) = Me._lazyCustomAttributesBag
            If attributesBag Is Nothing OrElse Not attributesBag.IsDecodedWellKnownAttributeDataComputed Then
                attributesBag = Me.GetAttributesBag()
            End If
 
            Return DirectCast(attributesBag.DecodedWellKnownAttributeData, CommonParameterWellKnownAttributeData)
        End Function
 
        Public Overrides ReadOnly Property HasExplicitDefaultValue As Boolean
            Get
                Return ExplicitDefaultConstantValue(SymbolsInProgress(Of ParameterSymbol).Empty) IsNot Nothing
            End Get
        End Property
 
        Friend Overrides ReadOnly Property ExplicitDefaultConstantValue(inProgress As SymbolsInProgress(Of ParameterSymbol)) As ConstantValue
            Get
                If _lazyDefaultValue Is ConstantValue.Unset Then
                    Dim diagnostics = BindingDiagnosticBag.GetInstance()
                    If Interlocked.CompareExchange(_lazyDefaultValue, BindDefaultValue(inProgress, diagnostics), ConstantValue.Unset) Is ConstantValue.Unset Then
                        DirectCast(ContainingModule, SourceModuleSymbol).AddDeclarationDiagnostics(diagnostics)
                    End If
                    diagnostics.Free()
                End If
 
                Return _lazyDefaultValue
            End Get
        End Property
 
        Private Function BindDefaultValue(inProgress As SymbolsInProgress(Of ParameterSymbol), diagnostics As BindingDiagnosticBag) As ConstantValue
 
            Dim parameterSyntax = SyntaxNode
            If parameterSyntax Is Nothing Then
                Return Nothing
            End If
 
            Dim defaultSyntax = parameterSyntax.[Default]
            If defaultSyntax Is Nothing Then
                Return Nothing
            End If
 
            Dim binder As Binder = BinderBuilder.CreateBinderForParameterDefaultValue(DirectCast(ContainingModule, SourceModuleSymbol),
                                                                                      _syntaxRef.SyntaxTree,
                                                                                      Me,
                                                                                      parameterSyntax)
 
            ' Before binding the default value, check if we are already in the process of binding it. If so report
            ' an error and return nothing.
            If inProgress.Contains(Me) Then
                Binder.ReportDiagnostic(diagnostics, defaultSyntax.Value, ERRID.ERR_CircularEvaluation1, Me)
                Return Nothing
            End If
 
            Dim inProgressBinder = New DefaultParametersInProgressBinder(inProgress.Add(Me), binder)
 
            Dim constValue As ConstantValue = Nothing
            inProgressBinder.BindParameterDefaultValue(Me.Type, defaultSyntax, diagnostics, constValue:=constValue)
 
            If constValue IsNot Nothing Then
                VerifyParamDefaultValueMatchesAttributeIfAny(constValue, defaultSyntax.Value, diagnostics)
            End If
 
            Return constValue
        End Function
 
        Friend ReadOnly Property SyntaxNode As ParameterSyntax
            Get
                Return If(_syntaxRef Is Nothing, Nothing, DirectCast(_syntaxRef.GetSyntax(), ParameterSyntax))
            End Get
        End Property
 
        Public Overrides ReadOnly Property DeclaringSyntaxReferences As ImmutableArray(Of SyntaxReference)
            Get
                If IsImplicitlyDeclared Then
                    Return ImmutableArray(Of SyntaxReference).Empty
                ElseIf _syntaxRef IsNot Nothing Then
                    Return GetDeclaringSyntaxReferenceHelper(_syntaxRef)
                Else
                    Return MyBase.DeclaringSyntaxReferences
                End If
            End Get
        End Property
 
        Friend NotOverridable Overrides Function IsDefinedInSourceTree(tree As SyntaxTree, definedWithinSpan As TextSpan?, Optional cancellationToken As CancellationToken = Nothing) As Boolean
            Return IsDefinedInSourceTree(Me.SyntaxNode, tree, definedWithinSpan, cancellationToken)
        End Function
 
        Public Overrides ReadOnly Property IsOptional As Boolean
            Get
                Return (_flags And SourceParameterFlags.Optional) <> 0
            End Get
        End Property
 
        Public Overrides ReadOnly Property IsParamArray As Boolean
            Get
                If (_flags And SourceParameterFlags.ParamArray) <> 0 Then
                    Return True
                End If
 
                Dim attributeSource As SourceParameterSymbol = If(Me.BoundAttributesSource, Me)
 
                Dim data = attributeSource.GetEarlyDecodedWellKnownAttributeData()
                Return data IsNot Nothing AndAlso data.HasParamArrayAttribute
            End Get
        End Property
 
        Friend Overrides ReadOnly Property IsCallerLineNumber As Boolean
            Get
                Dim attributeSource As SourceParameterSymbol = If(Me.BoundAttributesSource, Me)
 
                Dim data = attributeSource.GetEarlyDecodedWellKnownAttributeData()
                Return data IsNot Nothing AndAlso data.HasCallerLineNumberAttribute
            End Get
        End Property
 
        Friend Overrides ReadOnly Property IsCallerMemberName As Boolean
            Get
                Dim attributeSource As SourceParameterSymbol = If(Me.BoundAttributesSource, Me)
 
                Dim data = attributeSource.GetEarlyDecodedWellKnownAttributeData()
                Return data IsNot Nothing AndAlso data.HasCallerMemberNameAttribute
            End Get
        End Property
 
        Friend Overrides ReadOnly Property IsCallerFilePath As Boolean
            Get
                Dim attributeSource As SourceParameterSymbol = If(Me.BoundAttributesSource, Me)
 
                Dim data = attributeSource.GetEarlyDecodedWellKnownAttributeData()
                Return data IsNot Nothing AndAlso data.HasCallerFilePathAttribute
            End Get
        End Property
 
        Friend Overrides ReadOnly Property CallerArgumentExpressionParameterIndex As Integer
            Get
                Dim attributeSource As SourceParameterSymbol = If(Me.BoundAttributesSource, Me)
 
                Dim data = attributeSource.GetEarlyDecodedWellKnownAttributeData()
                If data Is Nothing Then
                    Return -1
                End If
 
                Return data.CallerArgumentExpressionParameterIndex
            End Get
        End Property
 
        ''' <summary>
        ''' Is parameter explicitly declared ByRef. Can be different from IsByRef only for
        ''' String parameters of Declare methods.
        ''' </summary>
        Friend Overrides ReadOnly Property IsExplicitByRef As Boolean
            Get
                Return (_flags And SourceParameterFlags.ByRef) <> 0
            End Get
        End Property
 
        Private Sub New(
            container As Symbol,
            name As String,
            ordinal As Integer,
            type As TypeSymbol,
            location As Location,
            syntaxRef As SyntaxReference,
            flags As SourceParameterFlags,
            defaultValueOpt As ConstantValue
        )
            MyBase.New(container, name, ordinal, type, location)
            _flags = flags
            _lazyDefaultValue = defaultValueOpt
            _syntaxRef = syntaxRef
        End Sub
 
        ' Create a simple or complex parameter, as necessary.
        Friend Shared Function Create(container As Symbol,
                                 name As String,
                                 ordinal As Integer,
                                 type As TypeSymbol,
                                 location As Location,
                                 syntaxRef As SyntaxReference,
                                 flags As SourceParameterFlags,
                                 defaultValueOpt As ConstantValue) As ParameterSymbol
 
            ' Note that parameters of partial method declarations should always be complex
            Dim method = TryCast(container, SourceMethodSymbol)
 
            If flags <> 0 OrElse
                defaultValueOpt IsNot Nothing OrElse
                syntaxRef IsNot Nothing OrElse
                (method IsNot Nothing AndAlso method.IsPartial) Then
 
                Return New SourceComplexParameterSymbol(container, name, ordinal, type, location, syntaxRef, flags, defaultValueOpt)
            Else
                Return New SourceSimpleParameterSymbol(container, name, ordinal, type, location)
            End If
        End Function
 
        Friend Overrides Function ChangeOwner(newContainingSymbol As Symbol) As ParameterSymbol
            ' When changing the owner, it is not safe to get the constant value from this parameter symbol (Me.DefaultConstantValue). Default values for source
            ' parameters are computed after all members have been added to the  type. See GenerateAllDeclarationErrors in SourceNamedTypeSymbol.
            ' Asking for the default value earlier than that can lead to infinite recursion. Instead, pass in the m_lazyDefaultValue.  If the value hasn't
            ' been computed yet, the new symbol will compute it.
 
            Return New SourceComplexParameterSymbol(newContainingSymbol, Me.Name, Me.Ordinal, Me.Type, Me.Locations(0), _syntaxRef, _flags, _lazyDefaultValue)
        End Function
 
        ' Create a parameter from syntax.
        Friend Shared Function CreateFromSyntax(container As Symbol,
                                                syntax As ParameterSyntax,
                                                name As String,
                                                flags As SourceParameterFlags,
                                                ordinal As Integer,
                                                binder As Binder,
                                                checkModifier As CheckParameterModifierDelegate,
                                                diagnostics As BindingDiagnosticBag) As ParameterSymbol
            Dim getErrorInfo As Func(Of DiagnosticInfo) = Nothing
 
            If binder.OptionStrict = OptionStrict.On Then
                getErrorInfo = ErrorFactory.GetErrorInfo_ERR_StrictDisallowsImplicitArgs
            ElseIf binder.OptionStrict = OptionStrict.Custom Then
                getErrorInfo = ErrorFactory.GetErrorInfo_WRN_ObjectAssumedVar1_WRN_MissingAsClauseinVarDecl
            End If
 
            Dim paramType = binder.DecodeModifiedIdentifierType(syntax.Identifier, syntax.AsClause, Nothing, getErrorInfo, diagnostics, ModifiedIdentifierTypeDecoderContext.ParameterType)
 
            If (flags And SourceParameterFlags.ParamArray) <> 0 AndAlso paramType.TypeKind <> TypeKind.Error Then
                If paramType.TypeKind <> TypeKind.Array Then
                    ' ParamArray must be of array type.
                    Binder.ReportDiagnostic(diagnostics, syntax.Identifier, ERRID.ERR_ParamArrayNotArray)
                Else
                    Dim paramTypeAsArray = DirectCast(paramType, ArrayTypeSymbol)
                    If Not paramTypeAsArray.IsSZArray Then
                        ' ParamArray type must be rank-1 array.
                        Binder.ReportDiagnostic(diagnostics, syntax.Identifier.Identifier, ERRID.ERR_ParamArrayRank)
                    End If
 
                    ' 'touch' the constructor in order to generate proper diagnostics
                    binder.ReportUseSiteInfoForSynthesizedAttribute(WellKnownMember.System_ParamArrayAttribute__ctor,
                                                                     syntax,
                                                                     diagnostics)
                End If
            End If
 
            Dim syntaxRef As SyntaxReference = Nothing
 
            ' Attributes and default values are computed lazily and need access to the parameter's syntax.
            ' If the parameter syntax includes either of these get a syntax reference and pass it to the parameter symbol.
            If (syntax.AttributeLists.Count <> 0 OrElse syntax.Default IsNot Nothing) Then
                syntaxRef = binder.GetSyntaxReference(syntax)
            End If
 
            Dim defaultValue As ConstantValue = Nothing
 
            If (flags And SourceParameterFlags.Optional) <> 0 Then
                ' The default value is computed lazily. If there is default syntax then set the value to ConstantValue.unset to indicate the value needs to
                ' be computed.
                If syntax.Default IsNot Nothing Then
                    defaultValue = ConstantValue.Unset
                End If
 
                ' Report diagnostic if constructors for datetime and decimal default values are not available
                Select Case paramType.SpecialType
                    Case SpecialType.System_DateTime
                        binder.ReportUseSiteInfoForSynthesizedAttribute(WellKnownMember.System_Runtime_CompilerServices_DateTimeConstantAttribute__ctor,
                                                                         syntax.Default,
                                                                         diagnostics)
 
                    Case SpecialType.System_Decimal
                        binder.ReportUseSiteInfoForSynthesizedAttribute(WellKnownMember.System_Runtime_CompilerServices_DecimalConstantAttribute__ctor,
                                                                        syntax.Default,
                                                                        diagnostics)
                End Select
            End If
 
            Return Create(container, name, ordinal, paramType, syntax.Identifier.Identifier.GetLocation(), syntaxRef, flags, defaultValue)
        End Function
 
        Public Overrides ReadOnly Property CustomModifiers As ImmutableArray(Of CustomModifier)
            Get
                Return ImmutableArray(Of CustomModifier).Empty
            End Get
        End Property
 
        Public Overrides ReadOnly Property RefCustomModifiers As ImmutableArray(Of CustomModifier)
            Get
                Return ImmutableArray(Of CustomModifier).Empty
            End Get
        End Property
 
        Friend Overrides Function WithTypeAndCustomModifiers(type As TypeSymbol, customModifiers As ImmutableArray(Of CustomModifier), refCustomModifiers As ImmutableArray(Of CustomModifier)) As ParameterSymbol
            If customModifiers.IsEmpty AndAlso refCustomModifiers.IsEmpty Then
                Return New SourceComplexParameterSymbol(Me.ContainingSymbol, Me.Name, Me.Ordinal, type, Me.Location, _syntaxRef, _flags, _lazyDefaultValue)
            End If
 
            Return New SourceComplexParameterSymbolWithCustomModifiers(Me.ContainingSymbol, Me.Name, Me.Ordinal, type, Me.Location, _syntaxRef, _flags, _lazyDefaultValue, customModifiers, refCustomModifiers)
        End Function
 
        Private Class SourceComplexParameterSymbolWithCustomModifiers
            Inherits SourceComplexParameterSymbol
 
            Private ReadOnly _customModifiers As ImmutableArray(Of CustomModifier)
            Private ReadOnly _refCustomModifiers As ImmutableArray(Of CustomModifier)
 
            Public Sub New(
                container As Symbol,
                name As String,
                ordinal As Integer,
                type As TypeSymbol,
                location As Location,
                syntaxRef As SyntaxReference,
                flags As SourceParameterFlags,
                defaultValueOpt As ConstantValue,
                customModifiers As ImmutableArray(Of CustomModifier),
                refCustomModifiers As ImmutableArray(Of CustomModifier)
            )
                MyBase.New(container, name, ordinal, type, location, syntaxRef, flags, defaultValueOpt)
 
                Debug.Assert(Not customModifiers.IsEmpty OrElse Not refCustomModifiers.IsEmpty)
                _customModifiers = customModifiers
                _refCustomModifiers = refCustomModifiers
 
                Debug.Assert(_refCustomModifiers.IsEmpty OrElse IsByRef)
            End Sub
 
            Public Overrides ReadOnly Property CustomModifiers As ImmutableArray(Of CustomModifier)
                Get
                    Return _customModifiers
                End Get
            End Property
 
            Public Overrides ReadOnly Property RefCustomModifiers As ImmutableArray(Of CustomModifier)
                Get
                    Return _refCustomModifiers
                End Get
            End Property
 
            Friend Overrides Function WithTypeAndCustomModifiers(type As TypeSymbol, customModifiers As ImmutableArray(Of CustomModifier), refCustomModifiers As ImmutableArray(Of CustomModifier)) As ParameterSymbol
                Throw ExceptionUtilities.Unreachable
            End Function
        End Class
 
    End Class
 
End Namespace