Skip to content
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

Support class target in RUC/RDC code fixers #107956

Merged
merged 3 commits into from
Sep 18, 2024
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@ protected enum AttributeableParentTargets
Property = 0x0002,
Field = 0x0004,
Event = 0x0008,
All = MethodOrConstructor | Property | Field | Event
Class = 0x0010,
All = MethodOrConstructor | Property | Field | Event | Class
}

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

case LocalFunctionStatementSyntax or BaseMethodDeclarationSyntax or AccessorDeclarationSyntax when targets.HasFlag (AttributeableParentTargets.MethodOrConstructor):
case PropertyDeclarationSyntax when targets.HasFlag (AttributeableParentTargets.Property):
case FieldDeclarationSyntax when targets.HasFlag (AttributeableParentTargets.Field):
case EventDeclarationSyntax when targets.HasFlag (AttributeableParentTargets.Event):
return (CSharpSyntaxNode) parentNode;
case PropertyDeclarationSyntax:
case EventDeclarationSyntax:
// If the attribute can be placed on a method but not directly on a property/event, we don't want to keep walking up
// the syntax tree to annotate the class. Instead the correct thing to do is to add accessor methods and annotate those.
// The code fixer doesn't support doing this automatically, so return null to indicate that the attribute can't be added.
if (targets.HasFlag (AttributeableParentTargets.MethodOrConstructor))
return null;

parentNode = parentNode.Parent;
break;
case LocalFunctionStatementSyntax or BaseMethodDeclarationSyntax or AccessorDeclarationSyntax when targets.HasFlag (AttributeableParentTargets.MethodOrConstructor):
case FieldDeclarationSyntax when targets.HasFlag (AttributeableParentTargets.Field):
case ClassDeclarationSyntax when targets.HasFlag (AttributeableParentTargets.Class):
return (CSharpSyntaxNode) parentNode;

default:
parentNode = parentNode.Parent;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public class RequiresDynamicCodeCodeFixProvider : BaseAttributeCodeFixProvider

private protected override string FullyQualifiedAttributeName => RequiresDynamicCodeAnalyzer.FullyQualifiedRequiresDynamicCodeAttribute;

private protected override AttributeableParentTargets AttributableParentTargets => AttributeableParentTargets.MethodOrConstructor;
private protected override AttributeableParentTargets AttributableParentTargets => AttributeableParentTargets.MethodOrConstructor | AttributeableParentTargets.Class;

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public sealed class RequiresUnreferencedCodeCodeFixProvider : BaseAttributeCodeF

private protected override string FullyQualifiedAttributeName => RequiresUnreferencedCodeAnalyzer.FullyQualifiedRequiresUnreferencedCodeAttribute;

private protected override AttributeableParentTargets AttributableParentTargets => AttributeableParentTargets.MethodOrConstructor;
private protected override AttributeableParentTargets AttributableParentTargets => AttributeableParentTargets.MethodOrConstructor | AttributeableParentTargets.Class;

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,46 @@ private int M2 {
return VerifyRequiresDynamicCodeCodeFix (src, fix, diag, Array.Empty<DiagnosticResult> ());
}

[Fact]
public Task FixInClass ()
{
var src = $$"""
using System;
using System.Diagnostics.CodeAnalysis;

public class C
{
[RequiresDynamicCodeAttribute("message")]
static int M1() => 0;

static int Field = M1();
}
""";

var fix = $$"""
using System;
using System.Diagnostics.CodeAnalysis;

[RequiresDynamicCode()]
public class C
{
[RequiresDynamicCodeAttribute("message")]
static int M1() => 0;

static int Field = M1();
}
""";
return VerifyRequiresDynamicCodeCodeFix (src, fix,
baselineExpected: new[] {
// /0/Test0.cs(9,21,9,25): warning IL2026: Using member 'C.M1()' which has 'RequiresDynamicCodeAttribute' can break functionality when trimming application code. message.
VerifyCS.Diagnostic(DiagnosticId.RequiresDynamicCode).WithSpan(9, 21, 9, 25).WithArguments("C.M1()", " message.", ""),
},
fixedExpected: new[] {
// /0/Test0.cs(4,2): error CS7036: There is no argument given that corresponds to the required parameter 'message' of 'RequiresDynamicCodeAttribute.RequiresDynamicCodeAttribute(string)'
DiagnosticResult.CompilerError("CS7036").WithSpan(4, 2, 4, 23).WithArguments("message", "System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute.RequiresDynamicCodeAttribute(string)"),
});
}

[Fact]
public Task MakeGenericTypeWithAllKnownTypes ()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,46 @@ private int M2 {
return VerifyRequiresUnreferencedCodeCodeFix (src, fix, diag, Array.Empty<DiagnosticResult> ());
}

[Fact]
public Task FixInClass ()
{
var src = $$"""
using System;
using System.Diagnostics.CodeAnalysis;

public class C
{
[RequiresUnreferencedCodeAttribute("message")]
static int M1() => 0;

static int Field = M1();
}
""";

var fix = $$"""
using System;
using System.Diagnostics.CodeAnalysis;

[RequiresUnreferencedCode()]
public class C
{
[RequiresUnreferencedCodeAttribute("message")]
static int M1() => 0;

static int Field = M1();
}
""";
return VerifyRequiresUnreferencedCodeCodeFix (src, fix,
baselineExpected: new[] {
// /0/Test0.cs(9,21): warning IL2026: Using member 'C.M1()' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. message.
VerifyCS.Diagnostic(DiagnosticId.RequiresUnreferencedCode).WithSpan(9, 21, 9, 25).WithArguments("C.M1()", " message.", "")
},
fixedExpected: new[] {
// /0/Test0.cs(4,2): error CS7036: There is no argument given that corresponds to the required parameter 'message' of 'RequiresUnreferencedCodeAttribute.RequiresUnreferencedCodeAttribute(string)'
DiagnosticResult.CompilerError("CS7036").WithSpan(4, 2, 4, 28).WithArguments("message", "System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute.RequiresUnreferencedCodeAttribute(string)"),
});
}

[Fact]
public Task TestMakeGenericMethodUsage ()
{
Expand Down
Loading