|
' 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.Metadata.PE
Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
Friend Class CustomModifierUtils
''' <summary>
''' sourceMethod has the custom modifiers
''' </summary>
Friend Shared Sub CopyMethodCustomModifiers(
sourceMethod As MethodSymbol,
destinationTypeParameters As ImmutableArray(Of TypeSymbol),
<[In], Out> ByRef destinationReturnType As TypeSymbol,
<[In], Out> ByRef parameters As ImmutableArray(Of ParameterSymbol))
Debug.Assert(sourceMethod IsNot Nothing)
' For the most part, we will copy custom modifiers by copying types.
' The only time when this fails Is when the type refers to a type parameter
' owned by the overridden method. We need to replace all such references
' with (equivalent) type parameters owned by this method. We know that
' we can perform this mapping positionally, because the method signatures
' have already been compared.
Dim constructedMethod As MethodSymbol = sourceMethod.ConstructIfGeneric(destinationTypeParameters)
parameters = CustomModifierUtils.CopyParameterCustomModifiers(constructedMethod.Parameters, parameters)
Dim returnTypeWithCustomModifiers = constructedMethod.ReturnType
' We do an extra check before copying the return type to handle the case where the overriding
' method (incorrectly) has a different return type than the overridden method. In such cases,
' we want to retain the original (incorrect) return type to avoid hiding the return type
' given in source.
If destinationReturnType.IsSameType(returnTypeWithCustomModifiers, TypeCompareKind.AllIgnoreOptionsForVB) Then
destinationReturnType = CopyTypeCustomModifiers(returnTypeWithCustomModifiers, destinationReturnType)
End If
End Sub
''' <summary>
''' sourceType has the custom modifiers
''' </summary>
Friend Shared Function CopyTypeCustomModifiers(sourceType As TypeSymbol, destinationType As TypeSymbol) As TypeSymbol
Dim resultType As TypeSymbol
Debug.Assert(sourceType.IsSameType(destinationType, TypeCompareKind.AllIgnoreOptionsForVB))
If destinationType.ContainsTuple() AndAlso Not sourceType.IsSameType(destinationType, TypeCompareKind.IgnoreCustomModifiersAndArraySizesAndLowerBounds) Then
Dim names As ImmutableArray(Of String) = VisualBasicCompilation.TupleNamesEncoder.Encode(destinationType)
resultType = TupleTypeDecoder.DecodeTupleTypesIfApplicable(sourceType, names)
Else
resultType = sourceType
End If
Debug.Assert(resultType.IsSameType(sourceType, TypeCompareKind.IgnoreTupleNames)) ' Same custom modifiers as source type
Debug.Assert(resultType.IsSameType(destinationType, TypeCompareKind.IgnoreCustomModifiersAndArraySizesAndLowerBounds)) ' Same tuple names as destination type
Return resultType
End Function
Public Shared Function CopyParameterCustomModifiers(
overriddenMemberParameters As ImmutableArray(Of ParameterSymbol),
parameters As ImmutableArray(Of ParameterSymbol)
) As ImmutableArray(Of ParameterSymbol)
Debug.Assert(Not parameters.IsDefault)
Debug.Assert(overriddenMemberParameters.Length = parameters.Length)
' Nearly all of the time, there will be no custom modifiers to copy, so don't
' allocate the builder until we know that we need it.
Dim builder As ArrayBuilder(Of ParameterSymbol) = Nothing
For i As Integer = 0 To parameters.Length - 1
Dim thisParam As ParameterSymbol = parameters(i)
If CopyParameterCustomModifiers(overriddenMemberParameters(i), thisParam) Then
If builder Is Nothing Then
builder = ArrayBuilder(Of ParameterSymbol).GetInstance()
builder.AddRange(parameters, i) ' add up To, but Not including, the current parameter
End If
builder.Add(thisParam)
ElseIf builder IsNot Nothing Then
builder.Add(thisParam)
End If
Next
Return If(builder Is Nothing, parameters, builder.ToImmutableAndFree())
End Function
''' <summary>
''' Returns True if <paramref name="thisParam"/> was modified.
''' </summary>
''' <returns></returns>
Public Shared Function CopyParameterCustomModifiers(
overriddenParam As ParameterSymbol,
<[In], Out> ByRef thisParam As ParameterSymbol
) As Boolean
Debug.Assert(TypeOf thisParam Is SourceParameterSymbolBase)
Debug.Assert(thisParam.Type.IsSameType(overriddenParam.Type, TypeCompareKind.AllIgnoreOptionsForVB))
If Not overriddenParam.CustomModifiers.SequenceEqual(thisParam.CustomModifiers) OrElse
(overriddenParam.IsByRef AndAlso thisParam.IsByRef AndAlso Not overriddenParam.RefCustomModifiers.SequenceEqual(thisParam.RefCustomModifiers)) OrElse
Not thisParam.Type.IsSameType(overriddenParam.Type, TypeCompareKind.AllIgnoreOptionsForVB And Not TypeCompareKind.IgnoreCustomModifiersAndArraySizesAndLowerBounds) Then
Dim thisParamType As TypeSymbol = thisParam.Type
Dim overriddenParamType As TypeSymbol = overriddenParam.Type
If thisParamType.ContainsTuple() AndAlso Not overriddenParam.Type.IsSameType(thisParamType, TypeCompareKind.IgnoreCustomModifiersAndArraySizesAndLowerBounds) Then
Dim names As ImmutableArray(Of String) = VisualBasicCompilation.TupleNamesEncoder.Encode(thisParamType)
overriddenParamType = TupleTypeDecoder.DecodeTupleTypesIfApplicable(overriddenParamType, names)
End If
thisParam = DirectCast(thisParam, SourceParameterSymbolBase).WithTypeAndCustomModifiers(
overriddenParamType,
overriddenParam.CustomModifiers,
If(thisParam.IsByRef, overriddenParam.RefCustomModifiers, ImmutableArray(Of CustomModifier).Empty))
Return True
End If
Return False
End Function
Friend Shared Function HasIsExternalInitModifier(modifiers As ImmutableArray(Of CustomModifier)) As Boolean
Return modifiers.Any(Function(modifier) Not modifier.IsOptional AndAlso
DirectCast(modifier, VisualBasicCustomModifier).ModifierSymbol.IsWellKnownTypeIsExternalInit())
End Function
End Class
End Namespace
|