/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/CSharp/Portable/Symbols/Source/CustomModifierUtils.cs
178 строк
11 KB
Jan Jones
Emit modopt for ref readonly parameters in function pointers (#68728)
14 июл 2023, 13:19
Не верифицирован
14 июл 2023, 13:19
66a5b66
Код
Авторство
О чём код?
// 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. #nullable disable using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE; using Microsoft.CodeAnalysis.PooledObjects; using System.Collections.Immutable; using System.Diagnostics; using System.Linq; namespace Microsoft.CodeAnalysis.CSharp.Symbols { internal static class CustomModifierUtils { /// <remarks> /// Out params are updated by assignment. If you require thread-safety, pass temps and then /// CompareExchange them back into shared memory. /// </remarks> internal static void CopyMethodCustomModifiers( MethodSymbol sourceMethod, MethodSymbol destinationMethod, out TypeWithAnnotations returnType, out ImmutableArray<CustomModifier> customModifiers, out ImmutableArray<ParameterSymbol> parameters, bool alsoCopyParamsModifier) // Last since always named. { Debug.Assert((object)sourceMethod != null); // Assert: none of the method's type parameters have been substituted Debug.Assert((object)sourceMethod == sourceMethod.ConstructedFrom); // 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. MethodSymbol constructedSourceMethod = sourceMethod.ConstructIfGeneric(destinationMethod.TypeArgumentsWithAnnotations); customModifiers = destinationMethod.RefKind != RefKind.None ? constructedSourceMethod.RefCustomModifiers : ImmutableArray<CustomModifier>.Empty; parameters = CopyParameterCustomModifiers(constructedSourceMethod.Parameters, destinationMethod.Parameters, alsoCopyParamsModifier); returnType = destinationMethod.ReturnTypeWithAnnotations; // Default value - in case we don't copy the custom modifiers. TypeSymbol returnTypeSymbol = returnType.Type; var sourceMethodReturnType = constructedSourceMethod.ReturnTypeWithAnnotations; // 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. TypeSymbol returnTypeWithCustomModifiers = sourceMethodReturnType.Type; if (returnTypeSymbol.Equals(returnTypeWithCustomModifiers, TypeCompareKind.AllIgnoreOptions)) { returnType = returnType.WithTypeAndModifiers(CopyTypeCustomModifiers(returnTypeWithCustomModifiers, returnTypeSymbol, destinationMethod.ContainingAssembly), sourceMethodReturnType.CustomModifiers); } } /// <param name="sourceType">Type that already has custom modifiers.</param> /// <param name="destinationType">Same as <paramref name="sourceType"/>, but without custom modifiers. /// May differ in object/dynamic, tuple element names, or other differences ignored by the runtime.</param> /// <param name="containingAssembly">The assembly containing the signature referring to the destination type.</param> /// <returns><paramref name="destinationType"/> with custom modifiers copied from <paramref name="sourceType"/>.</returns> internal static TypeSymbol CopyTypeCustomModifiers(TypeSymbol sourceType, TypeSymbol destinationType, AssemblySymbol containingAssembly) { Debug.Assert(sourceType.Equals(destinationType, TypeCompareKind.AllIgnoreOptions)); const RefKind refKind = RefKind.None; // NOTE: overrides can differ by object/dynamic, tuple element names, etc. // If they do, we'll need to tweak destinationType before we can use it in place of sourceType. // NOTE: refKind is irrelevant here since we are just encoding/decoding the type. ImmutableArray<bool> flags = CSharpCompilation.DynamicTransformsEncoder.EncodeWithoutCustomModifierFlags(destinationType, refKind); TypeSymbol resultType = DynamicTypeDecoder.TransformTypeWithoutCustomModifierFlags(sourceType, containingAssembly, refKind, flags); if (!containingAssembly.RuntimeSupportsNumericIntPtr) { var builder = ArrayBuilder<bool>.GetInstance(); CSharpCompilation.NativeIntegerTransformsEncoder.Encode(builder, destinationType); resultType = NativeIntegerTypeDecoder.TransformType(resultType, builder.ToImmutableAndFree()); } if (destinationType.ContainsTuple() && !sourceType.Equals(destinationType, TypeCompareKind.IgnoreCustomModifiersAndArraySizesAndLowerBounds | TypeCompareKind.IgnoreNullableModifiersForReferenceTypes | TypeCompareKind.IgnoreDynamic)) { // We also preserve tuple names, if present and different ImmutableArray<string> names = CSharpCompilation.TupleNamesEncoder.Encode(destinationType); resultType = TupleTypeDecoder.DecodeTupleTypesIfApplicable(resultType, names); } // Preserve nullable modifiers as well. // https://github.com/dotnet/roslyn/issues/30077: Is it reasonable to copy annotations from the source? // If the destination had some of those annotations but not all, then clearly the destination // was incorrect. Or if the destination is C#7, then the destination will advertise annotations // that the author did not write and did not validate. var flagsBuilder = ArrayBuilder<byte>.GetInstance(); destinationType.AddNullableTransforms(flagsBuilder); int position = 0; int length = flagsBuilder.Count; bool transformResult = resultType.ApplyNullableTransforms(defaultTransformFlag: 0, flagsBuilder.ToImmutableAndFree(), ref position, out resultType); Debug.Assert(transformResult && position == length); Debug.Assert(resultType.Equals(sourceType, TypeCompareKind.IgnoreDynamicAndTupleNames | TypeCompareKind.IgnoreNullableModifiersForReferenceTypes | TypeCompareKind.IgnoreNativeIntegers)); // Same custom modifiers as source type. // Same object/dynamic, nullability, native integers, and tuple names as destination type. Debug.Assert(resultType.Equals(destinationType, TypeCompareKind.IgnoreCustomModifiersAndArraySizesAndLowerBounds)); return resultType; } internal static ImmutableArray<ParameterSymbol> CopyParameterCustomModifiers(ImmutableArray<ParameterSymbol> sourceParameters, ImmutableArray<ParameterSymbol> destinationParameters, bool alsoCopyParamsModifier) { Debug.Assert(!destinationParameters.IsDefault); Debug.Assert(destinationParameters.All(p => p is SourceParameterSymbolBase)); Debug.Assert(sourceParameters.Length == destinationParameters.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. ArrayBuilder<ParameterSymbol> builder = null; int numParams = destinationParameters.Length; for (int i = 0; i < numParams; i++) { SourceParameterSymbolBase destinationParameter = (SourceParameterSymbolBase)destinationParameters[i]; ParameterSymbol sourceParameter = sourceParameters[i]; if (sourceParameter.TypeWithAnnotations.CustomModifiers.Any() || sourceParameter.RefCustomModifiers.Any() || sourceParameter.Type.HasCustomModifiers(flagNonDefaultArraySizesOrLowerBounds: true) || destinationParameter.TypeWithAnnotations.CustomModifiers.Any() || destinationParameter.RefCustomModifiers.Any() || destinationParameter.Type.HasCustomModifiers(flagNonDefaultArraySizesOrLowerBounds: true) || // Could happen if the associated property has custom modifiers. (alsoCopyParamsModifier && (sourceParameter.IsParams != destinationParameter.IsParams))) { if (builder == null) { builder = ArrayBuilder<ParameterSymbol>.GetInstance(); builder.AddRange(destinationParameters, i); //add up to, but not including, the current parameter } bool newParams = alsoCopyParamsModifier ? sourceParameter.IsParams : destinationParameter.IsParams; builder.Add(destinationParameter.WithCustomModifiersAndParams(sourceParameter.Type, sourceParameter.TypeWithAnnotations.CustomModifiers, destinationParameter.RefKind != RefKind.None ? sourceParameter.RefCustomModifiers : ImmutableArray<CustomModifier>.Empty, newParams)); } else if (builder != null) { builder.Add(destinationParameter); } } return builder == null ? destinationParameters : builder.ToImmutableAndFree(); } internal static bool HasInAttributeModifier(this ImmutableArray<CustomModifier> modifiers) { return modifiers.Any(static modifier => !modifier.IsOptional && ((CSharpCustomModifier)modifier).ModifierSymbol.IsWellKnownTypeInAttribute()); } internal static bool HasRequiresLocationAttributeModifier(this ImmutableArray<CustomModifier> modifiers) { return modifiers.Any(static modifier => modifier.IsOptional && ((CSharpCustomModifier)modifier).ModifierSymbol.IsWellKnownTypeRequiresLocationAttribute()); } internal static bool HasIsExternalInitModifier(this ImmutableArray<CustomModifier> modifiers) { return modifiers.Any(static modifier => !modifier.IsOptional && ((CSharpCustomModifier)modifier).ModifierSymbol.IsWellKnownTypeIsExternalInit()); } internal static bool HasOutAttributeModifier(this ImmutableArray<CustomModifier> modifiers) { return modifiers.Any(static modifier => !modifier.IsOptional && ((CSharpCustomModifier)modifier).ModifierSymbol.IsWellKnownTypeOutAttribute()); } } }