| File: Symbols\Source\CustomModifierUtils.vb | Web Access |
| Project: src\roslyn\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.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