/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/VisualBasic/Portable/Symbols/Source/SourceParameterSymbol.vb
530 строк
28 KB
AlekseyTs
Clean up inheritance hierarchy for CSharpAttributeData/VisualBasicAttributeData. (#70519)
25 окт 2023, 21:23
Не верифицирован
25 окт 2023, 21:23
bb259b0
Код
Авторство
О чём код?
' 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.VisualBasic.Emit Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Friend MustInherit Class SourceParameterSymbol Inherits SourceParameterSymbolBase Implements IAttributeTargetSymbol Private ReadOnly _location As Location Private ReadOnly _name As String Private ReadOnly _type As TypeSymbol Friend Sub New( container As Symbol, name As String, ordinal As Integer, type As TypeSymbol, location As Location) MyBase.New(container, ordinal) _name = name _type = type _location = location End Sub Friend ReadOnly Property Location As Location Get Return _location End Get End Property Public NotOverridable Overrides ReadOnly Property Name As String Get Return _name End Get End Property Friend NotOverridable Overrides ReadOnly Property HasOptionCompare As Boolean Get Return False End Get End Property Friend Overrides ReadOnly Property IsIDispatchConstant As Boolean Get ' Ideally we should look for IDispatchConstantAttribute on this source parameter symbol, ' but the native VB compiler respects this attribute only on metadata parameter symbols, we do the same. ' See Devdiv bug #10789 (Handle special processing of object type without a default value per VB Language Spec 11.8.2 Applicable Methods) for details. Return False End Get End Property Friend Overrides ReadOnly Property IsIUnknownConstant As Boolean Get ' Ideally we should look for IUnknownConstantAttribute on this source parameter symbol, ' but the native VB compiler respects this attribute only on metadata parameter symbols, we do the same. ' See Devdiv bug #10789 (Handle special processing of object type without a default value per VB Language Spec 11.8.2 Applicable Methods) for details. Return False End Get End Property Public NotOverridable Overrides ReadOnly Property Locations As ImmutableArray(Of Location) Get If _location IsNot Nothing Then Return ImmutableArray.Create(Of Location)(_location) Else Return ImmutableArray(Of Location).Empty End If End Get End Property Public NotOverridable Overrides ReadOnly Property Type As TypeSymbol Get Return _type End Get End Property Public MustOverride Overrides ReadOnly Property CustomModifiers As ImmutableArray(Of CustomModifier) Public MustOverride Overrides ReadOnly Property RefCustomModifiers As ImmutableArray(Of CustomModifier) Public Overrides ReadOnly Property DeclaringSyntaxReferences As ImmutableArray(Of SyntaxReference) Get If IsImplicitlyDeclared Then Return ImmutableArray(Of SyntaxReference).Empty Else Return GetDeclaringSyntaxReferenceHelper(Of ParameterSyntax)(Me.Locations) End If End Get End Property Public NotOverridable Overrides ReadOnly Property IsImplicitlyDeclared As Boolean Get If Me.ContainingSymbol.IsImplicitlyDeclared Then If If(TryCast(Me.ContainingSymbol, MethodSymbol)?.MethodKind = MethodKind.DelegateInvoke, False) AndAlso Not Me.ContainingType.AssociatedSymbol?.IsImplicitlyDeclared Then Return False End If Return True End If Return (GetMatchingPropertyParameter() IsNot Nothing) End Get End Property ''' <summary> ''' Is this an accessor parameter that came from the associated property? If so, ''' return it, else return Nothing. ''' </summary> Private Function GetMatchingPropertyParameter() As ParameterSymbol Dim containingMethod = TryCast(ContainingSymbol, MethodSymbol) If containingMethod IsNot Nothing AndAlso containingMethod.IsAccessor() Then Dim containingProperty = TryCast(containingMethod.AssociatedSymbol, PropertySymbol) If containingProperty IsNot Nothing AndAlso Ordinal < containingProperty.ParameterCount Then ' We match a parameter on our containing property. Return containingProperty.Parameters(Ordinal) End If End If Return Nothing End Function #Region "Attributes" ' Attributes on corresponding parameters of partial methods are merged. ' We always create a complex parameter for a partial definition to store potential merged attributes there. ' At the creation time we don't know if the corresponding partial implementation has attributes so we need to always assume it might. ' ' Unlike in C#, where both partial definition and partial implementation have partial syntax and ' hence we create a complex parameter for both of them, in VB partial implementation Sub syntax ' is no different from non-partial Sub. Therefore we can't determine at the creation time whether ' a parameter of a Sub that is not a partial definition might need to store attributes or not. ' ' We therefore need to virtualize the storage for attribute data. Simple parameter of a partial implementation ' uses attribute storage of the corresponding partial definition parameter. ' ' When an implementation parameter is asked for attributes it gets them from the definition parameter: ' 1) If the implementation is a simple parameter it calls GetAttributeBag on the definition. ' 2) If it is a complex parameter it copies the data from the definition using BoundAttributesSource. Friend MustOverride Function GetAttributesBag() As CustomAttributesBag(Of VisualBasicAttributeData) Friend MustOverride Function GetEarlyDecodedWellKnownAttributeData() As ParameterEarlyWellKnownAttributeData Friend MustOverride Function GetDecodedWellKnownAttributeData() As CommonParameterWellKnownAttributeData Friend MustOverride ReadOnly Property AttributeDeclarationList As SyntaxList(Of AttributeListSyntax) Friend NotOverridable Overrides ReadOnly Property HasParamArrayAttribute As Boolean Get Dim data = GetEarlyDecodedWellKnownAttributeData() Return data IsNot Nothing AndAlso data.HasParamArrayAttribute End Get End Property Friend NotOverridable Overrides ReadOnly Property HasDefaultValueAttribute As Boolean Get Dim data = GetEarlyDecodedWellKnownAttributeData() Return data IsNot Nothing AndAlso data.DefaultParameterValue <> ConstantValue.Unset End Get End Property Public ReadOnly Property DefaultAttributeLocation As AttributeLocation Implements IAttributeTargetSymbol.DefaultAttributeLocation Get Return AttributeLocation.Parameter End Get End Property ''' <summary> ''' Gets the attributes applied on this symbol. ''' Returns an empty array if there are no attributes. ''' </summary> Public NotOverridable Overrides Function GetAttributes() As ImmutableArray(Of VisualBasicAttributeData) Return Me.GetAttributesBag().Attributes End Function Friend Overrides Function EarlyDecodeWellKnownAttribute(ByRef arguments As EarlyDecodeWellKnownAttributeArguments(Of EarlyWellKnownAttributeBinder, NamedTypeSymbol, AttributeSyntax, AttributeLocation)) As VisualBasicAttributeData ' Declare methods need to know early what marshalling type are their parameters of to determine ByRef-ness. Dim containingSymbol = Me.ContainingSymbol If containingSymbol.Kind = SymbolKind.Method AndAlso DirectCast(containingSymbol, MethodSymbol).MethodKind = MethodKind.DeclareMethod Then If VisualBasicAttributeData.IsTargetEarlyAttribute(arguments.AttributeType, arguments.AttributeSyntax, AttributeDescription.MarshalAsAttribute) Then Dim hasAnyDiagnostics As Boolean = False Dim attrdata = arguments.Binder.GetAttribute(arguments.AttributeSyntax, arguments.AttributeType, hasAnyDiagnostics) If Not attrdata.HasErrors Then arguments.GetOrCreateData(Of ParameterEarlyWellKnownAttributeData).HasMarshalAsAttribute = True Return If(Not hasAnyDiagnostics, attrdata, Nothing) Else Return Nothing End If End If End If Dim possibleValidParamArrayTarget As Boolean = False Select Case containingSymbol.Kind Case SymbolKind.Property possibleValidParamArrayTarget = True Case SymbolKind.Method Select Case DirectCast(containingSymbol, MethodSymbol).MethodKind Case MethodKind.Conversion, MethodKind.UserDefinedOperator, MethodKind.EventAdd, MethodKind.EventRemove Debug.Assert(Not possibleValidParamArrayTarget) Case Else possibleValidParamArrayTarget = True End Select End Select If possibleValidParamArrayTarget AndAlso VisualBasicAttributeData.IsTargetEarlyAttribute(arguments.AttributeType, arguments.AttributeSyntax, AttributeDescription.ParamArrayAttribute) Then Dim hasAnyDiagnostics As Boolean = False Dim attrdata = arguments.Binder.GetAttribute(arguments.AttributeSyntax, arguments.AttributeType, hasAnyDiagnostics) If Not attrdata.HasErrors Then arguments.GetOrCreateData(Of ParameterEarlyWellKnownAttributeData).HasParamArrayAttribute = True Return If(Not hasAnyDiagnostics, attrdata, Nothing) Else Return Nothing End If End If If VisualBasicAttributeData.IsTargetEarlyAttribute(arguments.AttributeType, arguments.AttributeSyntax, AttributeDescription.DefaultParameterValueAttribute) Then Return EarlyDecodeAttributeForDefaultParameterValue(AttributeDescription.DefaultParameterValueAttribute, arguments) ElseIf VisualBasicAttributeData.IsTargetEarlyAttribute(arguments.AttributeType, arguments.AttributeSyntax, AttributeDescription.DecimalConstantAttribute) Then Return EarlyDecodeAttributeForDefaultParameterValue(AttributeDescription.DecimalConstantAttribute, arguments) ElseIf VisualBasicAttributeData.IsTargetEarlyAttribute(arguments.AttributeType, arguments.AttributeSyntax, AttributeDescription.DateTimeConstantAttribute) Then Return EarlyDecodeAttributeForDefaultParameterValue(AttributeDescription.DateTimeConstantAttribute, arguments) ElseIf VisualBasicAttributeData.IsTargetEarlyAttribute(arguments.AttributeType, arguments.AttributeSyntax, AttributeDescription.CallerLineNumberAttribute) Then arguments.GetOrCreateData(Of ParameterEarlyWellKnownAttributeData).HasCallerLineNumberAttribute = True ElseIf VisualBasicAttributeData.IsTargetEarlyAttribute(arguments.AttributeType, arguments.AttributeSyntax, AttributeDescription.CallerFilePathAttribute) Then arguments.GetOrCreateData(Of ParameterEarlyWellKnownAttributeData).HasCallerFilePathAttribute = True ElseIf VisualBasicAttributeData.IsTargetEarlyAttribute(arguments.AttributeType, arguments.AttributeSyntax, AttributeDescription.CallerMemberNameAttribute) Then arguments.GetOrCreateData(Of ParameterEarlyWellKnownAttributeData).HasCallerMemberNameAttribute = True ElseIf VisualBasicAttributeData.IsTargetEarlyAttribute(arguments.AttributeType, arguments.AttributeSyntax, AttributeDescription.CallerArgumentExpressionAttribute) Then Dim index = -1 Dim attribute = arguments.Binder.GetAttribute(arguments.AttributeSyntax, arguments.AttributeType, False) If Not attribute.HasErrors Then Dim parameterName As String = Nothing If attribute.ConstructorArguments.Single().TryDecodeValue(SpecialType.System_String, parameterName) Then Dim parameters = containingSymbol.GetParameters() For i = 0 To parameters.Length - 1 If IdentifierComparison.Equals(parameters(i).Name, parameterName) Then index = i Exit For End If Next End If End If arguments.GetOrCreateData(Of ParameterEarlyWellKnownAttributeData).CallerArgumentExpressionParameterIndex = index End If Return MyBase.EarlyDecodeWellKnownAttribute(arguments) End Function Friend Overrides Iterator Function GetCustomAttributesToEmit(moduleBuilder As PEModuleBuilder) As IEnumerable(Of VisualBasicAttributeData) Dim attributes = MyBase.GetCustomAttributesToEmit(moduleBuilder) For Each attribute In attributes If AttributeData.IsTargetEarlyAttribute(attributeType:=attribute.AttributeClass, attributeArgCount:=attribute.CommonConstructorArguments.Length, description:=AttributeDescription.CallerArgumentExpressionAttribute) Then Dim callerArgumentExpressionParameterIndex = Me.CallerArgumentExpressionParameterIndex If callerArgumentExpressionParameterIndex <> -1 AndAlso TypeOf attribute Is SourceAttributeData Then Debug.Assert(callerArgumentExpressionParameterIndex >= 0) Debug.Assert(attribute.CommonConstructorArguments.Length = 1) ' We allow CallerArgumentExpression to have case-insensitive parameter name, but we ' want to emit the parameter name with correct casing, so that it works with C#. Dim correctedParameterName = ContainingSymbol.GetParameters()(callerArgumentExpressionParameterIndex).Name Dim oldTypedConstant = attribute.CommonConstructorArguments.Single() If correctedParameterName.Equals(oldTypedConstant.Value.ToString(), StringComparison.Ordinal) Then Yield attribute Continue For End If Dim newArgs = ImmutableArray.Create(New TypedConstant(oldTypedConstant.TypeInternal, oldTypedConstant.Kind, correctedParameterName)) Yield New SourceAttributeData(DeclaringCompilation, attribute.ApplicationSyntaxReference, attribute.AttributeClass, attribute.AttributeConstructor, newArgs, attribute.CommonNamedArguments, attribute.IsConditionallyOmitted, attribute.HasErrors) Continue For End If End If Yield attribute Next End Function ' It is not strictly necessary to decode default value attributes early in VB, ' but it is necessary in C#, so this keeps the implementations consistent. Private Function EarlyDecodeAttributeForDefaultParameterValue(description As AttributeDescription, ByRef arguments As EarlyDecodeWellKnownAttributeArguments(Of EarlyWellKnownAttributeBinder, NamedTypeSymbol, AttributeSyntax, AttributeLocation)) As VisualBasicAttributeData Debug.Assert(description.Equals(AttributeDescription.DefaultParameterValueAttribute) OrElse description.Equals(AttributeDescription.DecimalConstantAttribute) OrElse description.Equals(AttributeDescription.DateTimeConstantAttribute)) Dim hasAnyDiagnostics = False Dim attribute = arguments.Binder.GetAttribute(arguments.AttributeSyntax, arguments.AttributeType, hasAnyDiagnostics) Dim value As ConstantValue If attribute.HasErrors Then value = ConstantValue.Bad hasAnyDiagnostics = True Else value = DecodeDefaultParameterValueAttribute(description, attribute) End If Dim paramData = arguments.GetOrCreateData(Of ParameterEarlyWellKnownAttributeData)() If paramData.DefaultParameterValue = ConstantValue.Unset Then paramData.DefaultParameterValue = value End If Return If(hasAnyDiagnostics, Nothing, attribute) End Function Friend Overrides Sub DecodeWellKnownAttribute(ByRef arguments As DecodeWellKnownAttributeArguments(Of AttributeSyntax, VisualBasicAttributeData, AttributeLocation)) Dim attrData = arguments.Attribute Debug.Assert(Not attrData.HasErrors) Debug.Assert(arguments.SymbolPart = AttributeLocation.None) Debug.Assert(TypeOf arguments.Diagnostics Is BindingDiagnosticBag) ' Differences from C#: ' ' DefaultParameterValueAttribute ' - emitted as is, not treated as pseudo-custom attribute ' - checked (along with DecimalConstantAttribute and DateTimeConstantAttribute) for consistency with any explicit default value ' ' OptionalAttribute ' - Not used by the language, only syntactically optional parameters or metadata optional parameters are recognized by overload resolution. ' OptionalAttribute is checked for in emit phase. ' ' ParamArrayAttribute ' - emitted as is, no error reported ' - Dev11 incorrectly emits the attribute twice ' ' InAttribute, OutAttribute ' - metadata flag set, no diagnostics reported, don't influence language semantics If attrData.IsTargetAttribute(AttributeDescription.TupleElementNamesAttribute) Then DirectCast(arguments.Diagnostics, BindingDiagnosticBag).Add(ERRID.ERR_ExplicitTupleElementNamesAttribute, arguments.AttributeSyntaxOpt.Location) End If If attrData.IsTargetAttribute(AttributeDescription.DefaultParameterValueAttribute) Then ' Attribute decoded and constant value stored during EarlyDecodeWellKnownAttribute. DecodeDefaultParameterValueAttribute(AttributeDescription.DefaultParameterValueAttribute, arguments) ElseIf attrData.IsTargetAttribute(AttributeDescription.DecimalConstantAttribute) Then ' Attribute decoded and constant value stored during EarlyDecodeWellKnownAttribute. DecodeDefaultParameterValueAttribute(AttributeDescription.DecimalConstantAttribute, arguments) ElseIf attrData.IsTargetAttribute(AttributeDescription.DateTimeConstantAttribute) Then ' Attribute decoded and constant value stored during EarlyDecodeWellKnownAttribute. DecodeDefaultParameterValueAttribute(AttributeDescription.DateTimeConstantAttribute, arguments) ElseIf attrData.IsTargetAttribute(AttributeDescription.InAttribute) Then arguments.GetOrCreateData(Of CommonParameterWellKnownAttributeData)().HasInAttribute = True ElseIf attrData.IsTargetAttribute(AttributeDescription.OutAttribute) Then arguments.GetOrCreateData(Of CommonParameterWellKnownAttributeData)().HasOutAttribute = True ElseIf attrData.IsTargetAttribute(AttributeDescription.MarshalAsAttribute) Then MarshalAsAttributeDecoder(Of CommonParameterWellKnownAttributeData, AttributeSyntax, VisualBasicAttributeData, AttributeLocation).Decode(arguments, AttributeTargets.Parameter, MessageProvider.Instance) ElseIf attrData.IsTargetAttribute(AttributeDescription.CallerArgumentExpressionAttribute) Then Dim index = GetEarlyDecodedWellKnownAttributeData()?.CallerArgumentExpressionParameterIndex If index = Ordinal Then DirectCast(arguments.Diagnostics, BindingDiagnosticBag).Add(ERRID.WRN_CallerArgumentExpressionAttributeSelfReferential, arguments.AttributeSyntaxOpt.Location, Me.Name) ElseIf index = -1 Then DirectCast(arguments.Diagnostics, BindingDiagnosticBag).Add(ERRID.WRN_CallerArgumentExpressionAttributeHasInvalidParameterName, arguments.AttributeSyntaxOpt.Location, Me.Name) End If End If MyBase.DecodeWellKnownAttribute(arguments) End Sub Private Sub DecodeDefaultParameterValueAttribute(description As AttributeDescription, ByRef arguments As DecodeWellKnownAttributeArguments(Of AttributeSyntax, VisualBasicAttributeData, AttributeLocation)) Dim attribute = arguments.Attribute Dim diagnostics = DirectCast(arguments.Diagnostics, BindingDiagnosticBag) Debug.Assert(arguments.AttributeSyntaxOpt IsNot Nothing) Debug.Assert(diagnostics IsNot Nothing) Dim value = DecodeDefaultParameterValueAttribute(description, attribute) If Not value.IsBad Then VerifyParamDefaultValueMatchesAttributeIfAny(value, arguments.AttributeSyntaxOpt, diagnostics) End If End Sub ''' <summary> ''' Verify the default value matches the default value from any earlier attribute ''' (DefaultParameterValueAttribute, DateTimeConstantAttribute or DecimalConstantAttribute). ''' If not, report ERR_ParamDefaultValueDiffersFromAttribute. ''' </summary> Protected Sub VerifyParamDefaultValueMatchesAttributeIfAny(value As ConstantValue, syntax As VisualBasicSyntaxNode, diagnostics As BindingDiagnosticBag) Dim data = GetEarlyDecodedWellKnownAttributeData() If data IsNot Nothing Then Dim attrValue = data.DefaultParameterValue If attrValue <> ConstantValue.Unset AndAlso value <> attrValue Then Binder.ReportDiagnostic(diagnostics, syntax, ERRID.ERR_ParamDefaultValueDiffersFromAttribute) End If End If End Sub Private Function DecodeDefaultParameterValueAttribute(description As AttributeDescription, attribute As VisualBasicAttributeData) As ConstantValue Debug.Assert(Not attribute.HasErrors) If description.Equals(AttributeDescription.DefaultParameterValueAttribute) Then Return DecodeDefaultParameterValueAttribute(attribute) ElseIf description.Equals(AttributeDescription.DecimalConstantAttribute) Then Return attribute.DecodeDecimalConstantValue() Else Debug.Assert(description.Equals(AttributeDescription.DateTimeConstantAttribute)) Return attribute.DecodeDateTimeConstantValue() End If End Function Private Function DecodeDefaultParameterValueAttribute(attribute As VisualBasicAttributeData) As ConstantValue Debug.Assert(attribute.CommonConstructorArguments.Length = 1) ' the type of the value is the type of the expression in the attribute Dim arg = attribute.CommonConstructorArguments(0) Dim specialType = If(arg.Kind = TypedConstantKind.Enum, DirectCast(arg.TypeInternal, NamedTypeSymbol).EnumUnderlyingType.SpecialType, arg.TypeInternal.SpecialType) Dim constantValueDiscriminator = ConstantValue.GetDiscriminator(specialType) If constantValueDiscriminator = ConstantValueTypeDiscriminator.Bad Then If arg.Kind <> TypedConstantKind.Array AndAlso arg.ValueInternal Is Nothing AndAlso Type.IsReferenceType Then Return ConstantValue.Null End If Return ConstantValue.Bad End If Return ConstantValue.Create(arg.ValueInternal, constantValueDiscriminator) End Function Friend NotOverridable Overrides ReadOnly Property MarshallingInformation As MarshalPseudoCustomAttributeData Get Dim data = GetDecodedWellKnownAttributeData() If data IsNot Nothing Then Return data.MarshallingInformation End If ' Default marshalling for string parameters of Declare methods (ByRef or ByVal) If Type.IsStringType() Then Dim container As Symbol = ContainingSymbol If container.Kind = SymbolKind.Method Then Dim methodSymbol = DirectCast(container, MethodSymbol) If methodSymbol.MethodKind = MethodKind.DeclareMethod Then Dim info As New MarshalPseudoCustomAttributeData() Debug.Assert(IsByRef) If IsExplicitByRef Then Dim pinvoke As DllImportData = methodSymbol.GetDllImportData() Select Case pinvoke.CharacterSet Case Cci.Constants.CharSet_None, CharSet.Ansi info.SetMarshalAsSimpleType(Cci.Constants.UnmanagedType_AnsiBStr) Case Cci.Constants.CharSet_Auto info.SetMarshalAsSimpleType(Cci.Constants.UnmanagedType_TBStr) Case CharSet.Unicode info.SetMarshalAsSimpleType(UnmanagedType.BStr) Case Else Throw ExceptionUtilities.UnexpectedValue(pinvoke.CharacterSet) End Select Else info.SetMarshalAsSimpleType(Cci.Constants.UnmanagedType_VBByRefStr) End If Return info End If End If End If Return Nothing End Get End Property Public NotOverridable Overrides ReadOnly Property IsByRef As Boolean Get If IsExplicitByRef Then Return True End If ' String parameters of Declare methods without explicit MarshalAs attribute are always ByRef, even if they are declared ByVal. If Type.IsStringType() AndAlso ContainingSymbol.Kind = SymbolKind.Method AndAlso DirectCast(ContainingSymbol, MethodSymbol).MethodKind = MethodKind.DeclareMethod Then Dim data = GetEarlyDecodedWellKnownAttributeData() Return data Is Nothing OrElse Not data.HasMarshalAsAttribute End If Return False End Get End Property Friend NotOverridable Overrides ReadOnly Property IsMetadataOut As Boolean Get Dim data = GetDecodedWellKnownAttributeData() Return data IsNot Nothing AndAlso data.HasOutAttribute End Get End Property Friend NotOverridable Overrides ReadOnly Property IsMetadataIn As Boolean Get Dim data = GetDecodedWellKnownAttributeData() Return data IsNot Nothing AndAlso data.HasInAttribute End Get End Property #End Region End Class Friend Enum SourceParameterFlags As Byte [ByVal] = 1 << 0 [ByRef] = 1 << 1 [Optional] = 1 << 2 [ParamArray] = 1 << 3 End Enum End Namespace