Skip to content
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
19 changes: 12 additions & 7 deletions src/ILLink.CodeFix/BaseAttributeCodeFixProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,22 @@ public sealed override FixAllProvider GetFixAllProvider ()
protected async Task BaseRegisterCodeFixesAsync (CodeFixContext context)
{
var document = context.Document;
var root = await document.GetSyntaxRootAsync (context.CancellationToken).ConfigureAwait (false);
if (await document.GetSyntaxRootAsync (context.CancellationToken).ConfigureAwait (false) is not { } root)
return;
var diagnostic = context.Diagnostics.First ();
SyntaxNode targetNode = root!.FindNode (diagnostic.Location.SourceSpan);
SyntaxNode targetNode = root.FindNode (diagnostic.Location.SourceSpan, getInnermostNodeForTie: true);
if (FindAttributableParent (targetNode, AttributableParentTargets) is not SyntaxNode attributableNode)
return;

var model = await document.GetSemanticModelAsync (context.CancellationToken).ConfigureAwait (false);
var targetSymbol = model!.GetSymbolInfo (targetNode).Symbol!;
if (await document.GetSemanticModelAsync (context.CancellationToken).ConfigureAwait (false) is not { } model)
return;
if (model.GetSymbolInfo (targetNode).Symbol is not { } targetSymbol)
return;
if (model.Compilation.GetTypeByMetadataName (FullyQualifiedAttributeName) is not { } attributeSymbol)
return;
// N.B. May be null for FieldDeclaration, since field declarations can declare multiple variables
var attributableSymbol = model.GetDeclaredSymbol (attributableNode);

var attributableSymbol = model!.GetDeclaredSymbol (attributableNode)!;
var attributeSymbol = model!.Compilation.GetTypeByMetadataName (FullyQualifiedAttributeName)!;
var attributeArguments = GetAttributeArguments (attributableSymbol, targetSymbol, SyntaxGenerator.GetGenerator (document), diagnostic);
var codeFixTitle = CodeFixTitle.ToString ();

Expand Down Expand Up @@ -104,7 +109,7 @@ protected enum AttributeableParentTargets
}

protected abstract SyntaxNode[] GetAttributeArguments (
ISymbol attributableSymbol,
ISymbol? attributableSymbol,
ISymbol targetSymbol,
SyntaxGenerator syntaxGenerator,
Diagnostic diagnostic);
Expand Down
2 changes: 1 addition & 1 deletion src/ILLink.CodeFix/RequiresAssemblyFilesCodeFixProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public class RequiresAssemblyFilesCodeFixProvider : BaseAttributeCodeFixProvider

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

protected override SyntaxNode[] GetAttributeArguments (ISymbol attributableSymbol, ISymbol targetSymbol, SyntaxGenerator syntaxGenerator, Diagnostic diagnostic)
protected override SyntaxNode[] GetAttributeArguments (ISymbol? attributableSymbol, ISymbol targetSymbol, SyntaxGenerator syntaxGenerator, Diagnostic diagnostic)
{
var symbolDisplayName = targetSymbol.GetDisplayName ();
if (string.IsNullOrEmpty (symbolDisplayName) || HasPublicAccessibility (attributableSymbol))
Expand Down
2 changes: 1 addition & 1 deletion src/ILLink.CodeFix/RequiresDynamicCodeCodeFixProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public class RequiresDynamicCodeCodeFixProvider : BaseAttributeCodeFixProvider

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

protected override SyntaxNode[] GetAttributeArguments (ISymbol attributableSymbol, ISymbol targetSymbol, SyntaxGenerator syntaxGenerator, Diagnostic diagnostic)
protected override SyntaxNode[] GetAttributeArguments (ISymbol? attributableSymbol, ISymbol targetSymbol, SyntaxGenerator syntaxGenerator, Diagnostic diagnostic)
{
var symbolDisplayName = targetSymbol.GetDisplayName ();
if (string.IsNullOrEmpty (symbolDisplayName) || HasPublicAccessibility (attributableSymbol))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public class RequiresUnreferencedCodeCodeFixProvider : BaseAttributeCodeFixProvi

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

protected override SyntaxNode[] GetAttributeArguments (ISymbol attributableSymbol, ISymbol targetSymbol, SyntaxGenerator syntaxGenerator, Diagnostic diagnostic)
protected override SyntaxNode[] GetAttributeArguments (ISymbol? attributableSymbol, ISymbol targetSymbol, SyntaxGenerator syntaxGenerator, Diagnostic diagnostic)
{
var symbolDisplayName = targetSymbol.GetDisplayName ();
if (string.IsNullOrEmpty (symbolDisplayName) || HasPublicAccessibility (attributableSymbol))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public sealed override ImmutableArray<string> FixableDiagnosticIds

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

protected override SyntaxNode[] GetAttributeArguments (ISymbol attributableSymbol, ISymbol targetSymbol, SyntaxGenerator syntaxGenerator, Diagnostic diagnostic)
protected override SyntaxNode[] GetAttributeArguments (ISymbol? attributableSymbol, ISymbol targetSymbol, SyntaxGenerator syntaxGenerator, Diagnostic diagnostic)
{
// Category of the attribute
var ruleCategory = syntaxGenerator.AttributeArgument (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,43 @@ static Task VerifyRequiresUnreferencedCodeCodeFix (
}


[Fact]
public async Task WarningInArgument ()
{
var test = """
using System.Diagnostics.CodeAnalysis;
public class C
{
[RequiresUnreferencedCode("message")]
public int M1() => 0;
public void M2(int x)
{
}
public void M3() => M2(M1());
}
""";
var fixtest = """
using System.Diagnostics.CodeAnalysis;
public class C
{
[RequiresUnreferencedCode("message")]
public int M1() => 0;
public void M2(int x)
{
}

[RequiresUnreferencedCode()]
public void M3() => M2(M1());
}
""";
await VerifyRequiresUnreferencedCodeCodeFix (test, fixtest, new[] {
// /0/Test0.cs(9,25): warning IL2026: Using member 'C.M1()' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. message.
VerifyCS.Diagnostic(DiagnosticId.RequiresUnreferencedCode).WithSpan(9, 25, 9, 29).WithArguments("C.M1()", " message.", ""),
}, new[] {
// /0/Test0.cs(10,6): error CS7036: There is no argument given that corresponds to the required formal parameter 'message' of 'RequiresUnreferencedCodeAttribute.RequiresUnreferencedCodeAttribute(string)'
DiagnosticResult.CompilerError("CS7036").WithSpan(10, 6, 10, 32).WithArguments("message", "System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute.RequiresUnreferencedCodeAttribute(string)"),
});
}

[Fact]
public async Task SimpleDiagnosticFix ()
Expand Down