| File: PseudoCustomAttributes.Identity.cs | Web Access |
| Project: ILAssembler.csproj (ILAssembler) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; namespace ILAssembler; internal static partial class PseudoCustomAttributes { private static bool TryGetAttributeTypeName(EntityRegistry.EntityBase constructor, out string @namespace, out string name) { switch (constructor) { case EntityRegistry.MemberReferenceEntity memberReference: switch (memberReference.Parent) { case EntityRegistry.TypeReferenceEntity typeReference: @namespace = typeReference.Namespace; name = typeReference.Name; return true; case EntityRegistry.TypeDefinitionEntity typeDefinition: @namespace = typeDefinition.Namespace; name = typeDefinition.Name; return true; } break; case EntityRegistry.MethodDefinitionEntity methodDefinition: @namespace = methodDefinition.ContainingType.Namespace; name = methodDefinition.ContainingType.Name; return true; } @namespace = ""; name = ""; return false; } private static BlobBuilder? GetConstructorSignature(EntityRegistry.EntityBase constructor) => constructor switch { EntityRegistry.MemberReferenceEntity memberReference => memberReference.Signature, EntityRegistry.MethodDefinitionEntity methodDefinition => methodDefinition.MethodSignature, _ => null }; /// <summary> /// Resolves a type or member reference that designates an entity defined in this module to that /// entity. References are otherwise only resolved while metadata rows are written, which happens /// after this pass runs. Anything that does not designate a local entity is returned unchanged. /// </summary> private static EntityRegistry.EntityBase ResolveOwner(EntityRegistry registry, EntityRegistry.EntityBase owner) { switch (owner) { case EntityRegistry.TypeReferenceEntity typeReference: return registry.FindLocalTypeDefinition(typeReference) ?? owner; case EntityRegistry.MemberReferenceEntity memberReference: if (ResolveDeclaringType(registry, memberReference.Parent) is not { } declaringType) { return owner; } byte[] signature = memberReference.Signature.ToArray(); if (signature.Length == 0) { return owner; } switch (new SignatureHeader(signature[0]).Kind) { case SignatureKind.Method: foreach (EntityRegistry.MethodDefinitionEntity method in declaringType.Methods) { if (method.Name == memberReference.Name && method.MethodSignature is { } methodSignature && methodSignature.ContentEquals(memberReference.Signature)) { return method; } } break; case SignatureKind.Field: foreach (EntityRegistry.FieldDefinitionEntity field in declaringType.Fields) { if (field.Name == memberReference.Name && field.Signature.ContentEquals(memberReference.Signature)) { return field; } } break; } return owner; default: return owner; } } private static EntityRegistry.TypeDefinitionEntity? ResolveDeclaringType( EntityRegistry registry, EntityRegistry.EntityBase? declaringType) => declaringType switch { EntityRegistry.TypeDefinitionEntity typeDefinition => typeDefinition, EntityRegistry.TypeReferenceEntity typeReference => registry.FindLocalTypeDefinition(typeReference), _ => null, }; private static KnownAttribute? TryFindKnownAttribute(EntityRegistry.EntityBase constructor, string @namespace, string name) { foreach (KnownAttribute candidate in s_knownAttributes) { if (candidate.Name != name || candidate.Namespace != @namespace) { continue; } if (candidate.MatchBySignature && !SignatureMatches(constructor, candidate)) { continue; } return candidate; } return null; } /// <summary> /// Discriminates between overloads of a known attribute by comparing the constructor signature's /// parameter count and element types against the descriptor's fixed arguments. The serialization /// type tags of the primitive types used by the known attributes coincide with their /// <c>ELEMENT_TYPE</c> values, so the tags can be compared directly. /// </summary> private static unsafe bool SignatureMatches(EntityRegistry.EntityBase constructor, KnownAttribute candidate) { BlobBuilder? signature = GetConstructorSignature(constructor); if (signature is null) { return false; } byte[] signatureBytes = signature.ToArray(); fixed (byte* signaturePointer = signatureBytes) { var reader = new BlobReader(signaturePointer, signatureBytes.Length); try { // Calling convention, then parameter count. if (!reader.TryReadCompressedInteger(out _) || !reader.TryReadCompressedInteger(out int parameterCount) || parameterCount != candidate.FixedArguments.Length // Skip the return type. || !reader.TryReadCompressedInteger(out _)) { return false; } for (int i = 0; i < parameterCount; i++) { if (!reader.TryReadCompressedInteger(out int element) || (SerializationTypeCode)element != candidate.FixedArguments[i]) { return false; } } return true; } catch (BadImageFormatException) { return false; } } } }