-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
Allow DynamicallyAccessedMembersAttribute on methods #36340
Allow DynamicallyAccessedMembersAttribute on methods #36340
Conversation
Tagging subscribers to this area: @ViktorHofer |
@@ -19,7 +19,7 @@ namespace System.Diagnostics.CodeAnalysis | |||
/// </remarks> | |||
[AttributeUsage( | |||
AttributeTargets.Field | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter | | |||
AttributeTargets.Parameter | AttributeTargets.Property, | |||
AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.Method, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should put comments around this explaining why we need this in CoreLib but we don't want this to be exposed through contracts.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed.
One concern I have is if/when someone regenerates the ref
assembly, this new AttributeTarget will get generated into the ref
assembly, and it might not get caught during code review.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 We want to be getting rid of the differences between autogenerated ref
assembly, not adding new ones.
Given the feedback - alternate solution is to introduce an internal only attribute specifically for this, basically Thoughts? |
Can you help me understand what's so special about corelib in this regard? I'm wondering if we have this use-case why others may not as well? It's specific not just to corelib but more so to Type itself? |
The So yes - it's basically specific to |
Would another alternative be to special-case |
Depends on what kind of "Special case" you have in mind. We already do special case some of the API on Type in the linker. But there's a lot of them, so the idea was to avoid special-casing all of them. The other consideration is maintenance. If we add/tweak something in CoreLib it's much closer to the change to have it in the attributes then in the linker. And another idea was that the system would work without the special casing in the linker, that just makes it "nicer" (less warnings for things linker can figure out) - but that requires annotations in the CoreLib itself - which is what this is about. I think that internal only attribute is basically a special case in the linker - just such that there's still reasonable separation between the tool and the library. |
Maybe an example would be helpful to explain what this is about: class Type
{
public ConstructorInfo[] GetConstructors() => ...
} The above API is only safe to call with linker in the picture if the class Type
{
// When placed on a method, this annotation annotates `this`
[DynamicallyAccessedMembers(MemberTypes.PublicConstructors)]
public ConstructorInfo[] GetConstructors() => ...
} |
I changed it to a separate internal only attribute - does that look better? |
It's public rather than internal; was that intentional? I know it's not in the ref, but it's not clear why this would need to be exposed as public even with that. Even so, it seems there are two aspects of "public" here: the visibility of the attribute itself in .NET 5, but also the recognition of it with the linker. If the linker is recognizing this attribute by name, isn't it effectively then something folks could rely on by defining their own version of the attribute? That said, if adding an internal (not public) attribute fixes the problem, that seems fine until something better can be devised. |
That's my bad - it should be internal. Linker actually ignores the attribute (even the public one, but it will do this for the new one as well) if it's applied to anything else then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not super excited about the name, but I can't think of anything better.
- DynamicallyAccessedMembersOnCurrent
- DynamicallyAccessedMembersOnInstance
- DynamicallyAccessedMembersInternal
- DynamicallyAccessedMembersForType
None of those are significantly better IMO. So I think what we have is fine. It is internal, so if we really want to change it, we could.
Would it make sense to just allow One has to be careful to apply |
@jkotas In the API review the allowed targets for the attribute were actually discussed quite a bit - I got the feeling that we try to reduce it to the very minimal set possible. Mainly because it gives people direct feedback in VS/build if they got it wrong. In this case I don't like that solution mainly because it's basically always wrong (with this one little internal exception). I do agree that in theory it doesn't make sense to put the attribute on the method directly, but I can easily see people getting confused by this pretty quickly. |
Is the linker going to warn when this attribute is applied in places where it does not make sense? It would fix the confusion for this case, and all other cases.
Another option is to put the internal version into the |
Currently linker doesn't warn if otherwise recognized attribute is used in a place where it's ignored. The main reason typically is that if somebody puts an attribute in the wrong place in a NuGet, when I build the app I would constantly get a warning without a good way to suppress it (we're building the ability to maybe suppress it now, but it's still relatively bad experience). I can definitely move this to other namespace if it makes more sense - and maybe even change the name to something including "Internal" or so. |
If the NuGet author is adding these attributes, they are presumably going to verify they work. If they depend on their customers to verify it, it is their problem. My default stance would be to warn about misplaced attributes always. It is the good diagnostic experience. Only worry about the noise if/once we find that people are shipping NuGets with misplaced attributes and not correcting the bugs fast enough. |
@marek-safar for more details on the current linker behavior (of not reporting any issues with input XMLs and most attributes). |
I'm fine with warnings for publicly available attributes as they are highly unlikely to change but not sure it's worth the effort to add warnings for internal attributes which could change in the future. |
I moved the attribute to |
src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
Outdated
Show resolved
Hide resolved
@@ -193,6 +193,7 @@ | |||
<Compile Include="$(MSBuildThisFileDirectory)System\Decimal.DecCalc.cs" /> | |||
<Compile Include="$(MSBuildThisFileDirectory)System\DefaultBinder.cs" /> | |||
<Compile Include="$(MSBuildThisFileDirectory)System\Delegate.cs" /> | |||
<Compile Include="$(MSBuildThisFileDirectory)Internal\Diagnostics\CodeAnalysis\DynamicallyAccessedMembersOnThisAttribute.cs" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: We are keeping this list alphabetically sorted. It should be in the Internal*
block.
I just realized that we will need to make this public (in whichever way we decide to do it). We need to be able to annotate the public APIs in ref assemblies as well (if only to make the libraries linker runs see the attributes). So even this special case will have to be public. So the two options are:
From end user perspective the best option is the original proposal - only make the change in impl. assembly and leave it out of ref assembly. No observable difference from the outside, but we get a publicly visible attribute to annotate the special methods with. So I personally prefer this one. If we think that introducing a new difference between impl. and ref. assemblies is a big problem, then I would probably vote for just allowing it on methods for everybody. I don't like introducing a new public attribute just for this. |
Yes, it is.
+1 |
57d1597
to
c36868a
Compare
I think these changes can be merged. The failures are below: There are 2 test failures which aren't related to this code change:
The
|
We need a way to add
DynamicallyAccessedMembersAttribute
to the "this" parameter for calls likeType.GetFields
. There's no way in C# to do this (and in fact even IL is a bit tricky in that regard), so the linker supports recognizing the attribute on a method itself, but only forSystem.Type
class. It then treats that attribute as if it's put on the "this" parameter.Fixes #36708