| File: Symbols\Metadata\PE\NativeIntegerTypeDecoder.cs | Web Access |
| Project: src\roslyn\src\Compilers\CSharp\Portable\Microsoft.CodeAnalysis.CSharp.csproj (Microsoft.CodeAnalysis.CSharp) |
// 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. using System; using System.Collections.Immutable; using System.Diagnostics; using System.Reflection.Metadata; using Microsoft.CodeAnalysis.PooledObjects; namespace Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE { internal struct NativeIntegerTypeDecoder { internal static TypeSymbol TransformType(TypeSymbol type, EntityHandle handle, PEModuleSymbol containingModule, TypeSymbol? containingType) { // Note: We avoid any cycles when loading members of System.Runtime.CompilerServices.RuntimeFeature if (containingType?.SpecialType == SpecialType.System_Runtime_CompilerServices_RuntimeFeature || type.ContainingAssembly?.RuntimeSupportsNumericIntPtr == true) { return type; } return containingModule.Module.HasNativeIntegerAttribute(handle, out var transformFlags) ? TransformType(type, transformFlags) : type; } internal static TypeSymbol TransformType(TypeSymbol type, ImmutableArray<bool> transformFlags) { var decoder = new NativeIntegerTypeDecoder(transformFlags); try { var result = decoder.TransformType(type); if (decoder._hitErrorType) { // If we failed to decode because there was an error type involved, marking the // metadata as unsupported means that we'll cover up the error that would otherwise // be reported for the type. This would likely lead to a worse error message as we // would just report a BindToBogus, so return the type unchanged. Debug.Assert(type.ContainsErrorType()); Debug.Assert(result is null); return type; } else if (decoder._index == transformFlags.Length) { Debug.Assert(result is object); return result; } else { return new UnsupportedMetadataTypeSymbol(); } } catch (UnsupportedSignatureContent) { return new UnsupportedMetadataTypeSymbol(); } } private readonly ImmutableArray<bool> _transformFlags; private int _index; private bool _hitErrorType; private NativeIntegerTypeDecoder(ImmutableArray<bool> transformFlags) { _transformFlags = transformFlags; _index = 0; _hitErrorType = false; } private TypeWithAnnotations? TransformTypeWithAnnotations(TypeWithAnnotations type) { if (TransformType(type.Type) is { } transformedType) { return type.WithTypeAndModifiers(transformedType, type.CustomModifiers); } return null; } private TypeSymbol? TransformType(TypeSymbol type) { switch (type.TypeKind) { case TypeKind.Array: return TransformArrayType((ArrayTypeSymbol)type); case TypeKind.Pointer: return TransformPointerType((PointerTypeSymbol)type); case TypeKind.FunctionPointer: return TransformFunctionPointerType((FunctionPointerTypeSymbol)type); case TypeKind.TypeParameter: case TypeKind.Dynamic: return type; case TypeKind.Class: case TypeKind.Struct: case TypeKind.Interface: case TypeKind.Delegate: case TypeKind.Enum: return TransformNamedType((NamedTypeSymbol)type); default: Debug.Assert(type.TypeKind == TypeKind.Error); _hitErrorType = true; return null; } } private NamedTypeSymbol? TransformNamedType(NamedTypeSymbol type) { if (!type.IsGenericType) { switch (type.SpecialType) { case SpecialType.System_IntPtr: case SpecialType.System_UIntPtr: if (_index >= _transformFlags.Length) { throw new UnsupportedSignatureContent(); } return (_transformFlags[_index++], type.IsNativeIntegerWrapperType) switch { (false, true) => type.NativeIntegerUnderlyingType, (true, false) => type.AsNativeInteger(), _ => type, }; } } var allTypeArguments = ArrayBuilder<TypeWithAnnotations>.GetInstance(); type.GetAllTypeArgumentsNoUseSiteDiagnostics(allTypeArguments); bool haveChanges = false; for (int i = 0; i < allTypeArguments.Count; i++) { TypeWithAnnotations oldTypeArgument = allTypeArguments[i]; if (TransformTypeWithAnnotations(oldTypeArgument) is not { } newTypeArgument) { allTypeArguments.Free(); return null; } if (!oldTypeArgument.IsSameAs(newTypeArgument)) { allTypeArguments[i] = newTypeArgument; haveChanges = true; } } NamedTypeSymbol result = haveChanges ? type.WithTypeArguments(allTypeArguments.ToImmutable()) : type; allTypeArguments.Free(); return result; } private ArrayTypeSymbol? TransformArrayType(ArrayTypeSymbol type) { if (TransformTypeWithAnnotations(type.ElementTypeWithAnnotations) is { } elementType) { return type.WithElementType(elementType); } return null; } private PointerTypeSymbol? TransformPointerType(PointerTypeSymbol type) { if (TransformTypeWithAnnotations(type.PointedAtTypeWithAnnotations) is { } pointedAtType) { return type.WithPointedAtType(pointedAtType); } return null; } private FunctionPointerTypeSymbol? TransformFunctionPointerType(FunctionPointerTypeSymbol type) { if (TransformTypeWithAnnotations(type.Signature.ReturnTypeWithAnnotations) is not { } transformedReturnType) { return null; } var transformedParameterTypes = ImmutableArray<TypeWithAnnotations>.Empty; var paramsModified = false; if (type.Signature.ParameterCount > 0) { var builder = ArrayBuilder<TypeWithAnnotations>.GetInstance(type.Signature.ParameterCount); foreach (var param in type.Signature.Parameters) { if (TransformTypeWithAnnotations(param.TypeWithAnnotations) is not { } transformedParam) { builder.Free(); return null; } paramsModified = paramsModified || !transformedParam.IsSameAs(param.TypeWithAnnotations); builder.Add(transformedParam); } if (paramsModified) { transformedParameterTypes = builder.ToImmutableAndFree(); } else { transformedParameterTypes = type.Signature.ParameterTypesWithAnnotations; builder.Free(); } } if (paramsModified || !transformedReturnType.IsSameAs(type.Signature.ReturnTypeWithAnnotations)) { return type.SubstituteTypeSymbol(transformedReturnType, transformedParameterTypes, refCustomModifiers: default, paramRefCustomModifiers: default); } else { return type; } } } }