Skip to content

Replace use of DAMT.All in ComponentModel with a more restricted set #114126

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 26, 2025

Conversation

MichalStrehovsky
Copy link
Member

@MichalStrehovsky MichalStrehovsky commented Apr 1, 2025

This is technically a breaking change. Fixes #106366.

@ghost
Copy link

ghost commented Apr 1, 2025

Note regarding the new-api-needs-documentation label:

This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, please make sure the API implementation in the src *.cs file is documented with triple slash comments, so the PR reviewers can sign off that change.

@ghost
Copy link

ghost commented Apr 1, 2025

Note regarding the new-api-needs-documentation label:

This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, please make sure the API implementation in the src *.cs file is documented with triple slash comments, so the PR reviewers can sign off that change.

Copy link
Contributor

Tagging subscribers to this area: @dotnet/area-system-componentmodel-dataannotations
See info in area-owners.md if you want to be subscribed.

@MichalStrehovsky
Copy link
Member Author

@steveharter @eerhardt any opinion about re-annotating ComponentModel with a more restricted annotation?

We used .All in multiple places of the framework whenever we needed to access private members in base type (e.g. DynamicallyAccessedMemberTypes.NonPublicMethods matches what BindingFlags.NonPublic will do and therefore doesn't look at nonpublics in the base - we had spots in ComponentModel where we walked base hierarchies looking for privates and .All was the only annotation that allowed this).

At the time ComponentModel was annotated we didn't have .AllMethods and friends.

The difference between .All and the replacement here is that .All means "all members, public and private, in bases and in implemented interfaces, and all implemented interfaces". The new annotation is "all members, public and private, in bases, and all implemented interfaces". I.e. we skip making members of interfaces available for reflection.

So if someone previously did annotatedType.GetInterfaces()[0].GetMethod("GetEnumerator") it would work. It will not work now.

I reviewed uses of GetInterface/GetInterfaces here and doesn't look like we're affected.

The only potential break here is that someone else could have taken a dependency on this being annotated .All.

A mitigating factor right now is that annotatedType.GetInterfaces()[0].GetMethod("GetEnumerator") currently generates trimming warning even if annotatedType is annotated as .All (we preserve the members, but we didn't teach dataflow analysis that this is safe). I'm fixing that in #114149 so it will become more likely someone could take advantage of this in the future.

@sbomer
Copy link
Member

sbomer commented Apr 3, 2025

The only public APIs where I see the new annotation flowing out of ComponentModel are:

  • MetadataTypeAttribute.MetadataClassType
  • RangeAttribute.OperandType
  • DbConnectionStringBuilder.GetType()

I don't see any reason those APIs would need to support getting interfaces, so I'm in favor of taking the breaking change (especially with considering the mitigating factor you mentioned).

@MichalStrehovsky
Copy link
Member Author

@steveharter @eerhardt any opinion about re-annotating ComponentModel with a more restricted annotation?

@steveharter do you have any opinion about this?

@MichalStrehovsky
Copy link
Member Author

@steveharter @eerhardt any opinion about re-annotating ComponentModel with a more restricted annotation?

@steveharter do you have any opinion about this?

We're running out of time to make this change. If we don't do this for .NET10, we'll lose the mitigating factor I mentioned above (I'll repeat it below). The breaking change would be even more breaking. The measurements over at MichalStrehovsky/rt-sz#118 (comment) suggest this could be a 6.3% size savings for for our benchmark app TodosApi when using the options validator (see #106366 for context).

A mitigating factor right now is that annotatedType.GetInterfaces()[0].GetMethod("GetEnumerator") currently generates trimming warning even if annotatedType is annotated as .All (we preserve the members, but we didn't teach dataflow analysis that this is safe). I'm fixing that in #114149 so it will become more likely someone could take advantage of this in the future.

@MichalStrehovsky MichalStrehovsky marked this pull request as ready for review May 23, 2025 05:28
@Copilot Copilot AI review requested due to automatic review settings May 23, 2025 05:28
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

Replaces broad uses of DynamicallyAccessedMemberTypes.All with targeted flag combinations to improve trimming behavior and maintainability.

  • Introduces AllMembersAndInterfaces constants and applies them in TypeDescriptor and related providers.
  • Updates DbConnectionStringBuilder and its ref file to explicitly list required member types.
  • Aligns annotations in both System.ComponentModel.TypeConverter and System.ComponentModel.Annotations to use the new restricted sets.

Reviewed Changes

Copilot reviewed 19 out of 19 changed files in this pull request and generated no comments.

File Description
src/libraries/System.Data.Common/src/System/Data/Common/DbConnectionStringBuilder.cs Replaced DAMT.All with explicit constructors/events/fields/etc.
src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/TypeDescriptor.cs Added AllMembersAndInterfaces constant and switched annotations
src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/AssociatedMetadataTypeTypeDescriptionProvider.cs Added AllMembersAndInterfaces constant and switched annotations
Comments suppressed due to low confidence (3)

src/libraries/System.Data.Common/src/System/Data/Common/DbConnectionStringBuilder.cs:14

  • Removal of the IL2113 suppression may reintroduce trimming warnings for reflection. Verify that the new attribute flags cover these cases or consider re-adding the suppression.
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2113:ReflectionToRequiresUnreferencedCode",

src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/TypeDescriptor.cs:37

  • Add an XML doc comment for AllMembersAndInterfaces to explain which member types it includes and why this specific set is needed.
internal const DynamicallyAccessedMemberTypes AllMembersAndInterfaces =

src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/AssociatedMetadataTypeTypeDescriptionProvider.cs:14

  • Add an XML summary comment for AllMembersAndInterfaces to clarify its purpose in this type description provider.
internal const DynamicallyAccessedMemberTypes AllMembersAndInterfaces =

@MichalStrehovsky
Copy link
Member Author

/ba-g timeouts on android are known (#115955)

@MichalStrehovsky MichalStrehovsky merged commit 8df4955 into dotnet:main May 26, 2025
84 of 87 checks passed
@MichalStrehovsky MichalStrehovsky deleted the componentmodel branch May 26, 2025 20:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Using Options Validation Source Generator results in increased app size
4 participants