File: Symbols\Metadata\PE\PEFieldSymbol.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.Generic
Imports System.Collections.Immutable
Imports System.Collections.ObjectModel
Imports System.Globalization
Imports System.Runtime.InteropServices
Imports System.Threading
Imports System.Reflection
Imports System.Reflection.Metadata
Imports Microsoft.CodeAnalysis.Text
Imports Microsoft.CodeAnalysis.VisualBasic.Symbols
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Imports TypeKind = Microsoft.CodeAnalysis.TypeKind
Imports System.Reflection.Metadata.Ecma335
Imports Microsoft.CodeAnalysis.VisualBasic.Emit
 
Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE
 
    ''' <summary>
    ''' The class to represent all fields imported from a PE/module.
    ''' </summary>
    Friend NotInheritable Class PEFieldSymbol
        Inherits FieldSymbol
 
        ''' <summary>
        ''' This symbol is used as a type for a "fake" required custom modifier added for ByRef fields.
        ''' This allows us to report use site errors for ByRef fields, and, at the same time, allows us
        ''' to accurately match them by signature (since this instance is unique and is not used for anything else)
        ''' without adding full support for RefKind and RefCustomModifiers
        ''' </summary>
        Private Shared ReadOnly _byRefPlaceholder As New UnsupportedMetadataTypeSymbol()
 
        Private ReadOnly _handle As FieldDefinitionHandle
        Private ReadOnly _name As String
        Private ReadOnly _flags As FieldAttributes
        Private ReadOnly _containingType As PENamedTypeSymbol
        Private _lazyType As TypeSymbol
        Private _lazyCustomModifiers As ImmutableArray(Of CustomModifier)
        Private _lazyConstantValue As ConstantValue = Microsoft.CodeAnalysis.ConstantValue.Unset
        Private _lazyDocComment As Tuple(Of CultureInfo, String)
        Private _lazyCustomAttributes As ImmutableArray(Of VisualBasicAttributeData)
        Private _lazyCachedUseSiteInfo As CachedUseSiteInfo(Of AssemblySymbol) = CachedUseSiteInfo(Of AssemblySymbol).Uninitialized ' Indicates unknown state. 
        Private _lazyObsoleteAttributeData As ObsoleteAttributeData = ObsoleteAttributeData.Uninitialized
        Private _lazyIsRequired As ThreeState = ThreeState.Unknown
 
        Friend Sub New(
            moduleSymbol As PEModuleSymbol,
            containingType As PENamedTypeSymbol,
            handle As FieldDefinitionHandle
        )
            Debug.Assert(moduleSymbol IsNot Nothing)
            Debug.Assert(containingType IsNot Nothing)
            Debug.Assert(Not handle.IsNil)
 
            _handle = handle
            _containingType = containingType
 
            Try
                moduleSymbol.Module.GetFieldDefPropsOrThrow(handle, _name, _flags)
            Catch mrEx As BadImageFormatException
                If _name Is Nothing Then
                    _name = String.Empty
                End If
 
                _lazyCachedUseSiteInfo.Initialize(ErrorFactory.ErrorInfo(ERRID.ERR_UnsupportedField1, Me))
            End Try
        End Sub
 
        Public Overrides ReadOnly Property Name As String
            Get
                Return _name
            End Get
        End Property
 
        Public Overrides ReadOnly Property MetadataToken As Integer
            Get
                Return MetadataTokens.GetToken(_handle)
            End Get
        End Property
 
        Friend ReadOnly Property FieldFlags As FieldAttributes
            Get
                Return _flags
            End Get
        End Property
 
        Public Overrides ReadOnly Property AssociatedSymbol As Symbol
            Get
                Return Nothing
            End Get
        End Property
 
        Public Overrides ReadOnly Property ContainingSymbol As Symbol
            Get
                Return _containingType
            End Get
        End Property
 
        Public Overrides ReadOnly Property ContainingType As NamedTypeSymbol
            Get
                Return _containingType
            End Get
        End Property
 
        Public Overrides ReadOnly Property DeclaredAccessibility As Accessibility
            Get
                Dim access As Accessibility = Accessibility.Private
 
                Select Case _flags And FieldAttributes.FieldAccessMask
                    Case FieldAttributes.Assembly
                        access = Accessibility.Friend
 
                    Case FieldAttributes.FamORAssem
                        access = Accessibility.ProtectedOrFriend
 
                    Case FieldAttributes.FamANDAssem
                        access = Accessibility.ProtectedAndFriend
 
                    Case FieldAttributes.Private,
                         FieldAttributes.PrivateScope
                        access = Accessibility.Private
 
                    Case FieldAttributes.Public
                        access = Accessibility.Public
 
                    Case FieldAttributes.Family
                        access = Accessibility.Protected
 
                    Case Else
                        access = Accessibility.Private
                End Select
 
                Return access
            End Get
        End Property
 
        Public Overloads Overrides Function GetAttributes() As ImmutableArray(Of VisualBasicAttributeData)
            If _lazyCustomAttributes.IsDefault Then
                Dim containingPEModuleSymbol = DirectCast(ContainingModule(), PEModuleSymbol)
 
                Dim filterOutConstantAttributeDescription As AttributeDescription = GetConstantAttributeDescription()
 
                If filterOutConstantAttributeDescription.Signatures IsNot Nothing Then
                    Dim constantAttribute As CustomAttributeHandle
                    Dim attributes = containingPEModuleSymbol.GetCustomAttributesForToken(
                        _handle,
                        constantAttribute,
                        filterOutConstantAttributeDescription)
 
                    ImmutableInterlocked.InterlockedInitialize(_lazyCustomAttributes, attributes)
                Else
                    containingPEModuleSymbol.LoadCustomAttributes(_handle, _lazyCustomAttributes)
                End If
            End If
 
            Return _lazyCustomAttributes
        End Function
 
        Private Function GetConstantAttributeDescription() As AttributeDescription
            Dim value As ConstantValue
 
            If Me.Type.SpecialType = SpecialType.System_DateTime Then
                value = GetConstantValue(ConstantFieldsInProgress.Empty)
                If value IsNot Nothing AndAlso value.Discriminator = ConstantValueTypeDiscriminator.DateTime Then
                    Return AttributeDescription.DateTimeConstantAttribute
                End If
            ElseIf Me.Type.SpecialType = SpecialType.System_Decimal Then
                value = GetConstantValue(ConstantFieldsInProgress.Empty)
                If value IsNot Nothing AndAlso value.Discriminator = ConstantValueTypeDiscriminator.Decimal Then
                    Return AttributeDescription.DecimalConstantAttribute
                End If
            End If
 
            Return Nothing
        End Function
 
        Friend Overrides Iterator Function GetCustomAttributesToEmit(moduleBuilder As PEModuleBuilder) As IEnumerable(Of VisualBasicAttributeData)
            For Each attribute In GetAttributes()
                Yield attribute
            Next
 
            ' Yield hidden attributes last, order might be important.
            Dim filteredOutConstantAttributeDescription As AttributeDescription = GetConstantAttributeDescription()
 
            If filteredOutConstantAttributeDescription.Signatures IsNot Nothing Then
                Dim containingPEModuleSymbol = DirectCast(ContainingModule(), PEModuleSymbol)
                Yield New PEAttributeData(containingPEModuleSymbol,
                                          containingPEModuleSymbol.Module.FindLastTargetAttribute(Me._handle, filteredOutConstantAttributeDescription).Handle)
            End If
        End Function
 
        Friend Overrides ReadOnly Property HasSpecialName As Boolean
            Get
                Return (_flags And FieldAttributes.SpecialName) <> 0
            End Get
        End Property
 
        Friend Overrides ReadOnly Property HasRuntimeSpecialName As Boolean
            Get
                Return (_flags And FieldAttributes.RTSpecialName) <> 0
            End Get
        End Property
 
        Friend Overrides ReadOnly Property IsNotSerialized As Boolean
            Get
#Disable Warning SYSLIB0050 ' 'TypeAttributes.Serializable' is obsolete
                Return (_flags And FieldAttributes.NotSerialized) <> 0
#Enable Warning SYSLIB0050
            End Get
        End Property
 
        Public Overrides ReadOnly Property IsReadOnly As Boolean
            Get
                Return (_flags And FieldAttributes.InitOnly) <> 0
            End Get
        End Property
 
        Public Overrides ReadOnly Property IsConst As Boolean
            Get
                Return (_flags And FieldAttributes.Literal) <> 0 OrElse GetConstantValue(ConstantFieldsInProgress.Empty) IsNot Nothing
            End Get
        End Property
 
        Friend Overrides Function GetConstantValue(inProgress As ConstantFieldsInProgress) As ConstantValue
            If _lazyConstantValue Is Microsoft.CodeAnalysis.ConstantValue.Unset Then
                Dim value As ConstantValue = Nothing
 
                If (_flags And FieldAttributes.Literal) <> 0 Then
                    value = _containingType.ContainingPEModule.Module.GetConstantFieldValue(_handle)
                    value = AdjustConstantValueFromMetadata(value, Me.Type, False)
                    Dim selfOrUnderlyingType = Me.Type.GetEnumUnderlyingTypeOrSelf
                    Dim selfOrUnderlyingSpecialType = selfOrUnderlyingType.SpecialType
 
                    ' handle nothing literal conversions
                    If value.IsNothing Then
                        ' assign a numerical 0 to numeric types
                        If Me.Type.GetEnumUnderlyingTypeOrSelf.IsNumericType Then
                            value = Microsoft.CodeAnalysis.ConstantValue.Default(
                            Microsoft.CodeAnalysis.ConstantValue.GetDiscriminator(selfOrUnderlyingSpecialType))
                        ElseIf selfOrUnderlyingSpecialType = SpecialType.System_DateTime Then
                            ' assign the default value for DateTime
                            value = Microsoft.CodeAnalysis.ConstantValue.Default(ConstantValueTypeDiscriminator.DateTime)
                        ElseIf selfOrUnderlyingSpecialType = SpecialType.System_Boolean Then
                            ' assign the default value for Boolean
                            value = Microsoft.CodeAnalysis.ConstantValue.Default(ConstantValueTypeDiscriminator.Boolean)
                        ElseIf selfOrUnderlyingSpecialType = SpecialType.System_Char Then
                            ' assign the default value for Char
                            value = Microsoft.CodeAnalysis.ConstantValue.Default(ConstantValueTypeDiscriminator.Char)
                        Else
                            ' This case handles System.Object (last remaining type of VB's primitives types) and
                            ' all type where const folding of a nothing reference would succeed (Dev10 allows importing constants 
                            ' of arbitrary reference types with a constant value of "nothing"). So we are allowing a bit more than
                            ' the spec defines.
                            If selfOrUnderlyingType.IsErrorType OrElse
                               Conversions.TryFoldNothingReferenceConversion(value,
                                                                             ConversionKind.WideningNothingLiteral,
                                                                             selfOrUnderlyingType) Is Nothing Then
 
                                ' type parameters and structures are not supported to be initialized with nothing
                                value = Microsoft.CodeAnalysis.ConstantValue.Bad
                            End If
                        End If
 
                    ElseIf value.SpecialType <> selfOrUnderlyingSpecialType Then
                        ' If the constant value from metadata is invalid (has a different type), mark the value as bad.
                        value = Microsoft.CodeAnalysis.ConstantValue.Bad
                    End If
                End If
 
                ' If this is a DateTime or Decimal, the constant value comes from an attributes (VB assumption).
                ' This also means that these values overwrite constant values that have been generated by non VB compilers.
                Dim defaultValue As ConstantValue = CodeAnalysis.ConstantValue.NotAvailable
 
                If Me.Type.SpecialType = SpecialType.System_DateTime Then
                    If PEModule.HasDateTimeConstantAttribute(Handle, defaultValue) Then
                        value = defaultValue
                    End If
                ElseIf Me.Type.SpecialType = SpecialType.System_Decimal Then
                    If PEModule.HasDecimalConstantAttribute(Handle, defaultValue) Then
                        value = defaultValue
                    End If
                End If
 
                Interlocked.CompareExchange(_lazyConstantValue,
                                            value,
                                            Microsoft.CodeAnalysis.ConstantValue.Unset)
            End If
 
            Return _lazyConstantValue
        End Function
 
        Public Overrides ReadOnly Property IsRequired As Boolean
            Get
                If Not _lazyIsRequired.HasValue() Then
                    _lazyIsRequired = PEModule.HasAttribute(Handle, AttributeDescription.RequiredMemberAttribute).ToThreeState()
                End If
 
                Return _lazyIsRequired.Value()
            End Get
        End Property
 
        Public Overrides ReadOnly Property IsShared As Boolean
            Get
                Return (_flags And FieldAttributes.Static) <> 0
            End Get
        End Property
 
        Friend Overrides ReadOnly Property MarshallingInformation As MarshalPseudoCustomAttributeData
            Get
                ' the compiler doesn't need full marshalling information, just the unmanaged type
                Return Nothing
            End Get
        End Property
 
        Friend Overrides ReadOnly Property ObsoleteAttributeData As ObsoleteAttributeData
            Get
                ObsoleteAttributeHelpers.InitializeObsoleteDataFromMetadata(_lazyObsoleteAttributeData, _handle, DirectCast(ContainingModule, PEModuleSymbol))
                Return _lazyObsoleteAttributeData
            End Get
        End Property
 
        Friend Overrides ReadOnly Property IsMarshalledExplicitly As Boolean
            Get
                Return (_flags And FieldAttributes.HasFieldMarshal) <> 0
            End Get
        End Property
 
        Friend Overrides ReadOnly Property MarshallingType As UnmanagedType
            Get
                If (_flags And FieldAttributes.HasFieldMarshal) = 0 Then
                    Return Nothing
                End If
 
                Return PEModule.GetMarshallingType(_handle)
            End Get
        End Property
 
        Friend Overrides ReadOnly Property MarshallingDescriptor As ImmutableArray(Of Byte)
            Get
                If (_flags And FieldAttributes.HasFieldMarshal) = 0 Then
                    Return Nothing
                End If
 
                Return PEModule.GetMarshallingDescriptor(_handle)
            End Get
        End Property
 
        Friend Overrides ReadOnly Property TypeLayoutOffset As Integer?
            Get
                Return PEModule.GetFieldOffset(_handle)
            End Get
        End Property
 
        Public Overrides ReadOnly Property Locations As ImmutableArray(Of Location)
            Get
                Return StaticCast(Of Location).From(_containingType.ContainingPEModule.MetadataLocation)
            End Get
        End Property
 
        Public Overrides ReadOnly Property DeclaringSyntaxReferences As ImmutableArray(Of SyntaxReference)
            Get
                Return ImmutableArray(Of SyntaxReference).Empty
            End Get
        End Property
 
        Private Sub EnsureSignatureIsLoaded()
            If _lazyType Is Nothing Then
                Dim moduleSymbol = _containingType.ContainingPEModule
                Dim fieldInfo As FieldInfo(Of TypeSymbol) = New MetadataDecoder(moduleSymbol, _containingType).DecodeFieldSignature(_handle)
 
                Dim type As TypeSymbol = Nothing
                Dim customModifiers As ImmutableArray(Of ModifierInfo(Of TypeSymbol)) = Nothing
                GetSignatureParts(fieldInfo, type, customModifiers)
 
                type = TupleTypeDecoder.DecodeTupleTypesIfApplicable(type, _handle, moduleSymbol)
 
                ImmutableInterlocked.InterlockedCompareExchange(_lazyCustomModifiers, VisualBasicCustomModifier.Convert(customModifiers), Nothing)
                Interlocked.CompareExchange(_lazyType, type, Nothing)
            End If
        End Sub
 
        Friend Shared Sub GetSignatureParts(fieldInfo As FieldInfo(Of TypeSymbol), ByRef type As TypeSymbol, ByRef customModifiers As ImmutableArray(Of ModifierInfo(Of TypeSymbol)))
            type = fieldInfo.Type
            customModifiers = fieldInfo.CustomModifiers.NullToEmpty
 
            If fieldInfo.IsByRef Then
                Dim refCustomModifiers = fieldInfo.RefCustomModifiers.NullToEmpty.Add(New ModifierInfo(Of TypeSymbol)(isOptional:=False, _byRefPlaceholder))
                customModifiers = refCustomModifiers.AddRange(customModifiers)
            ElseIf Not fieldInfo.RefCustomModifiers.IsDefaultOrEmpty Then
                Throw ExceptionUtilities.Unreachable
            End If
        End Sub
 
        Public Overrides ReadOnly Property Type As TypeSymbol
            Get
                EnsureSignatureIsLoaded()
                Return _lazyType
            End Get
        End Property
 
        Public Overrides ReadOnly Property CustomModifiers As ImmutableArray(Of CustomModifier)
            Get
                EnsureSignatureIsLoaded()
                Return _lazyCustomModifiers
            End Get
        End Property
 
        Public Overrides Function GetDocumentationCommentXml(Optional preferredCulture As CultureInfo = Nothing, Optional expandIncludes As Boolean = False, Optional cancellationToken As CancellationToken = Nothing) As String
            ' Note: m_LazyDocComment is passed ByRef
            Return PEDocumentationCommentUtils.GetDocumentationComment(
                Me, _containingType.ContainingPEModule, preferredCulture, cancellationToken, _lazyDocComment)
        End Function
 
        Friend Overrides Function GetUseSiteInfo() As UseSiteInfo(Of AssemblySymbol)
            Dim primaryDependency As AssemblySymbol = Me.PrimaryDependency
 
            If Not _lazyCachedUseSiteInfo.IsInitialized Then
                Dim fieldUseSiteInfo = CalculateUseSiteInfo()
 
                If fieldUseSiteInfo.DiagnosticInfo Is Nothing Then
                    Dim errorInfo = DeriveCompilerFeatureRequiredDiagnostic(fieldUseSiteInfo)
                    If errorInfo IsNot Nothing Then
                        fieldUseSiteInfo = New UseSiteInfo(Of AssemblySymbol)(errorInfo)
                    End If
                End If
 
                ' if there was no previous use site error for this symbol, check the constant value
                If fieldUseSiteInfo.DiagnosticInfo Is Nothing Then
 
                    ' report use site errors for invalid constant values 
                    Dim constantValue = GetConstantValue(ConstantFieldsInProgress.Empty)
                    If constantValue IsNot Nothing AndAlso
                        constantValue.IsBad Then
                        fieldUseSiteInfo = New UseSiteInfo(Of AssemblySymbol)(New DiagnosticInfo(MessageProvider.Instance,
                                                                                                 ERRID.ERR_UnsupportedConstant2,
                                                                                                 Me.ContainingType,
                                                                                                 Me.Name))
                    End If
                End If
 
                _lazyCachedUseSiteInfo.Initialize(primaryDependency, fieldUseSiteInfo)
            End If
 
            Return _lazyCachedUseSiteInfo.ToUseSiteInfo(primaryDependency)
        End Function
 
        Private Function DeriveCompilerFeatureRequiredDiagnostic(ByRef result As UseSiteInfo(Of AssemblySymbol)) As DiagnosticInfo
            Dim containingModule = _containingType.ContainingPEModule
            Return If(DeriveCompilerFeatureRequiredAttributeDiagnostic(Me, containingModule, Handle, CompilerFeatureRequiredFeatures.None, New MetadataDecoder(containingModule, _containingType)),
                      _containingType.GetCompilerFeatureRequiredDiagnostic())
        End Function
 
        Friend ReadOnly Property Handle As FieldDefinitionHandle
            Get
                Return _handle
            End Get
        End Property
 
        ''' <remarks>
        ''' This is for perf, not for correctness.
        ''' </remarks>
        Friend Overrides ReadOnly Property DeclaringCompilation As VisualBasicCompilation
            Get
                Return Nothing
            End Get
        End Property
 
        Private ReadOnly Property PEModule As PEModule
            Get
                Return DirectCast(ContainingModule, PEModuleSymbol).Module
            End Get
        End Property
    End Class
 
End Namespace