Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/tools/ilasm/src/ILAssembler/Diagnostic.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@ public static class DiagnosticIds
public const string MissingExportedTypeImplementation = "ILA0031";
public const string KeyFileError = "ILA0032";
public const string TooManyGenericParameters = "ILA0033";
public const string PseudoCustomAttributeInvalidTarget = "ILA0034";
public const string PseudoCustomAttributeInvalidValue = "ILA0035";
public const string PseudoCustomAttributeInvalidBlob = "ILA0036";
public const string PseudoCustomAttributeInvalidGuid = "ILA0037";
public const string PseudoCustomAttributeUnknownArgument = "ILA0038";
public const string PseudoCustomAttributeRepeatedArgument = "ILA0039";
}

internal static class DiagnosticMessageTemplates
Expand Down Expand Up @@ -89,4 +95,10 @@ internal static class DiagnosticMessageTemplates
public const string DuplicateMethod = "Duplicate method definition";
public const string MissingExportedTypeImplementation = "Undefined implementation in ExportedType '{0}' -- ExportedType not emitted";
public const string TooManyGenericParameters = "Generic parameter count {0} exceeds the maximum of {1}";
public const string PseudoCustomAttributeInvalidTarget = "Custom attribute '{0}' cannot be applied to this target";
public const string PseudoCustomAttributeInvalidValue = "Custom attribute '{0}' has an invalid argument value";
public const string PseudoCustomAttributeInvalidBlob = "Custom attribute '{0}' has a malformed value blob";
public const string PseudoCustomAttributeInvalidGuid = "Custom attribute '{0}' does not specify a valid GUID";
public const string PseudoCustomAttributeUnknownArgument = "Custom attribute '{0}' does not have a field or property named '{1}'";
public const string PseudoCustomAttributeRepeatedArgument = "Custom attribute '{0}' specifies '{1}' more than once";
}
65 changes: 62 additions & 3 deletions src/tools/ilasm/src/ILAssembler/EntityRegistry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -819,6 +819,34 @@ public TypeDefinitionEntity GetOrCreateTypeDefinition(TypeDefinitionEntity? cont
return null;
}

/// <summary>
/// Finds the local type definition that a type reference refers to, without assigning or
/// reading any handles. Passes that run before <see cref="WriteContentTo"/> resolves
/// references need this, because handles are not assigned until emission.
/// </summary>
public TypeDefinitionEntity? FindLocalTypeDefinition(TypeReferenceEntity typeReference)
{
switch (typeReference.ResolutionScope)
{
case TypeReferenceEntity enclosing:
return FindLocalTypeDefinition(enclosing) is { } enclosingTypeDef
? FindTypeDefinition(enclosingTypeDef, typeReference.Namespace, typeReference.Name)
: null;

case AssemblyReferenceEntity assemblyReference:
return Assembly is not null
&& string.Equals(assemblyReference.Name, Assembly.Name, StringComparison.OrdinalIgnoreCase)
? FindTypeDefinition(null, typeReference.Namespace, typeReference.Name)
: null;

case ModuleEntity or ModuleReferenceEntity:
return FindTypeDefinition(null, typeReference.Namespace, typeReference.Name);

default:
return null;
}
}

public AssemblyReferenceEntity GetOrCreateAssemblyReference(string name, Action<AssemblyReferenceEntity> onCreateAssemblyReference)
{
return GetOrCreateEntity(name, TableIndex.AssemblyRef, _seenAssemblyRefs, _ => new(name), onCreateAssemblyReference);
Expand Down Expand Up @@ -1599,6 +1627,31 @@ public CustomAttributeEntity CreateCustomAttribute(EntityBase constructor, BlobB
return entity;
}

/// <summary>
/// Removes custom attributes that were lowered to metadata bits or auxiliary table rows
/// by the pseudo custom attribute pass, and renumbers the handles of the survivors.
/// </summary>
/// <remarks>
/// Nothing in metadata refers to a CustomAttribute handle (a CustomAttribute can never be
/// the parent of another custom attribute), so removing rows is safe. Handles are still
/// reassigned so that they stay consistent with the emitted row numbers.
/// </remarks>
public void RemoveCustomAttributes(IReadOnlyCollection<CustomAttributeEntity> toRemove)
{
if (toRemove.Count == 0 || !_seenEntities.TryGetValue(TableIndex.CustomAttribute, out List<EntityBase>? entities))
{
return;
}

var removeSet = new HashSet<CustomAttributeEntity>(toRemove);
entities.RemoveAll(entity => entity is CustomAttributeEntity customAttribute && removeSet.Contains(customAttribute));

for (int i = 0; i < entities.Count; i++)
{
((IHasHandle)entities[i]).SetHandle(MetadataTokens.EntityHandle(TableIndex.CustomAttribute, i + 1));
}
}

public static MethodImplementationEntity CreateUnrecordedMethodImplementation(MethodDefinitionEntity methodBody, MemberReferenceEntity methodDeclaration)
{
return new MethodImplementationEntity(methodBody, methodDeclaration);
Expand Down Expand Up @@ -1939,7 +1992,7 @@ public sealed class MethodDefinitionEntity(TypeDefinitionEntity containingType,

public sealed class ParameterEntity(ParameterAttributes attributes, string? name, BlobBuilder marshallingDescriptor, int sequence) : EntityBase
{
public ParameterAttributes Attributes { get; } = attributes;
public ParameterAttributes Attributes { get; set; } = attributes;
public string? Name { get; } = name;
public BlobBuilder MarshallingDescriptor { get; set; } = marshallingDescriptor;
public bool HasCustomAttributes { get; set; }
Expand Down Expand Up @@ -2004,6 +2057,12 @@ public sealed class CustomAttributeEntity(EntityBase constructor, BlobBuilder va
public EntityBase? Owner { get; set; }
public EntityBase Constructor { get; } = constructor;
public BlobBuilder Value { get; } = value;

/// <summary>
/// Source location of the originating <c>.custom</c> directive, used to report
/// diagnostics from the pseudo custom attribute lowering pass, which runs after parsing.
/// </summary>
public Location? Location { get; set; }
}

public sealed class MethodImplementationEntity(MethodDefinitionEntity methodBody, MemberReferenceEntity methodDeclaration) : EntityBase
Expand All @@ -2014,7 +2073,7 @@ public sealed class MethodImplementationEntity(MethodDefinitionEntity methodBody

public sealed class FieldDefinitionEntity(FieldAttributes attributes, TypeDefinitionEntity type, string name, BlobBuilder signature) : EntityBase
{
public FieldAttributes Attributes { get; } = attributes;
public FieldAttributes Attributes { get; set; } = attributes;
public TypeDefinitionEntity ContainingType { get; } = type;
public string Name { get; } = name;
public BlobBuilder Signature { get; } = signature;
Expand All @@ -2038,7 +2097,7 @@ public sealed class InterfaceImplementationEntity(TypeDefinitionEntity type, Typ

public sealed class EventEntity(EventAttributes attributes, TypeEntity type, string name) : EntityBase
{
public EventAttributes Attributes { get; } = attributes;
public EventAttributes Attributes { get; set; } = attributes;
public TypeEntity Type { get; } = type;
public string Name { get; } = name;

Expand Down
11 changes: 9 additions & 2 deletions src/tools/ilasm/src/ILAssembler/GrammarVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ private void ReportWarning(string id, string message, Antlr4.Runtime.ParserRuleC
}

BlobBuilder ilStream = new();
PseudoCustomAttributes.Lower(_entityRegistry, _diagnostics);
_entityRegistry.WriteContentTo(_metadataBuilder, ilStream, _mappedFieldDataNames);
MetadataRootBuilder rootBuilder = new(_metadataBuilder, _options.MetadataVersion);

Expand Down Expand Up @@ -1866,7 +1867,9 @@ private static GrammarResult.String VisitCompQstring(CILParser.CompQstringContex
var resolved = TryResolveTypedefAsCustomAttribute(alias);
if (resolved is not null)
{
return new(_entityRegistry.CreateCustomAttribute(resolved.Value.Constructor, resolved.Value.Value));
var typedefAttribute = _entityRegistry.CreateCustomAttribute(resolved.Value.Constructor, resolved.Value.Value);
typedefAttribute.Location = Location.From(context.Start, _documents);
return new(typedefAttribute);
}
// Typedef not found - could report diagnostic here
return new(null);
Expand Down Expand Up @@ -1983,10 +1986,13 @@ public GrammarResult.FormattedBlob VisitCustomBlobNVPairs(CILParser.CustomBlobNV
value.WriteUInt16(0);
}

return new(_entityRegistry.CreateCustomAttribute(ctor, value));
var attribute = _entityRegistry.CreateCustomAttribute(ctor, value);
attribute.Location = Location.From(context.Start, _documents);
return new(attribute);
}

GrammarResult ICILVisitor<GrammarResult>.VisitCustomDescrWithOwner(CILParser.CustomDescrWithOwnerContext context) => VisitCustomDescrWithOwner(context);

public GrammarResult.Literal<EntityRegistry.CustomAttributeEntity> VisitCustomDescrWithOwner(CILParser.CustomDescrWithOwnerContext context)
{
var ctor = VisitCustomType(context.customType()).Value;
Expand Down Expand Up @@ -2016,6 +2022,7 @@ public GrammarResult.FormattedBlob VisitCustomBlobNVPairs(CILParser.CustomBlobNV

var attr = _entityRegistry.CreateCustomAttribute(ctor, value);

attr.Location = Location.From(context.Start, _documents);
attr.Owner = VisitOwnerType(context.ownerType()).Value;

return new(attr);
Expand Down
45 changes: 45 additions & 0 deletions src/tools/ilasm/src/ILAssembler/MetadataExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,44 @@

using System;
using System.Reflection;
using System.Runtime.InteropServices;

namespace ILAssembler;

internal static class MetadataExtensions
{
extension(FieldAttributes)
{
public static FieldAttributes NotSerializedFlag => (FieldAttributes)0x0080;
}

extension(MethodImplAttributes)
{
public static MethodImplAttributes UserMask =>
MethodImplAttributes.ManagedMask |
MethodImplAttributes.ForwardRef |
MethodImplAttributes.PreserveSig |
MethodImplAttributes.InternalCall |
MethodImplAttributes.Synchronized |
MethodImplAttributes.NoInlining |
MethodImplAttributes.AggressiveInlining |
MethodImplAttributes.NoOptimization |
MethodImplAttributes.AggressiveOptimization |
MethodImplAttributes.Async;
}

extension(TypeAttributes)
{
public static TypeAttributes ExtendedLayout => (TypeAttributes)0x18;
public static TypeAttributes Forwarder => (TypeAttributes)0x00200000;
public static TypeAttributes SerializableFlag => (TypeAttributes)0x00002000;
}

extension(UnmanagedType)
{
public static int ArraySizeParamIndexSpecified => 0x0001;
public static UnmanagedType ByValStr => (UnmanagedType)0x22;
public static UnmanagedType Max => (UnmanagedType)0x50;
}

extension(DeclarativeSecurityAction)
Expand All @@ -30,3 +59,19 @@ internal static class MetadataExtensions
public static AssemblyFlags ArchitectureMask => (AssemblyFlags)0xF0;
}
}

internal static class ClassInterfaceTypeExtensions
{
extension(ClassInterfaceType)
{
public static ClassInterfaceType Last => (ClassInterfaceType)3;
}
}

internal static class ComInterfaceTypeExtensions
{
extension(ComInterfaceType)
{
public static ComInterfaceType Last => (ComInterfaceType)4;
}
}
Loading
Loading