Skip to content

Parse custom attribute value blobs for dependencies and rewrite type name strings in ILTrim#127596

Draft
Copilot wants to merge 5 commits intomainfrom
copilot/fix-custom-attribute-todos
Draft

Parse custom attribute value blobs for dependencies and rewrite type name strings in ILTrim#127596
Copilot wants to merge 5 commits intomainfrom
copilot/fix-custom-attribute-todos

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 30, 2026

Description

CustomAttributeNode had two TODOs: it wasn't parsing the custom attribute value blob for dependencies, and it wasn't rewriting type name strings that could become stale after trimming removes type forwarders.

Dependency analysis (GetStaticDependencies)

Decodes the custom attribute blob via CustomAttributeTypeProvider and reports dependencies for:

  • typeof() arguments
  • Enum types (needed for boxing)
  • Property setters and fields referenced in named arguments
  • Non-primitive array element types

Follows the same pattern as CustomAttributeBasedDependencyAlgorithm in ILCompiler.

Blob rewriting (WriteInternal)

Always re-encodes the blob using BlobEncoder.CustomAttributeSignature with FixedArgumentsEncoder and CustomAttributeNamedArgumentsEncoder APIs to resolve type name strings to their definitions. Uses writeContext.GetSharedBlobBuilder() following the established pattern of other callers — the rewriter writes directly to the provided BlobBuilder without materializing an intermediate array. The blob is unconditionally re-encoded (no early-out optimization) to ensure the encoding logic is always exercised and bugs are not hidden.

This handles the case where trimming drops type forwarders — e.g. typeof(object) stored as System.Object, System.Runtime gets re-encoded as System.Object, System.Private.CoreLib via CustomAttributeTypeNameFormatter.

Code style

  • Methods use cascading if/else if/else instead of early return statements.
  • EncodeElementType switches on type.Category and handles IsEnum and System.Type in the default case, rather than checking them before the switch.

Test results

24 previously-expected-failing tests now pass and have been removed from ILTrimExpectedFailures.txt (382 passed, 0 failed).

Copilot AI and others added 2 commits April 30, 2026 04:17
…ame strings

Implement custom attribute blob parsing in CustomAttributeNode:
1. GetStaticDependencies now decodes the custom attribute value blob and
   reports dependencies for typeof() arguments, enum types, property
   setters, and fields referenced in the blob.
2. WriteInternal now re-encodes the blob with type name strings resolved
   to their definitions, handling cases where trimming drops type
   forwarders (e.g. re-encoding "System.Object, System.Runtime" to
   "System.Object, System.Private.CoreLib").

Remove 24 tests from ILTrimExpectedFailures.txt that now pass.

Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/f4173cc7-fd45-4a62-9a1c-1a31c06cc85b

Co-authored-by: MichalStrehovsky <13110571+MichalStrehovsky@users.noreply.github.com>
… remove unused parameter

- Catch TypeSystemException and BadImageFormatException instead of base Exception
- Add DependencyNode type alias to reduce verbose fully-qualified type names
- Remove unused isFixedArg parameter from WriteArgumentValue
- Hoist constructor resolution out of named argument loop
- Fix duplicate CustomAttributeTypeNameFormatter allocations

Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/f4173cc7-fd45-4a62-9a1c-1a31c06cc85b

Co-authored-by: MichalStrehovsky <13110571+MichalStrehovsky@users.noreply.github.com>
@dotnet-policy-service
Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke, @dotnet/illink
See info in area-owners.md if you want to be subscribed.

CustomAttributeValue<TypeDesc> decodedValue,
CustomAttributeTypeNameFormatter formatter)
{
var blobBuilder = new BlobBuilder();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot change the custom attribute encoding logic in this file to use BlobEncoder.CustomAttributeNamedArgumentsEncoder APIs. Use the BlobBuilder that is provided by writeContext.GetSharedBlobBuilder. Follow the existing patterns that the other callers of writeContext.GetSharedBlobBuilder use (the rewriter just returns void, writes to the provided BlobBuilder, do not materialize array).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in da3465b. Refactored to use BlobEncoder.CustomAttributeSignature with FixedArgumentsEncoder / CustomAttributeNamedArgumentsEncoder, NamedArgumentTypeEncoder, CustomAttributeElementTypeEncoder, LiteralEncoder, ScalarEncoder, etc. Uses writeContext.GetSharedBlobBuilder() following the established pattern — the rewriter is now void and writes directly to the shared BlobBuilder, no array materialization.

… BlobBuilder

Use BlobEncoder.CustomAttributeSignature with FixedArgumentsEncoder and
CustomAttributeNamedArgumentsEncoder instead of manual byte writing.
Use writeContext.GetSharedBlobBuilder() following established patterns.
Removed byte[] materialization - writes directly to shared BlobBuilder.

Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/d078b767-9d76-41e5-9168-8f6651786108

Co-authored-by: MichalStrehovsky <13110571+MichalStrehovsky@users.noreply.github.com>
Copilot AI requested review from Copilot and removed request for Copilot April 30, 2026 09:04
Copilot AI requested a review from MichalStrehovsky April 30, 2026 09:05
Comment on lines +257 to +264
bool needsRewrite = false;
CheckArgumentsForRewrite(decodedValue, ref needsRewrite);

if (!needsRewrite)
{
blobBuilder.WriteBytes(_module.MetadataReader.GetBlobBytes(customAttribute.Value));
return;
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot this optimization is premature, we should rewrite always, this will just make the rewriting logic run rarely and hide bugs

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the CheckArgumentsForRewrite/CheckArgumentValueForRewrite optimization in 20a8fef. The blob is now always re-encoded through the EncodeCustomAttributeBlob path.

…bute blobs

Remove CheckArgumentsForRewrite/CheckArgumentValueForRewrite that skipped
rewriting when no typeof() references were found. Always rewrite to exercise
the encoding logic and surface bugs.

Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/46e2e54d-5313-4538-8274-c5cfe241e547

Co-authored-by: MichalStrehovsky <13110571+MichalStrehovsky@users.noreply.github.com>
if (argType.IsObject)
{
type.Object();
return;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot The methods in this file have many return statements. Use cascading if/else if/else instead.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replaced early returns with cascading if/else if/else in EncodeNamedArgumentType, WriteLiteralValue, and WriteScalarValue in 229cd7f2.

Comment on lines +331 to +343
if (type.IsEnum)
{
encoder.Enum(formatter.FormatName(type, true));
return;
}

if (IsSystemType(type))
{
encoder.SystemType();
return;
}

switch (type.UnderlyingType.Category)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot Make the switch over type.Category and handle IsEnum and System.Type in the default case.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Switched to type.Category and moved IsEnum/IsSystemType/IsString handling into the default case in 229cd7f2.

…pe.Category

- Replace early returns with cascading if/else if/else in EncodeNamedArgumentType,
  WriteLiteralValue, and WriteScalarValue.
- Switch on type.Category instead of type.UnderlyingType.Category in
  EncodeElementType, handling IsEnum and System.Type in the default case.

Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/683a21bb-4e07-4219-81e8-b0a320967bd3

Co-authored-by: MichalStrehovsky <13110571+MichalStrehovsky@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 1, 2026 11:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-Tools-ILLink .NET linker development as well as trimming analyzers

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants