Files
Siegfried Pammer 7d3a330f68 Move raw metadata helpers out of MetadataExtensions
Raw metadata table readers compensate for SRM APIs that do not expose every table shape directly, so keeping them separate from general metadata helpers makes that boundary explicit.

Assisted-by: OpenCode:openai/gpt-5.5:OpenCode
2026-10-03 15:35:09 +02:00

826 lines
29 KiB
C#

// Copyright (c) 2018 Siegfried Pammer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Immutable;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Reflection;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using System.Reflection.PortableExecutable;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Util;
using SRM = System.Reflection.Metadata;
namespace ICSharpCode.Decompiler
{
public static partial class SRMExtensions
{
internal const GenericParameterAttributes AllowByRefLike = (GenericParameterAttributes)0x0020;
internal const MethodImplAttributes MethodImplAsync = (MethodImplAttributes)0x2000;
public static bool HasFlag(this TypeDefinition typeDefinition, TypeAttributes attribute)
=> (typeDefinition.Attributes & attribute) == attribute;
public static bool HasFlag(this MethodDefinition methodDefinition, MethodAttributes attribute)
=> (methodDefinition.Attributes & attribute) == attribute;
public static bool HasFlag(this FieldDefinition fieldDefinition, FieldAttributes attribute)
=> (fieldDefinition.Attributes & attribute) == attribute;
public static bool HasFlag(this PropertyDefinition propertyDefinition, PropertyAttributes attribute)
=> (propertyDefinition.Attributes & attribute) == attribute;
public static bool HasFlag(this EventDefinition eventDefinition, EventAttributes attribute)
=> (eventDefinition.Attributes & attribute) == attribute;
public static bool IsTypeKind(this HandleKind kind) =>
kind == HandleKind.TypeDefinition || kind == HandleKind.TypeReference
|| kind == HandleKind.TypeSpecification;
public static bool IsMemberKind(this HandleKind kind) =>
kind == HandleKind.MethodDefinition || kind == HandleKind.PropertyDefinition
|| kind == HandleKind.FieldDefinition || kind == HandleKind.EventDefinition
|| kind == HandleKind.MemberReference || kind == HandleKind.MethodSpecification;
public static bool IsEntityHandle(this Handle handle) =>
handle.IsNil || (byte)handle.Kind < 112;
public static bool IsValueType(this TypeDefinitionHandle handle, MetadataReader reader)
{
return reader.GetTypeDefinition(handle).IsValueType(reader);
}
public static bool IsValueType(this TypeDefinition typeDefinition, MetadataReader reader)
{
EntityHandle baseType = typeDefinition.GetBaseTypeOrNil();
if (baseType.IsNil)
return false;
if (baseType.IsKnownType(reader, KnownTypeCode.Enum))
return true;
if (!baseType.IsKnownType(reader, KnownTypeCode.ValueType))
return false;
var thisType = typeDefinition.GetFullTypeName(reader);
return !thisType.IsKnownType(KnownTypeCode.Enum);
}
public static bool IsEnum(this TypeDefinitionHandle handle, MetadataReader reader)
{
return reader.GetTypeDefinition(handle).IsEnum(reader);
}
public static bool IsEnum(this TypeDefinition typeDefinition, MetadataReader reader)
{
EntityHandle baseType = typeDefinition.GetBaseTypeOrNil();
if (baseType.IsNil)
return false;
return baseType.IsKnownType(reader, KnownTypeCode.Enum);
}
public static bool IsEnum(this TypeDefinitionHandle handle, MetadataReader reader,
out PrimitiveTypeCode underlyingType)
{
return reader.GetTypeDefinition(handle).IsEnum(reader, out underlyingType);
}
public static bool IsEnum(this TypeDefinition typeDefinition, MetadataReader reader,
out PrimitiveTypeCode underlyingType)
{
underlyingType = 0;
EntityHandle baseType = typeDefinition.GetBaseTypeOrNil();
if (baseType.IsNil)
return false;
if (!baseType.IsKnownType(reader, KnownTypeCode.Enum))
return false;
foreach (var handle in typeDefinition.GetFields())
{
var field = reader.GetFieldDefinition(handle);
if ((field.Attributes & FieldAttributes.Static) != 0)
continue;
var blob = reader.GetBlobReader(field.Signature);
if (blob.ReadSignatureHeader().Kind != SignatureKind.Field)
return false;
underlyingType = (PrimitiveTypeCode)blob.ReadByte();
return true;
}
return false;
}
public static bool IsDelegate(this TypeDefinitionHandle handle, MetadataReader reader)
{
return reader.GetTypeDefinition(handle).IsDelegate(reader);
}
public static bool IsDelegate(this TypeDefinition typeDefinition, MetadataReader reader)
{
var baseType = typeDefinition.GetBaseTypeOrNil();
return !baseType.IsNil && baseType.IsKnownType(reader, KnownTypeCode.MulticastDelegate);
}
public static bool HasBody(this MethodDefinition methodDefinition)
{
const MethodAttributes noBodyAttrs = MethodAttributes.Abstract | MethodAttributes.PinvokeImpl;
const MethodImplAttributes noBodyImplAttrs = MethodImplAttributes.InternalCall
| MethodImplAttributes.Native | MethodImplAttributes.Unmanaged | MethodImplAttributes.Runtime;
return (methodDefinition.Attributes & noBodyAttrs) == 0 &&
(methodDefinition.ImplAttributes & noBodyImplAttrs) == 0 &&
methodDefinition.RelativeVirtualAddress > 0;
}
public static int GetCodeSize(this MethodBodyBlock body)
{
if (body == null)
throw new ArgumentNullException(nameof(body));
return body.GetILReader().Length;
}
public static MethodDefinitionHandle GetAny(this PropertyAccessors accessors)
{
if (!accessors.Getter.IsNil)
return accessors.Getter;
return accessors.Setter;
}
public static MethodDefinitionHandle GetAny(this EventAccessors accessors)
{
if (!accessors.Adder.IsNil)
return accessors.Adder;
if (!accessors.Remover.IsNil)
return accessors.Remover;
return accessors.Raiser;
}
public static ImmutableArray<MethodImplementationHandle> GetMethodImplementations(
this MethodDefinitionHandle handle, MetadataReader reader)
{
var resultBuilder = ImmutableArray.CreateBuilder<MethodImplementationHandle>();
var typeDefinition = reader.GetTypeDefinition(reader.GetMethodDefinition(handle)
.GetDeclaringType());
foreach (var methodImplementationHandle in typeDefinition.GetMethodImplementations())
{
var methodImplementation = reader.GetMethodImplementation(methodImplementationHandle);
if (methodImplementation.MethodBody == handle)
{
resultBuilder.Add(methodImplementationHandle);
}
}
return resultBuilder.ToImmutable();
}
public static EntityHandle GetGenericType(this in TypeSpecification ts, MetadataReader metadata)
{
if (ts.Signature.IsNil)
return default;
// Do a quick scan using BlobReader
var signature = metadata.GetBlobReader(ts.Signature);
// When dealing with FSM implementations, we can safely assume that if it's a type spec,
// it must be a generic type instance.
if (signature.ReadByte() != (byte)SignatureTypeCode.GenericTypeInstance)
return default;
// Skip over the rawTypeKind: value type or class
var rawTypeKind = signature.ReadCompressedInteger();
if (rawTypeKind < 17 || rawTypeKind > 18)
return default;
// Only read the generic type, ignore the type arguments
return signature.ReadTypeHandle();
}
public static EntityHandle GetDeclaringType(this EntityHandle entity, MetadataReader metadata)
{
switch (entity.Kind)
{
case HandleKind.TypeDefinition:
var td = metadata.GetTypeDefinition((TypeDefinitionHandle)entity);
return td.GetDeclaringType();
case HandleKind.TypeReference:
var tr = metadata.GetTypeReference((TypeReferenceHandle)entity);
return tr.GetDeclaringType();
case HandleKind.TypeSpecification:
var ts = metadata.GetTypeSpecification((TypeSpecificationHandle)entity);
return ts.GetGenericType(metadata).GetDeclaringType(metadata);
case HandleKind.FieldDefinition:
var fd = metadata.GetFieldDefinition((FieldDefinitionHandle)entity);
return fd.GetDeclaringType();
case HandleKind.MethodDefinition:
var md = metadata.GetMethodDefinition((MethodDefinitionHandle)entity);
return md.GetDeclaringType();
case HandleKind.MemberReference:
var mr = metadata.GetMemberReference((MemberReferenceHandle)entity);
return mr.Parent;
case HandleKind.EventDefinition:
var ed = metadata.GetEventDefinition((EventDefinitionHandle)entity);
return metadata.GetMethodDefinition(ed.GetAccessors().GetAny()).GetDeclaringType();
case HandleKind.PropertyDefinition:
var pd = metadata.GetPropertyDefinition((PropertyDefinitionHandle)entity);
return metadata.GetMethodDefinition(pd.GetAccessors().GetAny()).GetDeclaringType();
case HandleKind.MethodSpecification:
var ms = metadata.GetMethodSpecification((MethodSpecificationHandle)entity);
return ms.Method.GetDeclaringType(metadata);
default:
throw new ArgumentOutOfRangeException();
}
}
public static TypeReferenceHandle GetDeclaringType(this in TypeReference tr)
{
switch (tr.ResolutionScope.Kind)
{
case HandleKind.TypeReference:
return (TypeReferenceHandle)tr.ResolutionScope;
default:
return default(TypeReferenceHandle);
}
}
public static FullTypeName GetFullTypeName(this EntityHandle handle, MetadataReader reader)
{
if (handle.IsNil)
throw new ArgumentNullException(nameof(handle));
switch (handle.Kind)
{
case HandleKind.TypeDefinition:
return ((TypeDefinitionHandle)handle).GetFullTypeName(reader);
case HandleKind.TypeReference:
return ((TypeReferenceHandle)handle).GetFullTypeName(reader);
case HandleKind.TypeSpecification:
return ((TypeSpecificationHandle)handle).GetFullTypeName(reader);
default:
throw new ArgumentOutOfRangeException();
}
}
public static bool IsKnownType(this EntityHandle handle, MetadataReader reader,
KnownTypeCode knownType)
{
return IsKnownType(handle, reader, KnownTypeReference.Get(knownType).TypeName);
}
internal static bool IsKnownType(this EntityHandle handle, MetadataReader reader,
KnownAttribute knownType)
{
return IsKnownType(handle, reader, knownType.GetTypeName());
}
private static bool IsKnownType(EntityHandle handle, MetadataReader reader, TopLevelTypeName knownType)
{
if (handle.IsNil)
return false;
StringHandle nameHandle, namespaceHandle;
try
{
switch (handle.Kind)
{
case HandleKind.TypeReference:
var tr = reader.GetTypeReference((TypeReferenceHandle)handle);
// ignore exported and nested types
if (tr.ResolutionScope.IsNil || tr.ResolutionScope.Kind == HandleKind.TypeReference)
return false;
nameHandle = tr.Name;
namespaceHandle = tr.Namespace;
break;
case HandleKind.TypeDefinition:
var td = reader.GetTypeDefinition((TypeDefinitionHandle)handle);
if (td.IsNested)
return false;
nameHandle = td.Name;
namespaceHandle = td.Namespace;
break;
case HandleKind.TypeSpecification:
var ts = reader.GetTypeSpecification((TypeSpecificationHandle)handle);
var blob = reader.GetBlobReader(ts.Signature);
return SignatureIsKnownType(reader, knownType, ref blob);
default:
return false;
}
}
catch (BadImageFormatException)
{
// ignore bad metadata when trying to resolve ResolutionScope et al.
return false;
}
if (knownType.TypeParameterCount == 0)
{
if (!reader.StringComparer.Equals(nameHandle, knownType.Name))
return false;
}
else
{
string name = reader.GetString(nameHandle);
name = ReflectionHelper.SplitTypeParameterCountFromReflectionName(name, out int typeParameterCount);
if (typeParameterCount != knownType.TypeParameterCount || name != knownType.Name)
return false;
}
if (namespaceHandle.IsNil)
{
return knownType.Namespace.Length == 0;
}
else
{
return reader.StringComparer.Equals(namespaceHandle, knownType.Namespace);
}
}
private static bool SignatureIsKnownType(MetadataReader reader, TopLevelTypeName knownType, ref BlobReader blob)
{
if (!blob.TryReadCompressedInteger(out int typeCode))
return false;
switch (typeCode)
{
case 0x1: // ELEMENT_TYPE_VOID
return knownType.IsKnownType(KnownTypeCode.Void);
case 0x2: // ELEMENT_TYPE_BOOLEAN
return knownType.IsKnownType(KnownTypeCode.Boolean);
case 0x3: // ELEMENT_TYPE_CHAR
return knownType.IsKnownType(KnownTypeCode.Char);
case 0x4: // ELEMENT_TYPE_I1
return knownType.IsKnownType(KnownTypeCode.SByte);
case 0x5: // ELEMENT_TYPE_U1
return knownType.IsKnownType(KnownTypeCode.Byte);
case 0x6: // ELEMENT_TYPE_I2
return knownType.IsKnownType(KnownTypeCode.Int16);
case 0x7: // ELEMENT_TYPE_U2
return knownType.IsKnownType(KnownTypeCode.UInt16);
case 0x8: // ELEMENT_TYPE_I4
return knownType.IsKnownType(KnownTypeCode.Int32);
case 0x9: // ELEMENT_TYPE_U4
return knownType.IsKnownType(KnownTypeCode.UInt32);
case 0xA: // ELEMENT_TYPE_I8
return knownType.IsKnownType(KnownTypeCode.Int64);
case 0xB: // ELEMENT_TYPE_U8
return knownType.IsKnownType(KnownTypeCode.UInt64);
case 0xC: // ELEMENT_TYPE_R4
return knownType.IsKnownType(KnownTypeCode.Single);
case 0xD: // ELEMENT_TYPE_R8
return knownType.IsKnownType(KnownTypeCode.Double);
case 0xE: // ELEMENT_TYPE_STRING
return knownType.IsKnownType(KnownTypeCode.String);
case 0x16: // ELEMENT_TYPE_TYPEDBYREF
return knownType.IsKnownType(KnownTypeCode.TypedReference);
case 0x18: // ELEMENT_TYPE_I
return knownType.IsKnownType(KnownTypeCode.IntPtr);
case 0x19: // ELEMENT_TYPE_U
return knownType.IsKnownType(KnownTypeCode.UIntPtr);
case 0x1C: // ELEMENT_TYPE_OBJECT
return knownType.IsKnownType(KnownTypeCode.Object);
case 0xF: // ELEMENT_TYPE_PTR
case 0x10: // ELEMENT_TYPE_BYREF
case 0x45: // ELEMENT_TYPE_PINNED
case 0x1D: // ELEMENT_TYPE_SZARRAY
case 0x1B: // ELEMENT_TYPE_FNPTR
case 0x14: // ELEMENT_TYPE_ARRAY
return false;
case 0x1F: // ELEMENT_TYPE_CMOD_REQD
case 0x20: // ELEMENT_TYPE_CMOD_OPT
// modifier
blob.ReadTypeHandle(); // skip modifier
return SignatureIsKnownType(reader, knownType, ref blob);
case 0x15: // ELEMENT_TYPE_GENERICINST
// generic type
return SignatureIsKnownType(reader, knownType, ref blob);
case 0x13: // ELEMENT_TYPE_VAR
case 0x1E: // ELEMENT_TYPE_MVAR
// index
return false;
case 0x11: // ELEMENT_TYPE_VALUETYPE
case 0x12: // ELEMENT_TYPE_CLASS
return IsKnownType(blob.ReadTypeHandle(), reader, knownType);
default:
return false;
}
}
public static FullTypeName GetFullTypeName(this TypeSpecificationHandle handle, MetadataReader reader)
{
if (handle.IsNil)
throw new ArgumentNullException(nameof(handle));
var ts = reader.GetTypeSpecification(handle);
return ts.DecodeSignature(new Metadata.FullTypeNameSignatureDecoder(reader), default(Unit));
}
public static FullTypeName GetFullTypeName(this TypeReferenceHandle handle, MetadataReader reader)
{
if (handle.IsNil)
throw new ArgumentNullException(nameof(handle));
var tr = reader.GetTypeReference(handle);
string name;
try
{
name = reader.GetString(tr.Name);
}
catch (BadImageFormatException)
{
name = $"TR{reader.GetToken(handle):x8}";
}
name = ReflectionHelper.SplitTypeParameterCountFromReflectionName(
name, out var typeParameterCount);
TypeReferenceHandle declaringTypeHandle;
try
{
declaringTypeHandle = tr.GetDeclaringType();
}
catch (BadImageFormatException)
{
declaringTypeHandle = default;
}
if (declaringTypeHandle.IsNil)
{
string ns;
try
{
ns = tr.Namespace.IsNil ? "" : reader.GetString(tr.Namespace);
}
catch (BadImageFormatException)
{
ns = "";
}
return new FullTypeName(new TopLevelTypeName(ns, name, typeParameterCount));
}
else
{
return declaringTypeHandle.GetFullTypeName(reader).NestedType(name, typeParameterCount);
}
}
public static FullTypeName GetFullTypeName(this TypeDefinitionHandle handle, MetadataReader reader)
{
if (handle.IsNil)
throw new ArgumentNullException(nameof(handle));
return reader.GetTypeDefinition(handle).GetFullTypeName(reader);
}
public static FullTypeName GetFullTypeName(this TypeDefinition td, MetadataReader reader)
{
TypeDefinitionHandle declaringTypeHandle;
string name = ReflectionHelper.SplitTypeParameterCountFromReflectionName(
reader.GetString(td.Name), out var typeParameterCount);
if ((declaringTypeHandle = td.GetDeclaringType()).IsNil)
{
string @namespace = td.Namespace.IsNil ? "" : reader.GetString(td.Namespace);
return new FullTypeName(new TopLevelTypeName(@namespace, name, typeParameterCount));
}
else
{
return declaringTypeHandle.GetFullTypeName(reader).NestedType(name, typeParameterCount);
}
}
public static FullTypeName GetFullTypeName(this ExportedType type, MetadataReader metadata)
{
string name = ReflectionHelper.SplitTypeParameterCountFromReflectionName(
metadata.GetString(type.Name), out int typeParameterCount);
if (type.Implementation.Kind == HandleKind.ExportedType)
{
var outerType = metadata.GetExportedType((ExportedTypeHandle)type.Implementation);
return outerType.GetFullTypeName(metadata).NestedType(name, typeParameterCount);
}
else
{
string ns = type.Namespace.IsNil ? "" : metadata.GetString(type.Namespace);
return new TopLevelTypeName(ns, name, typeParameterCount);
}
}
/// <summary>
/// See NRExtensions.HasOnlyReadOnlyProperties: an anonymous type with a settable property
/// cannot be written as a C# anonymous type, so its declaration must not be hidden.
/// </summary>
static bool HasOnlyReadOnlyProperties(TypeDefinition type, MetadataReader metadata)
{
foreach (var handle in type.GetProperties())
{
if (!metadata.GetPropertyDefinition(handle).GetAccessors().Setter.IsNil)
return false;
}
return true;
}
public static bool IsAnonymousType(this TypeDefinition type, MetadataReader metadata)
{
string name = metadata.GetString(type.Name);
if (type.Namespace.IsNil && type.HasGeneratedName(metadata)
&& (name.Contains("AnonType") || name.Contains("AnonymousType")))
{
return type.IsCompilerGenerated(metadata) && HasOnlyReadOnlyProperties(type, metadata);
}
return false;
}
#region HasGeneratedName
public static bool IsGeneratedName(this StringHandle handle, MetadataReader metadata)
{
return !handle.IsNil && IsGeneratedName(metadata.GetString(handle));
}
/// <summary>
/// Detects the mangled names compilers give to entities that have no user-written
/// declaration. The C# compiler prefixes them with '&lt;', the VB compiler separates
/// the parts with '$' (VB$AnonymousType_0, VB$StateMachine_1_Foo). Neither character
/// is legal in a C# or VB identifier.
/// Note that a name may legitimately contain '&lt;' without being generated: explicit
/// implementations of generic interface members are named after the interface.
/// </summary>
internal static bool IsGeneratedName(string name)
{
return name.StartsWith("<", StringComparison.Ordinal) || name.Contains("$");
}
public static bool HasGeneratedName(this MethodDefinitionHandle handle, MetadataReader metadata)
{
return metadata.GetMethodDefinition(handle).Name.IsGeneratedName(metadata);
}
public static bool HasGeneratedName(this TypeDefinitionHandle handle, MetadataReader metadata)
{
return metadata.GetTypeDefinition(handle).Name.IsGeneratedName(metadata);
}
public static bool HasGeneratedName(this TypeDefinition type, MetadataReader metadata)
{
return type.Name.IsGeneratedName(metadata);
}
public static bool HasGeneratedName(this FieldDefinitionHandle handle, MetadataReader metadata)
{
return metadata.GetFieldDefinition(handle).Name.IsGeneratedName(metadata);
}
#endregion
#region IsCompilerGenerated
public static bool IsCompilerGenerated(this MethodDefinitionHandle handle, MetadataReader metadata)
{
return metadata.GetMethodDefinition(handle).IsCompilerGenerated(metadata);
}
public static bool IsCompilerGeneratedOrIsInCompilerGeneratedClass(this MethodDefinitionHandle handle,
MetadataReader metadata)
{
MethodDefinition method = metadata.GetMethodDefinition(handle);
if (method.IsCompilerGenerated(metadata))
return true;
TypeDefinitionHandle declaringTypeHandle = method.GetDeclaringType();
if (!declaringTypeHandle.IsNil && declaringTypeHandle.IsCompilerGenerated(metadata))
return true;
return false;
}
public static bool IsCompilerGeneratedOrIsInCompilerGeneratedClass(this TypeDefinitionHandle handle,
MetadataReader metadata)
{
TypeDefinition type = metadata.GetTypeDefinition(handle);
if (type.IsCompilerGenerated(metadata))
return true;
TypeDefinitionHandle declaringTypeHandle = type.GetDeclaringType();
if (!declaringTypeHandle.IsNil && declaringTypeHandle.IsCompilerGenerated(metadata))
return true;
return false;
}
public static bool IsCompilerGenerated(this MethodDefinition method, MetadataReader metadata)
{
return method.GetCustomAttributes().HasKnownAttribute(metadata, KnownAttribute.CompilerGenerated);
}
public static bool IsCompilerGenerated(this FieldDefinitionHandle handle, MetadataReader metadata)
{
return metadata.GetFieldDefinition(handle).IsCompilerGenerated(metadata);
}
public static bool IsCompilerGenerated(this FieldDefinition field, MetadataReader metadata)
{
return field.GetCustomAttributes().HasKnownAttribute(metadata, KnownAttribute.CompilerGenerated);
}
public static bool IsCompilerGenerated(this TypeDefinitionHandle handle, MetadataReader metadata)
{
return metadata.GetTypeDefinition(handle).IsCompilerGenerated(metadata);
}
public static bool IsCompilerGenerated(this TypeDefinition type, MetadataReader metadata)
{
return type.GetCustomAttributes().HasKnownAttribute(metadata, KnownAttribute.CompilerGenerated);
}
#endregion
#region Attribute extensions
/// <summary>
/// Gets the type of the attribute.
/// </summary>
public static EntityHandle GetAttributeType(this SRM.CustomAttribute attribute, MetadataReader reader)
{
switch (attribute.Constructor.Kind)
{
case HandleKind.MethodDefinition:
var md = reader.GetMethodDefinition((MethodDefinitionHandle)attribute.Constructor);
return md.GetDeclaringType();
case HandleKind.MemberReference:
var mr = reader.GetMemberReference((MemberReferenceHandle)attribute.Constructor);
return mr.Parent;
default:
throw new BadImageFormatException("Unexpected token kind for attribute constructor: "
+ attribute.Constructor.Kind);
}
}
public static bool HasKnownAttribute(this CustomAttributeHandleCollection customAttributes,
MetadataReader metadata, KnownAttribute type)
{
foreach (var handle in customAttributes)
{
var customAttribute = metadata.GetCustomAttribute(handle);
if (customAttribute.IsKnownAttribute(metadata, type))
return true;
}
return false;
}
internal static bool IsKnownAttribute(this SRM.CustomAttribute attr, MetadataReader metadata,
KnownAttribute attrType)
{
return attr.GetAttributeType(metadata).IsKnownType(metadata, attrType);
}
public static Nullability? GetNullableContext(this CustomAttributeHandleCollection customAttributes,
MetadataReader metadata)
{
foreach (var handle in customAttributes)
{
var customAttribute = metadata.GetCustomAttribute(handle);
if (customAttribute.IsKnownAttribute(metadata, KnownAttribute.NullableContext))
{
// Decode
CustomAttributeValue<IType> value;
try
{
value = customAttribute.DecodeValue(
Metadata.MetadataExtensions.MinimalAttributeTypeProvider);
}
catch (BadImageFormatException)
{
continue;
}
catch (Metadata.EnumUnderlyingTypeResolveException)
{
continue;
}
if (value.FixedArguments.Length == 1 && value.FixedArguments[0].Value is byte b && b <= 2)
{
return (Nullability)b;
}
}
}
return null;
}
#endregion
public static unsafe BlobReader GetInitialValue(this FieldDefinition field, MetadataFile pefile,
ICompilation typeSystem)
{
if (!field.HasFlag(FieldAttributes.HasFieldRVA))
return default;
int rva = field.GetRelativeVirtualAddress();
if (rva == 0)
return default;
int size = field.DecodeSignature(new FieldValueSizeDecoder(typeSystem), default);
var sectionData = pefile.GetSectionData(rva);
if (sectionData.Length == 0 && size != 0)
throw new BadImageFormatException($"Field data (rva=0x{rva:x}) could not be found"
+ " in any section!");
if (size < 0 || size > sectionData.Length)
throw new BadImageFormatException($"Invalid size {size} for field data!");
return sectionData.GetReader(0, size);
}
sealed class FieldValueSizeDecoder : ISignatureTypeProvider<int, GenericContext>
{
readonly MetadataModule module;
readonly int pointerSize;
public FieldValueSizeDecoder(ICompilation typeSystem = null)
{
this.module = (MetadataModule)typeSystem?.MainModule;
if (module?.MetadataFile is not PEFile pefile)
this.pointerSize = IntPtr.Size;
else
this.pointerSize = pefile.Reader.PEHeaders.PEHeader.Magic == PEMagic.PE32 ? 4 : 8;
}
public int GetArrayType(int elementType, ArrayShape shape) =>
GetPrimitiveType(PrimitiveTypeCode.Object);
public int GetSZArrayType(int elementType) => GetPrimitiveType(PrimitiveTypeCode.Object);
public int GetByReferenceType(int elementType) => pointerSize;
public int GetFunctionPointerType(MethodSignature<int> signature) => pointerSize;
public int GetGenericInstantiation(int genericType, ImmutableArray<int> typeArguments)
=> genericType;
public int GetGenericMethodParameter(GenericContext genericContext, int index) => 0;
public int GetGenericTypeParameter(GenericContext genericContext, int index) => 0;
public int GetModifiedType(int modifier, int unmodifiedType, bool isRequired) => unmodifiedType;
public int GetPinnedType(int elementType) => elementType;
public int GetPointerType(int elementType) => pointerSize;
public int GetPrimitiveType(PrimitiveTypeCode typeCode)
{
switch (typeCode)
{
case PrimitiveTypeCode.Boolean:
case PrimitiveTypeCode.Byte:
case PrimitiveTypeCode.SByte:
return 1;
case PrimitiveTypeCode.Char:
case PrimitiveTypeCode.Int16:
case PrimitiveTypeCode.UInt16:
return 2;
case PrimitiveTypeCode.Int32:
case PrimitiveTypeCode.UInt32:
case PrimitiveTypeCode.Single:
return 4;
case PrimitiveTypeCode.Int64:
case PrimitiveTypeCode.UInt64:
case PrimitiveTypeCode.Double:
return 8;
case PrimitiveTypeCode.IntPtr:
case PrimitiveTypeCode.UIntPtr:
return pointerSize;
default:
return 0;
}
}
public int GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle,
byte rawTypeKind)
{
var td = reader.GetTypeDefinition(handle);
return td.GetLayout().Size;
}
public int GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle,
byte rawTypeKind)
{
var typeDef = module?.ResolveType(handle, new GenericContext()).GetDefinition();
if (typeDef == null || typeDef.MetadataToken.IsNil)
return 0;
reader = typeDef.ParentModule.MetadataFile.Metadata;
var td = reader.GetTypeDefinition((TypeDefinitionHandle)typeDef.MetadataToken);
return td.GetLayout().Size;
}
public int GetTypeFromSpecification(MetadataReader reader, GenericContext genericContext,
TypeSpecificationHandle handle, byte rawTypeKind)
{
return reader.GetTypeSpecification(handle).DecodeSignature(this, genericContext);
}
}
public static EntityHandle GetBaseTypeOrNil(this TypeDefinition definition)
{
try
{
return definition.BaseType;
}
catch (BadImageFormatException)
{
return default;
}
}
public static string ToILSyntax(this SignatureCallingConvention callConv)
{
return callConv switch {
SignatureCallingConvention.Default => "default",
SignatureCallingConvention.CDecl => "unmanaged cdecl",
SignatureCallingConvention.StdCall => "unmanaged stdcall",
SignatureCallingConvention.ThisCall => "unmanaged thiscall",
SignatureCallingConvention.FastCall => "unmanaged fastcall",
SignatureCallingConvention.VarArgs => "vararg",
SignatureCallingConvention.Unmanaged => "unmanaged",
_ => callConv.ToString().ToLowerInvariant()
};
}
public static UnmanagedMemoryStream AsStream(this MemoryMappedViewAccessor view)
{
long size = checked((long)view.SafeMemoryMappedViewHandle.ByteLength);
return new UnmanagedMemoryStream(view.SafeMemoryMappedViewHandle, 0, size);
}
}
}