Skip to content

Commit 77ee357

Browse files
sbomerjtschuster
authored andcommitted
Support class target in RUC/RDC code fixers (#107956)
This adds support to the RequiresUnreferencedCode and RequiresDynamicCode code fixer for adding new annotations at the class level. This helps while annotating libraries where static field initializers had trim/aot warnings. --------- Co-authored-by: Jackson Schuster <[email protected]>
1 parent e30f446 commit 77ee357

File tree

5 files changed

+98
-5
lines changed

5 files changed

+98
-5
lines changed

src/tools/illink/src/ILLink.CodeFix/BaseAttributeCodeFixProvider.cs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,8 @@ protected enum AttributeableParentTargets
8686
Property = 0x0002,
8787
Field = 0x0004,
8888
Event = 0x0008,
89-
All = MethodOrConstructor | Property | Field | Event
89+
Class = 0x0010,
90+
All = MethodOrConstructor | Property | Field | Event | Class
9091
}
9192

9293
private static CSharpSyntaxNode? FindAttributableParent (SyntaxNode node, AttributeableParentTargets targets)
@@ -97,11 +98,23 @@ protected enum AttributeableParentTargets
9798
case LambdaExpressionSyntax:
9899
return null;
99100

100-
case LocalFunctionStatementSyntax or BaseMethodDeclarationSyntax or AccessorDeclarationSyntax when targets.HasFlag (AttributeableParentTargets.MethodOrConstructor):
101101
case PropertyDeclarationSyntax when targets.HasFlag (AttributeableParentTargets.Property):
102-
case FieldDeclarationSyntax when targets.HasFlag (AttributeableParentTargets.Field):
103102
case EventDeclarationSyntax when targets.HasFlag (AttributeableParentTargets.Event):
104103
return (CSharpSyntaxNode) parentNode;
104+
case PropertyDeclarationSyntax:
105+
case EventDeclarationSyntax:
106+
// If the attribute can be placed on a method but not directly on a property/event, we don't want to keep walking up
107+
// the syntax tree to annotate the class. Instead the correct thing to do is to add accessor methods and annotate those.
108+
// The code fixer doesn't support doing this automatically, so return null to indicate that the attribute can't be added.
109+
if (targets.HasFlag (AttributeableParentTargets.MethodOrConstructor))
110+
return null;
111+
112+
parentNode = parentNode.Parent;
113+
break;
114+
case LocalFunctionStatementSyntax or BaseMethodDeclarationSyntax or AccessorDeclarationSyntax when targets.HasFlag (AttributeableParentTargets.MethodOrConstructor):
115+
case FieldDeclarationSyntax when targets.HasFlag (AttributeableParentTargets.Field):
116+
case ClassDeclarationSyntax when targets.HasFlag (AttributeableParentTargets.Class):
117+
return (CSharpSyntaxNode) parentNode;
105118

106119
default:
107120
parentNode = parentNode.Parent;

src/tools/illink/src/ILLink.CodeFix/RequiresDynamicCodeCodeFixProvider.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public class RequiresDynamicCodeCodeFixProvider : BaseAttributeCodeFixProvider
2525

2626
private protected override string FullyQualifiedAttributeName => RequiresDynamicCodeAnalyzer.FullyQualifiedRequiresDynamicCodeAttribute;
2727

28-
private protected override AttributeableParentTargets AttributableParentTargets => AttributeableParentTargets.MethodOrConstructor;
28+
private protected override AttributeableParentTargets AttributableParentTargets => AttributeableParentTargets.MethodOrConstructor | AttributeableParentTargets.Class;
2929

3030
public sealed override Task RegisterCodeFixesAsync (CodeFixContext context) => BaseRegisterCodeFixesAsync (context);
3131

src/tools/illink/src/ILLink.CodeFix/RequiresUnreferencedCodeCodeFixProvider.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public sealed class RequiresUnreferencedCodeCodeFixProvider : BaseAttributeCodeF
2525

2626
private protected override string FullyQualifiedAttributeName => RequiresUnreferencedCodeAnalyzer.FullyQualifiedRequiresUnreferencedCodeAttribute;
2727

28-
private protected override AttributeableParentTargets AttributableParentTargets => AttributeableParentTargets.MethodOrConstructor;
28+
private protected override AttributeableParentTargets AttributableParentTargets => AttributeableParentTargets.MethodOrConstructor | AttributeableParentTargets.Class;
2929

3030
public sealed override Task RegisterCodeFixesAsync (CodeFixContext context) => BaseRegisterCodeFixesAsync (context);
3131

src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/RequiresDynamicCodeAnalyzerTests.cs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,46 @@ private int M2 {
348348
return VerifyRequiresDynamicCodeCodeFix (src, fix, diag, Array.Empty<DiagnosticResult> ());
349349
}
350350

351+
[Fact]
352+
public Task FixInClass ()
353+
{
354+
var src = $$"""
355+
using System;
356+
using System.Diagnostics.CodeAnalysis;
357+
358+
public class C
359+
{
360+
[RequiresDynamicCodeAttribute("message")]
361+
static int M1() => 0;
362+
363+
static int Field = M1();
364+
}
365+
""";
366+
367+
var fix = $$"""
368+
using System;
369+
using System.Diagnostics.CodeAnalysis;
370+
371+
[RequiresDynamicCode()]
372+
public class C
373+
{
374+
[RequiresDynamicCodeAttribute("message")]
375+
static int M1() => 0;
376+
377+
static int Field = M1();
378+
}
379+
""";
380+
return VerifyRequiresDynamicCodeCodeFix (src, fix,
381+
baselineExpected: new[] {
382+
// /0/Test0.cs(9,21,9,25): warning IL2026: Using member 'C.M1()' which has 'RequiresDynamicCodeAttribute' can break functionality when trimming application code. message.
383+
VerifyCS.Diagnostic(DiagnosticId.RequiresDynamicCode).WithSpan(9, 21, 9, 25).WithArguments("C.M1()", " message.", ""),
384+
},
385+
fixedExpected: new[] {
386+
// /0/Test0.cs(4,2): error CS7036: There is no argument given that corresponds to the required parameter 'message' of 'RequiresDynamicCodeAttribute.RequiresDynamicCodeAttribute(string)'
387+
DiagnosticResult.CompilerError("CS7036").WithSpan(4, 2, 4, 23).WithArguments("message", "System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute.RequiresDynamicCodeAttribute(string)"),
388+
});
389+
}
390+
351391
[Fact]
352392
public Task MakeGenericTypeWithAllKnownTypes ()
353393
{

src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/RequiresUnreferencedCodeAnalyzerTests.cs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,46 @@ private int M2 {
371371
return VerifyRequiresUnreferencedCodeCodeFix (src, fix, diag, Array.Empty<DiagnosticResult> ());
372372
}
373373

374+
[Fact]
375+
public Task FixInClass ()
376+
{
377+
var src = $$"""
378+
using System;
379+
using System.Diagnostics.CodeAnalysis;
380+
381+
public class C
382+
{
383+
[RequiresUnreferencedCodeAttribute("message")]
384+
static int M1() => 0;
385+
386+
static int Field = M1();
387+
}
388+
""";
389+
390+
var fix = $$"""
391+
using System;
392+
using System.Diagnostics.CodeAnalysis;
393+
394+
[RequiresUnreferencedCode()]
395+
public class C
396+
{
397+
[RequiresUnreferencedCodeAttribute("message")]
398+
static int M1() => 0;
399+
400+
static int Field = M1();
401+
}
402+
""";
403+
return VerifyRequiresUnreferencedCodeCodeFix (src, fix,
404+
baselineExpected: new[] {
405+
// /0/Test0.cs(9,21): warning IL2026: Using member 'C.M1()' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. message.
406+
VerifyCS.Diagnostic(DiagnosticId.RequiresUnreferencedCode).WithSpan(9, 21, 9, 25).WithArguments("C.M1()", " message.", "")
407+
},
408+
fixedExpected: new[] {
409+
// /0/Test0.cs(4,2): error CS7036: There is no argument given that corresponds to the required parameter 'message' of 'RequiresUnreferencedCodeAttribute.RequiresUnreferencedCodeAttribute(string)'
410+
DiagnosticResult.CompilerError("CS7036").WithSpan(4, 2, 4, 28).WithArguments("message", "System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute.RequiresUnreferencedCodeAttribute(string)"),
411+
});
412+
}
413+
374414
[Fact]
375415
public Task TestMakeGenericMethodUsage ()
376416
{

0 commit comments

Comments
 (0)