Skip to content

Commit

Permalink
Add support to detect unnecessary local SuppressMessageAttribute supp…
Browse files Browse the repository at this point in the history
…ressions

Fixes #44178

Builds on top of #44848, which added support to detect unnecessary pragma suppressions.
  • Loading branch information
mavasani committed Jul 7, 2020
1 parent 1d4a9ce commit 73fd51e
Show file tree
Hide file tree
Showing 9 changed files with 874 additions and 140 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@
namespace Microsoft.CodeAnalysis.CSharp.RemoveUnnecessarySuppressions
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
internal sealed class CSharpRemoveUnnecessaryPragmaSuppressionsDiagnosticAnalyzer
: AbstractRemoveUnnecessaryPragmaSuppressionsDiagnosticAnalyzer
internal sealed class CSharpRemoveUnnecessaryInlineSuppressionsDiagnosticAnalyzer
: AbstractRemoveUnnecessaryInlineSuppressionsDiagnosticAnalyzer
{
protected override string CompilerErrorCodePrefix => "CS";
protected override int CompilerErrorCodeDigitCount => 4;
protected override ISyntaxFacts SyntaxFacts => CSharpSyntaxFacts.Instance;
protected override ISemanticFacts SemanticFacts => CSharpSemanticFacts.Instance;
protected override (Assembly assembly, string typeName) GetCompilerDiagnosticAnalyzerInfo()
=> (typeof(SyntaxKind).Assembly, CompilerDiagnosticAnalyzerNames.CSharpCompilerAnalyzerTypeName);
}
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,18 @@
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Shared.Extensions;

namespace Microsoft.CodeAnalysis.RemoveUnnecessarySuppressions
{
[ExportCodeFixProvider(LanguageNames.CSharp, LanguageNames.VisualBasic, Name = PredefinedCodeFixProviderNames.RemoveUnnecessaryPragmaSuppressions), Shared]
internal sealed class RemoveUnnecessaryPragmaSuppressionsCodeFixProvider : SyntaxEditorBasedCodeFixProvider
internal sealed class RemoveUnnecessaryInlineSuppressionsCodeFixProvider : SyntaxEditorBasedCodeFixProvider
{
[ImportingConstructor]
[SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")]
public RemoveUnnecessaryPragmaSuppressionsCodeFixProvider()
public RemoveUnnecessaryInlineSuppressionsCodeFixProvider()
{
}

Expand All @@ -38,10 +39,12 @@ internal override CodeFixCategory CodeFixCategory
public override async Task RegisterCodeFixesAsync(CodeFixContext context)
{
var root = await context.Document.GetRequiredSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
var syntaxFacts = context.Document.GetRequiredLanguageService<ISyntaxFactsService>();
foreach (var diagnostic in context.Diagnostics)
{
// Defensive check that we are operating on the diagnostic on a pragma.
if (root.FindTrivia(diagnostic.Location.SourceSpan.Start).HasStructure)
if (root.FindNode(diagnostic.Location.SourceSpan) is { } node && syntaxFacts.IsAttribute(node) ||
root.FindTrivia(diagnostic.Location.SourceSpan.Start).HasStructure)
{
context.RegisterCodeFix(
new MyCodeAction(c => FixAsync(context.Document, diagnostic, c)),
Expand All @@ -58,22 +61,36 @@ protected override Task FixAllAsync(Document document, ImmutableArray<Diagnostic
// Our code fix ensures that we remove both the disable and restore directives with a single code fix application.
// So, we need to ensure that we do not attempt to remove the same node multiple times when performing a FixAll in document operation.
using var _ = PooledHashSet<SyntaxNode>.GetInstance(out var processedNodes);

var syntaxFacts = document.GetRequiredLanguageService<ISyntaxFactsService>();
foreach (var diagnostic in diagnostics)
{
RemoveNode(diagnostic.Location, editor, processedNodes);
RemoveNode(diagnostic.Location, editor, processedNodes, syntaxFacts);

foreach (var location in diagnostic.AdditionalLocations)
{
RemoveNode(location, editor, processedNodes);
RemoveNode(location, editor, processedNodes, syntaxFacts);
}
}

return Task.CompletedTask;

static void RemoveNode(Location location, SyntaxEditor editor, HashSet<SyntaxNode> processedNodes)
static void RemoveNode(
Location location,
SyntaxEditor editor,
HashSet<SyntaxNode> processedNodes,
ISyntaxFacts syntaxFacts)
{
var node = editor.OriginalRoot.FindTrivia(location.SourceSpan.Start).GetStructure()!;
SyntaxNode node;
if (editor.OriginalRoot.FindNode(location.SourceSpan) is { } attribute &&
syntaxFacts.IsAttribute(attribute))
{
node = attribute;
}
else
{
node = editor.OriginalRoot.FindTrivia(location.SourceSpan.Start).GetStructure()!;
}

if (processedNodes.Add(node))
{
editor.RemoveNode(node);
Expand All @@ -84,7 +101,7 @@ static void RemoveNode(Location location, SyntaxEditor editor, HashSet<SyntaxNod
private class MyCodeAction : CustomCodeActions.DocumentChangeAction
{
public MyCodeAction(Func<CancellationToken, Task<Document>> createChangedDocument)
: base(AnalyzersResources.Remove_unnecessary_suppression, createChangedDocument, nameof(RemoveUnnecessaryPragmaSuppressionsCodeFixProvider))
: base(AnalyzersResources.Remove_unnecessary_suppression, createChangedDocument, nameof(RemoveUnnecessaryInlineSuppressionsCodeFixProvider))
{
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,17 @@ Imports Microsoft.CodeAnalysis.VisualBasic.LanguageServices
Namespace Microsoft.CodeAnalysis.VisualBasic.RemoveUnnecessarySuppressions

<DiagnosticAnalyzer(LanguageNames.VisualBasic)>
Friend NotInheritable Class VisualBasicRemoveUnnecessaryPragmaSuppressionsDiagnosticAnalyzer
Inherits AbstractRemoveUnnecessaryPragmaSuppressionsDiagnosticAnalyzer
Friend NotInheritable Class VisualBasicRemoveUnnecessaryInlineSuppressionsDiagnosticAnalyzer
Inherits AbstractRemoveUnnecessaryInlineSuppressionsDiagnosticAnalyzer

Protected Overrides ReadOnly Property CompilerErrorCodePrefix As String = "BC"

Protected Overrides ReadOnly Property CompilerErrorCodeDigitCount As Integer = 5

Protected Overrides ReadOnly Property SyntaxFacts As ISyntaxFacts = VisualBasicSyntaxFacts.Instance

Protected Overrides ReadOnly Property SemanticFacts As ISemanticFacts = VisualBasicSemanticFacts.Instance

Protected Overrides Function GetCompilerDiagnosticAnalyzerInfo() As (assembly As Assembly, typeName As String)
Return (GetType(SyntaxKind).Assembly, CompilerDiagnosticAnalyzerNames.VisualBasicCompilerAnalyzerTypeName)
End Function
Expand Down
Loading

0 comments on commit 73fd51e

Please sign in to comment.