未验证 提交 1a70791b 编写于 作者: M msftbot[bot] 提交者: GitHub

Merge pull request #44287 from mavasani/Issue44176

Add analyzer/fixer for unnecessary global SuppressMessageAttributes with invalid 'Scope' and/or 'Target'
......@@ -18,6 +18,7 @@
<Compile Include="$(MSBuildThisFileDirectory)AddAccessibilityModifiers\CSharpAddAccessibilityModifiersDiagnosticAnalyzer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)AddBraces\CSharpAddBracesDiagnosticAnalyzer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)AddRequiredParentheses\CSharpAddRequiredPatternParenthesesDiagnosticAnalyzer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)RemoveUnnecessarySuppressions\CSharpRemoveUnnecessarySuppressionsDiagnosticAnalyzer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)RemoveUnnecessaryParentheses\CSharpRemoveUnnecessaryPatternParenthesesDiagnosticAnalyzer.cs" />
<Compile Include="..\..\..\Analyzers\CSharp\Analyzers\AddRequiredParentheses\CSharpAddRequiredExpressionParenthesesDiagnosticAnalyzer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ConvertAnonymousTypeToTuple\CSharpConvertAnonymousTypeToTupleDiagnosticAnalyzer.cs" />
......
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.RemoveUnnecessarySuppressions;
#nullable enable
namespace Microsoft.CodeAnalysis.CSharp.RemoveUnnecessarySuppressions
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
internal sealed class CSharpRemoveUnnecessarySuppressionsDiagnosticAnalyzer
: AbstractRemoveUnnecessarySuppressionsDiagnosticAnalyzer
{
protected override void RegisterAttributeSyntaxAction(CompilationStartAnalysisContext context, CompilationAnalyzer compilationAnalyzer)
{
context.RegisterSyntaxNodeAction(context =>
{
var attributeList = (AttributeListSyntax)context.Node;
switch (attributeList.Target?.Identifier.Kind())
{
case SyntaxKind.AssemblyKeyword:
case SyntaxKind.ModuleKeyword:
foreach (var attribute in attributeList.Attributes)
{
compilationAnalyzer.AnalyzeAssemblyOrModuleAttribute(attribute, context.SemanticModel, context.ReportDiagnostic, context.CancellationToken);
}
break;
}
}, SyntaxKind.AttributeList);
}
}
}
......@@ -25,6 +25,7 @@
<Compile Include="$(MSBuildThisFileDirectory)MisplacedUsingDirectives\MisplacedUsingDirectivesCodeFixProviderTests.cs" />
<Compile Include="$(MSBuildThisFileDirectory)OrderModifiers\OrderModifiersCompilerErrorTests.cs" />
<Compile Include="$(MSBuildThisFileDirectory)OrderModifiers\OrderModifiersTests.cs" />
<Compile Include="$(MSBuildThisFileDirectory)RemoveUnnecessarySuppressions\RemoveUnnecessarySuppressionsTests.cs" />
<Compile Include="$(MSBuildThisFileDirectory)RemoveUnnecessaryParentheses\RemoveUnnecessaryPatternParenthesesTests.cs" />
<Compile Include="$(MSBuildThisFileDirectory)RemoveUnreachableCode\RemoveUnreachableCodeTests.cs" />
<Compile Include="$(MSBuildThisFileDirectory)SimplifyBooleanExpression\SimplifyConditionalTests.cs" />
......
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
using VerifyCS = Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions.CSharpCodeFixVerifier<
Microsoft.CodeAnalysis.CSharp.RemoveUnnecessarySuppressions.CSharpRemoveUnnecessarySuppressionsDiagnosticAnalyzer,
Microsoft.CodeAnalysis.RemoveUnnecessarySuppressions.RemoveUnnecessarySuppressionsCodeFixProvider>;
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.RemoveUnnecessarySuppressions
{
[Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessarySuppressions)]
[WorkItem(44176, "https://github.com/dotnet/roslyn/issues/44176")]
public class RemoveUnnecessarySuppressionsTests
{
[Fact]
public void TestStandardProperties()
=> VerifyCS.VerifyStandardProperties();
[Theory]
// Field
[InlineData(@"Scope = ""member""", @"Target = ""~F:N.C.F""", "assembly")]
// Property
[InlineData(@"Scope = ""member""", @"Target = ""~P:N.C.P""", "assembly")]
// Method
[InlineData(@"Scope = ""member""", @"Target = ""~M:N.C.M()""", "assembly")]
// Type
[InlineData(@"Scope = ""member""", @"Target = ""~T:N.C""", "assembly")]
// Namespace
[InlineData(@"Scope = ""namespace""", @"Target = ""~N:N""", "assembly")]
// NamespaceAndDescendants
[InlineData(@"Scope = ""namespaceanddescendants""", @"Target = ""~N:N""", "assembly")]
// Module - no scope, no target
[InlineData(null, null, "assembly")]
// Module - no target
[InlineData(@"Scope = ""module""", null, "assembly")]
// Module - null target
[InlineData(@"Scope = ""module""", @"Target = null", "assembly")]
// Resource - not handled
[InlineData(@"Scope = ""resource""", @"Target = """"", "assembly")]
// 'module' attribute target
[InlineData(@"Scope = ""member""", @"Target = ""~M:N.C.M()""", "module")]
// Member with non-matching scope (seems to be respected by suppression decoder)
[InlineData(@"Scope = ""type""", @"Target = ""~M:N.C.M()""", "assembly")]
[InlineData(@"Scope = ""namespace""", @"Target = ""~F:N.C.F""", "assembly")]
// Case insensitive scope
[InlineData(@"Scope = ""Member""", @"Target = ""~F:N.C.F""", "assembly")]
[InlineData(@"Scope = ""MEMBER""", @"Target = ""~F:N.C.F""", "assembly")]
public async Task ValidSuppressions(string? scope, string? target, string attributeTarget)
{
var scopeString = scope != null ? $@", {scope}" : string.Empty;
var targetString = target != null ? $@", {target}" : string.Empty;
var input = $@"
[{attributeTarget}: System.Diagnostics.CodeAnalysis.SuppressMessage(""Category"", ""Id: Title"", Justification = ""Pending""{scopeString}{targetString})]
namespace N
{{
class C
{{
public int F;
public int P {{ get; }}
public void M() {{ }}
}}
}}";
await VerifyCS.VerifyCodeFixAsync(input, input);
}
[Theory]
// Field - no matching symbol
[InlineData(@"Scope = ""member""", @"Target = ""~F:N.C.F2""", "assembly")]
// Field - no matching symbol (case insensitive)
[InlineData(@"Scope = ""Member""", @"Target = ""~F:N.C.F2""", "assembly")]
[InlineData(@"Scope = ""MEMBER""", @"Target = ""~F:N.C.F2""", "assembly")]
// Property - invalid scope
[InlineData(@"Scope = ""invalid""", @"Target = ""~P:N.C.P""", "assembly")]
// Method - wrong signature
[InlineData(@"Scope = ""member""", @"Target = ""~M:N.C.M(System.Int32)""", "assembly")]
// Method - module scope
[InlineData(@"Scope = ""module""", @"Target = ""~M:N.C.M()""", "assembly")]
// Method - null scope
[InlineData(@"Scope = null", @"Target = ""~M:N.C.M()""", "assembly")]
// Method - no scope
[InlineData(null, @"Target = ""~M:N.C.M()""", "assembly")]
// Member scope - null target
[InlineData(@"Scope = ""member""", @"Target = null", "assembly")]
// Member scope - no target
[InlineData(@"Scope = ""member""", null, "assembly")]
// Type - no matching namespace
[InlineData(@"Scope = ""type""", @"Target = ""~T:N2.C""", "assembly")]
// Namespace - extra namespace qualification
[InlineData(@"Scope = ""namespace""", @"Target = ""~N:N.N2""", "assembly")]
// NamespaceAndDescendants - empty target
[InlineData(@"Scope = ""namespaceanddescendants""", @"Target = """"", "assembly")]
// Module - no scope, empty target
[InlineData(null, @"Target = """"", "assembly")]
// Module - no scope, non-empty target
[InlineData(null, @"Target = ""~T:N.C""", "assembly")]
// Module scope, empty target
[InlineData(@"Scope = ""module""", @"Target = """"", "assembly")]
// Module no scope, non-empty target
[InlineData(@"Scope = ""module""", @"Target = ""~T:N.C""", "assembly")]
public async Task InvalidSuppressions(string? scope, string? target, string attributeTarget)
{
var scopeString = scope != null ? $@", {scope}" : string.Empty;
var targetString = target != null ? $@", {target}" : string.Empty;
var input = $@"
[{attributeTarget}: [|System.Diagnostics.CodeAnalysis.SuppressMessage(""Category"", ""Id: Title"", Justification = ""Pending""{scopeString}{targetString})|]]
namespace N
{{
class C
{{
public int F;
public int P {{ get; }}
public void M() {{ }}
}}
}}";
var fixedCode = $@"
namespace N
{{
class C
{{
public int F;
public int P {{ get; }}
public void M() {{ }}
}}
}}";
await VerifyCS.VerifyCodeFixAsync(input, fixedCode);
}
[Fact]
public async Task ValidAndInvalidSuppressions()
{
var attributePrefix = @"System.Diagnostics.CodeAnalysis.SuppressMessage(""Category"", ""Id: Title"", Justification = ""Pending""";
var validSuppression = $@"{attributePrefix}, Scope = ""member"", Target = ""~T:C"")";
var invalidSuppression = $@"[|{attributePrefix}, Scope = ""member"", Target = """")|]";
var input = $@"
[assembly: {validSuppression}]
[assembly: {invalidSuppression}]
[assembly: {validSuppression}, {validSuppression}]
[assembly: {invalidSuppression}, {invalidSuppression}]
[assembly: {validSuppression}, {invalidSuppression}]
[assembly: {invalidSuppression}, {validSuppression}]
[assembly: {invalidSuppression}, {validSuppression}, {invalidSuppression}, {validSuppression}]
class C {{ }}
";
var fixedCode = $@"
[assembly: {validSuppression}]
[assembly: {validSuppression}, {validSuppression}]
[assembly: {validSuppression}]
[assembly: {validSuppression}]
[assembly: {validSuppression}, {validSuppression}]
class C {{ }}
";
await VerifyCS.VerifyCodeFixAsync(input, fixedCode);
}
[Theory]
[InlineData("")]
[InlineData(@", Scope = ""member"", Target = ""~M:C.M()""")]
[InlineData(@", Scope = ""invalid"", Target = ""invalid""")]
public async Task LocalSuppressions(string scopeAndTarget)
{
var input = $@"
[System.Diagnostics.CodeAnalysis.SuppressMessage(""Category"", ""Id: Title"", Justification = ""Pending""{scopeAndTarget})]
class C
{{
public void M() {{ }}
}}";
await VerifyCS.VerifyCodeFixAsync(input, input);
}
}
}
......@@ -30,6 +30,10 @@
<Compile Include="$(MSBuildThisFileDirectory)Helpers\DiagnosticHelper.cs" />
<Compile Include="$(MSBuildThisFileDirectory)IDEDiagnosticIds.cs" />
<Compile Include="$(MSBuildThisFileDirectory)IDEDiagnosticIdToOptionMappingHelper.cs" />
<Compile Include="$(MSBuildThisFileDirectory)RemoveUnnecessarySuppressions\SuppressMessageAttributeState.cs" />
<Compile Include="$(MSBuildThisFileDirectory)RemoveUnnecessarySuppressions\AbstractRemoveUnnecessarySuppressionsDiagnosticAnalyzer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)..\..\..\Compilers\Core\Portable\DiagnosticAnalyzer\SuppressMessageAttributeState.TargetScope.cs" Link="RemoveUnnecessarySuppressions\SuppressMessageAttributeState.TargetScope.cs" />
<Compile Include="$(MSBuildThisFileDirectory)..\..\..\Compilers\Core\Portable\DiagnosticAnalyzer\SuppressMessageAttributeState.TargetSymbolResolver.cs" Link="RemoveUnnecessarySuppressions\SuppressMessageAttributeState.TargetSymbolResolver.cs" />
<Compile Include="$(MSBuildThisFileDirectory)MakeFieldReadonly\MakeFieldReadonlyDiagnosticAnalyzer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)NamingStyle\NamingStyleDiagnosticAnalyzerBase.cs" />
<Compile Include="$(MSBuildThisFileDirectory)OrderModifiers\AbstractOrderModifiersDiagnosticAnalyzer.cs" />
......
......@@ -307,4 +307,13 @@
<data name="Conditional_expression_can_be_simplified" xml:space="preserve">
<value>Conditional expression can be simplified</value>
</data>
<data name="Invalid_global_SuppressMessageAttribute" xml:space="preserve">
<value>Invalid global 'SuppressMessageAttribute'</value>
</data>
<data name="Invalid_scope_for_SuppressMessageAttribute" xml:space="preserve">
<value>Invalid scope for 'SuppressMessageAttribute'</value>
</data>
<data name="Invalid_or_missing_target_for_SuppressMessageAttribute" xml:space="preserve">
<value>Invalid or missing target for 'SuppressMessageAttribute'</value>
</data>
</root>
\ No newline at end of file
......@@ -130,6 +130,8 @@ internal static class IDEDiagnosticIds
public const string SimplifyConditionalExpressionDiagnosticId = "IDE0075";
public const string InvalidSuppressMessageAttributeDiagnosticId = "IDE0076";
// Analyzer error Ids
public const string AnalyzerChangedId = "IDE1001";
public const string AnalyzerDependencyConflictId = "IDE1002";
......
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System;
using System.Collections.Immutable;
using System.Threading;
using Microsoft.CodeAnalysis.CodeQuality;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Shared.Extensions;
namespace Microsoft.CodeAnalysis.RemoveUnnecessarySuppressions
{
internal abstract class AbstractRemoveUnnecessarySuppressionsDiagnosticAnalyzer
: AbstractCodeQualityDiagnosticAnalyzer
{
private static readonly LocalizableResourceString s_localizableTitle = new LocalizableResourceString(
nameof(AnalyzersResources.Invalid_global_SuppressMessageAttribute), AnalyzersResources.ResourceManager, typeof(AnalyzersResources));
private static readonly LocalizableResourceString s_localizableInvalidScopeMessage = new LocalizableResourceString(
nameof(AnalyzersResources.Invalid_scope_for_SuppressMessageAttribute), AnalyzersResources.ResourceManager, typeof(AnalyzersResources));
private static readonly LocalizableResourceString s_localizableInvalidOrMissingTargetMessage = new LocalizableResourceString(
nameof(AnalyzersResources.Invalid_or_missing_target_for_SuppressMessageAttribute), AnalyzersResources.ResourceManager, typeof(AnalyzersResources));
private static readonly DiagnosticDescriptor s_invalidScopeDescriptor = CreateDescriptor(
IDEDiagnosticIds.InvalidSuppressMessageAttributeDiagnosticId, s_localizableTitle, s_localizableInvalidScopeMessage, isUnnecessary: true);
private static readonly DiagnosticDescriptor s_invalidOrMissingTargetDescriptor = CreateDescriptor(
IDEDiagnosticIds.InvalidSuppressMessageAttributeDiagnosticId, s_localizableTitle, s_localizableInvalidOrMissingTargetMessage, isUnnecessary: true);
public AbstractRemoveUnnecessarySuppressionsDiagnosticAnalyzer()
: base(ImmutableArray.Create(s_invalidScopeDescriptor, s_invalidOrMissingTargetDescriptor), GeneratedCodeAnalysisFlags.None)
{
}
protected abstract void RegisterAttributeSyntaxAction(CompilationStartAnalysisContext context, CompilationAnalyzer compilationAnalyzer);
public sealed override DiagnosticAnalyzerCategory GetAnalyzerCategory() => DiagnosticAnalyzerCategory.SemanticDocumentAnalysis;
protected sealed override void InitializeWorker(AnalysisContext context)
{
context.RegisterCompilationStartAction(context =>
{
var suppressMessageAttributeType = context.Compilation.SuppressMessageAttributeType();
if (suppressMessageAttributeType == null)
{
return;
}
RegisterAttributeSyntaxAction(context, new CompilationAnalyzer(context.Compilation, suppressMessageAttributeType));
});
}
protected sealed class CompilationAnalyzer
{
private readonly SuppressMessageAttributeState _state;
public CompilationAnalyzer(Compilation compilation, INamedTypeSymbol suppressMessageAttributeType)
{
_state = new SuppressMessageAttributeState(compilation, suppressMessageAttributeType);
}
public void AnalyzeAssemblyOrModuleAttribute(SyntaxNode attributeSyntax, SemanticModel model, Action<Diagnostic> reportDiagnostic, CancellationToken cancellationToken)
{
if (!_state.IsSuppressMessageAttributeWithNamedArguments(attributeSyntax, model, cancellationToken, out var namedAttributeArguments))
{
return;
}
DiagnosticDescriptor rule;
if (_state.HasInvalidScope(namedAttributeArguments, out var targetScope))
{
rule = s_invalidScopeDescriptor;
}
else if (_state.HasInvalidOrMissingTarget(namedAttributeArguments, targetScope))
{
rule = s_invalidOrMissingTargetDescriptor;
}
else
{
return;
}
reportDiagnostic(Diagnostic.Create(rule, attributeSyntax.GetLocation()));
}
}
}
}
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Threading;
using Microsoft.CodeAnalysis.Operations;
using Microsoft.CodeAnalysis.PooledObjects;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Diagnostics
{
internal partial class SuppressMessageAttributeState
{
internal const string SuppressMessageScope = "Scope";
internal const string SuppressMessageTarget = "Target";
private static readonly ImmutableDictionary<string, TargetScope> s_targetScopesMap = CreateTargetScopesMap();
private static readonly ObjectPool<List<ISymbol>> s_listPool = new ObjectPool<List<ISymbol>>(() => new List<ISymbol>());
private readonly Compilation _compilation;
private readonly INamedTypeSymbol _suppressMessageAttributeType;
public SuppressMessageAttributeState(Compilation compilation, INamedTypeSymbol suppressMessageAttributeType)
{
_compilation = compilation;
_suppressMessageAttributeType = suppressMessageAttributeType;
}
private static ImmutableDictionary<string, TargetScope> CreateTargetScopesMap()
{
var builder = ImmutableDictionary.CreateBuilder<string, TargetScope>(StringComparer.OrdinalIgnoreCase);
#pragma warning disable CS8605 // Unboxing a possibly null value.
foreach (TargetScope targetScope in Enum.GetValues(typeof(TargetScope)))
#pragma warning restore CS8605 // Unboxing a possibly null value.
{
if (targetScope == TargetScope.None)
{
continue;
}
builder.Add(targetScope.ToString(), targetScope);
}
return builder.ToImmutable();
}
public bool IsSuppressMessageAttributeWithNamedArguments(
SyntaxNode attributeSyntax,
SemanticModel model,
CancellationToken cancellationToken,
out ImmutableArray<(string name, IOperation value)> namedAttributeArguments)
{
var attribute = model.GetOperation(attributeSyntax, cancellationToken);
if (attribute == null)
{
namedAttributeArguments = ImmutableArray<(string name, IOperation value)>.Empty;
return false;
}
// Workaround for https://github.com/dotnet/roslyn/issues/18198
// Use 'IOperation.Children' to get named attribute arguments.
// Each named attribute argument is represented as an 'ISimpleAssignmentOperation'
// with a constant value assignment to an 'IPropertyReferenceOperation' in the operation tree.
using var _ = ArrayBuilder<(string name, IOperation value)>.GetInstance(out var builder);
foreach (var childOperation in attribute.Children)
{
if (childOperation is ISimpleAssignmentOperation simpleAssignment &&
simpleAssignment.Target is IPropertyReferenceOperation propertyReference &&
_suppressMessageAttributeType.Equals(propertyReference.Property.ContainingType))
{
builder.Add((propertyReference.Property.Name, simpleAssignment.Value));
}
}
namedAttributeArguments = builder.ToImmutable();
return namedAttributeArguments.Length > 0;
}
public bool HasInvalidScope(ImmutableArray<(string name, IOperation value)> namedAttributeArguments, out TargetScope targetScope)
{
if (!TryGetNamedArgument(namedAttributeArguments, SuppressMessageScope, out var scopeString) ||
RoslynString.IsNullOrEmpty(scopeString))
{
// Missing/Null/Empty scope values are treated equivalent to a compilation wide suppression.
targetScope = TargetScope.Module;
}
else if (!s_targetScopesMap.TryGetValue(scopeString, out targetScope))
{
targetScope = TargetScope.None;
return true;
}
return false;
}
public bool HasInvalidOrMissingTarget(ImmutableArray<(string name, IOperation value)> namedAttributeArguments, TargetScope targetScope)
{
if (targetScope == TargetScope.Resource)
{
// Legacy scope which we do not handle.
return false;
}
if (!TryGetNamedArgument(namedAttributeArguments, SuppressMessageTarget, out var targetSymbolString))
{
targetSymbolString = null;
}
if (targetScope == TargetScope.Module)
{
// Compilation wide suppression with a non-null target is considered invalid.
return targetSymbolString != null;
}
var resolvedSymbols = s_listPool.Allocate();
try
{
var resolver = new TargetSymbolResolver(_compilation, targetScope, targetSymbolString);
resolvedSymbols.Clear();
resolver.Resolve(resolvedSymbols);
return resolvedSymbols.Count == 0;
}
finally
{
s_listPool.Free(resolvedSymbols);
}
}
private bool TryGetNamedArgument(ImmutableArray<(string name, IOperation value)> namedAttributeArguments, string argumentName, out string? argumentValue)
{
foreach (var (name, value) in namedAttributeArguments)
{
if (name == argumentName &&
value.ConstantValue.HasValue &&
value.ConstantValue.Value is string stringValue)
{
argumentValue = stringValue;
return true;
}
}
argumentValue = null;
return false;
}
}
}
......@@ -97,6 +97,21 @@
<target state="new">Invalid format string</target>
<note />
</trans-unit>
<trans-unit id="Invalid_global_SuppressMessageAttribute">
<source>Invalid global 'SuppressMessageAttribute'</source>
<target state="new">Invalid global 'SuppressMessageAttribute'</target>
<note />
</trans-unit>
<trans-unit id="Invalid_or_missing_target_for_SuppressMessageAttribute">
<source>Invalid or missing target for 'SuppressMessageAttribute'</source>
<target state="new">Invalid or missing target for 'SuppressMessageAttribute'</target>
<note />
</trans-unit>
<trans-unit id="Invalid_scope_for_SuppressMessageAttribute">
<source>Invalid scope for 'SuppressMessageAttribute'</source>
<target state="new">Invalid scope for 'SuppressMessageAttribute'</target>
<note />
</trans-unit>
<trans-unit id="Make_field_readonly">
<source>Make field readonly</source>
<target state="new">Make field readonly</target>
......
......@@ -97,6 +97,21 @@
<target state="new">Invalid format string</target>
<note />
</trans-unit>
<trans-unit id="Invalid_global_SuppressMessageAttribute">
<source>Invalid global 'SuppressMessageAttribute'</source>
<target state="new">Invalid global 'SuppressMessageAttribute'</target>
<note />
</trans-unit>
<trans-unit id="Invalid_or_missing_target_for_SuppressMessageAttribute">
<source>Invalid or missing target for 'SuppressMessageAttribute'</source>
<target state="new">Invalid or missing target for 'SuppressMessageAttribute'</target>
<note />
</trans-unit>
<trans-unit id="Invalid_scope_for_SuppressMessageAttribute">
<source>Invalid scope for 'SuppressMessageAttribute'</source>
<target state="new">Invalid scope for 'SuppressMessageAttribute'</target>
<note />
</trans-unit>
<trans-unit id="Make_field_readonly">
<source>Make field readonly</source>
<target state="new">Make field readonly</target>
......
......@@ -97,6 +97,21 @@
<target state="new">Invalid format string</target>
<note />
</trans-unit>
<trans-unit id="Invalid_global_SuppressMessageAttribute">
<source>Invalid global 'SuppressMessageAttribute'</source>
<target state="new">Invalid global 'SuppressMessageAttribute'</target>
<note />
</trans-unit>
<trans-unit id="Invalid_or_missing_target_for_SuppressMessageAttribute">
<source>Invalid or missing target for 'SuppressMessageAttribute'</source>
<target state="new">Invalid or missing target for 'SuppressMessageAttribute'</target>
<note />
</trans-unit>
<trans-unit id="Invalid_scope_for_SuppressMessageAttribute">
<source>Invalid scope for 'SuppressMessageAttribute'</source>
<target state="new">Invalid scope for 'SuppressMessageAttribute'</target>
<note />
</trans-unit>
<trans-unit id="Make_field_readonly">
<source>Make field readonly</source>
<target state="new">Make field readonly</target>
......
......@@ -97,6 +97,21 @@
<target state="new">Invalid format string</target>
<note />
</trans-unit>
<trans-unit id="Invalid_global_SuppressMessageAttribute">
<source>Invalid global 'SuppressMessageAttribute'</source>
<target state="new">Invalid global 'SuppressMessageAttribute'</target>
<note />
</trans-unit>
<trans-unit id="Invalid_or_missing_target_for_SuppressMessageAttribute">
<source>Invalid or missing target for 'SuppressMessageAttribute'</source>
<target state="new">Invalid or missing target for 'SuppressMessageAttribute'</target>
<note />
</trans-unit>
<trans-unit id="Invalid_scope_for_SuppressMessageAttribute">
<source>Invalid scope for 'SuppressMessageAttribute'</source>
<target state="new">Invalid scope for 'SuppressMessageAttribute'</target>
<note />
</trans-unit>
<trans-unit id="Make_field_readonly">
<source>Make field readonly</source>
<target state="new">Make field readonly</target>
......
......@@ -97,6 +97,21 @@
<target state="new">Invalid format string</target>
<note />
</trans-unit>
<trans-unit id="Invalid_global_SuppressMessageAttribute">
<source>Invalid global 'SuppressMessageAttribute'</source>
<target state="new">Invalid global 'SuppressMessageAttribute'</target>
<note />
</trans-unit>
<trans-unit id="Invalid_or_missing_target_for_SuppressMessageAttribute">
<source>Invalid or missing target for 'SuppressMessageAttribute'</source>
<target state="new">Invalid or missing target for 'SuppressMessageAttribute'</target>
<note />
</trans-unit>
<trans-unit id="Invalid_scope_for_SuppressMessageAttribute">
<source>Invalid scope for 'SuppressMessageAttribute'</source>
<target state="new">Invalid scope for 'SuppressMessageAttribute'</target>
<note />
</trans-unit>
<trans-unit id="Make_field_readonly">
<source>Make field readonly</source>
<target state="new">Make field readonly</target>
......
......@@ -97,6 +97,21 @@
<target state="new">Invalid format string</target>
<note />
</trans-unit>
<trans-unit id="Invalid_global_SuppressMessageAttribute">
<source>Invalid global 'SuppressMessageAttribute'</source>
<target state="new">Invalid global 'SuppressMessageAttribute'</target>
<note />
</trans-unit>
<trans-unit id="Invalid_or_missing_target_for_SuppressMessageAttribute">
<source>Invalid or missing target for 'SuppressMessageAttribute'</source>
<target state="new">Invalid or missing target for 'SuppressMessageAttribute'</target>
<note />
</trans-unit>
<trans-unit id="Invalid_scope_for_SuppressMessageAttribute">
<source>Invalid scope for 'SuppressMessageAttribute'</source>
<target state="new">Invalid scope for 'SuppressMessageAttribute'</target>
<note />
</trans-unit>
<trans-unit id="Make_field_readonly">
<source>Make field readonly</source>
<target state="new">Make field readonly</target>
......
......@@ -97,6 +97,21 @@
<target state="new">Invalid format string</target>
<note />
</trans-unit>
<trans-unit id="Invalid_global_SuppressMessageAttribute">
<source>Invalid global 'SuppressMessageAttribute'</source>
<target state="new">Invalid global 'SuppressMessageAttribute'</target>
<note />
</trans-unit>
<trans-unit id="Invalid_or_missing_target_for_SuppressMessageAttribute">
<source>Invalid or missing target for 'SuppressMessageAttribute'</source>
<target state="new">Invalid or missing target for 'SuppressMessageAttribute'</target>
<note />
</trans-unit>
<trans-unit id="Invalid_scope_for_SuppressMessageAttribute">
<source>Invalid scope for 'SuppressMessageAttribute'</source>
<target state="new">Invalid scope for 'SuppressMessageAttribute'</target>
<note />
</trans-unit>
<trans-unit id="Make_field_readonly">
<source>Make field readonly</source>
<target state="new">Make field readonly</target>
......
......@@ -97,6 +97,21 @@
<target state="new">Invalid format string</target>
<note />
</trans-unit>
<trans-unit id="Invalid_global_SuppressMessageAttribute">
<source>Invalid global 'SuppressMessageAttribute'</source>
<target state="new">Invalid global 'SuppressMessageAttribute'</target>
<note />
</trans-unit>
<trans-unit id="Invalid_or_missing_target_for_SuppressMessageAttribute">
<source>Invalid or missing target for 'SuppressMessageAttribute'</source>
<target state="new">Invalid or missing target for 'SuppressMessageAttribute'</target>
<note />
</trans-unit>
<trans-unit id="Invalid_scope_for_SuppressMessageAttribute">
<source>Invalid scope for 'SuppressMessageAttribute'</source>
<target state="new">Invalid scope for 'SuppressMessageAttribute'</target>
<note />
</trans-unit>
<trans-unit id="Make_field_readonly">
<source>Make field readonly</source>
<target state="new">Make field readonly</target>
......
......@@ -97,6 +97,21 @@
<target state="new">Invalid format string</target>
<note />
</trans-unit>
<trans-unit id="Invalid_global_SuppressMessageAttribute">
<source>Invalid global 'SuppressMessageAttribute'</source>
<target state="new">Invalid global 'SuppressMessageAttribute'</target>
<note />
</trans-unit>
<trans-unit id="Invalid_or_missing_target_for_SuppressMessageAttribute">
<source>Invalid or missing target for 'SuppressMessageAttribute'</source>
<target state="new">Invalid or missing target for 'SuppressMessageAttribute'</target>
<note />
</trans-unit>
<trans-unit id="Invalid_scope_for_SuppressMessageAttribute">
<source>Invalid scope for 'SuppressMessageAttribute'</source>
<target state="new">Invalid scope for 'SuppressMessageAttribute'</target>
<note />
</trans-unit>
<trans-unit id="Make_field_readonly">
<source>Make field readonly</source>
<target state="new">Make field readonly</target>
......
......@@ -97,6 +97,21 @@
<target state="new">Invalid format string</target>
<note />
</trans-unit>
<trans-unit id="Invalid_global_SuppressMessageAttribute">
<source>Invalid global 'SuppressMessageAttribute'</source>
<target state="new">Invalid global 'SuppressMessageAttribute'</target>
<note />
</trans-unit>
<trans-unit id="Invalid_or_missing_target_for_SuppressMessageAttribute">
<source>Invalid or missing target for 'SuppressMessageAttribute'</source>
<target state="new">Invalid or missing target for 'SuppressMessageAttribute'</target>
<note />
</trans-unit>
<trans-unit id="Invalid_scope_for_SuppressMessageAttribute">
<source>Invalid scope for 'SuppressMessageAttribute'</source>
<target state="new">Invalid scope for 'SuppressMessageAttribute'</target>
<note />
</trans-unit>
<trans-unit id="Make_field_readonly">
<source>Make field readonly</source>
<target state="new">Make field readonly</target>
......
......@@ -97,6 +97,21 @@
<target state="new">Invalid format string</target>
<note />
</trans-unit>
<trans-unit id="Invalid_global_SuppressMessageAttribute">
<source>Invalid global 'SuppressMessageAttribute'</source>
<target state="new">Invalid global 'SuppressMessageAttribute'</target>
<note />
</trans-unit>
<trans-unit id="Invalid_or_missing_target_for_SuppressMessageAttribute">
<source>Invalid or missing target for 'SuppressMessageAttribute'</source>
<target state="new">Invalid or missing target for 'SuppressMessageAttribute'</target>
<note />
</trans-unit>
<trans-unit id="Invalid_scope_for_SuppressMessageAttribute">
<source>Invalid scope for 'SuppressMessageAttribute'</source>
<target state="new">Invalid scope for 'SuppressMessageAttribute'</target>
<note />
</trans-unit>
<trans-unit id="Make_field_readonly">
<source>Make field readonly</source>
<target state="new">Make field readonly</target>
......
......@@ -97,6 +97,21 @@
<target state="new">Invalid format string</target>
<note />
</trans-unit>
<trans-unit id="Invalid_global_SuppressMessageAttribute">
<source>Invalid global 'SuppressMessageAttribute'</source>
<target state="new">Invalid global 'SuppressMessageAttribute'</target>
<note />
</trans-unit>
<trans-unit id="Invalid_or_missing_target_for_SuppressMessageAttribute">
<source>Invalid or missing target for 'SuppressMessageAttribute'</source>
<target state="new">Invalid or missing target for 'SuppressMessageAttribute'</target>
<note />
</trans-unit>
<trans-unit id="Invalid_scope_for_SuppressMessageAttribute">
<source>Invalid scope for 'SuppressMessageAttribute'</source>
<target state="new">Invalid scope for 'SuppressMessageAttribute'</target>
<note />
</trans-unit>
<trans-unit id="Make_field_readonly">
<source>Make field readonly</source>
<target state="new">Make field readonly</target>
......
......@@ -97,6 +97,21 @@
<target state="new">Invalid format string</target>
<note />
</trans-unit>
<trans-unit id="Invalid_global_SuppressMessageAttribute">
<source>Invalid global 'SuppressMessageAttribute'</source>
<target state="new">Invalid global 'SuppressMessageAttribute'</target>
<note />
</trans-unit>
<trans-unit id="Invalid_or_missing_target_for_SuppressMessageAttribute">
<source>Invalid or missing target for 'SuppressMessageAttribute'</source>
<target state="new">Invalid or missing target for 'SuppressMessageAttribute'</target>
<note />
</trans-unit>
<trans-unit id="Invalid_scope_for_SuppressMessageAttribute">
<source>Invalid scope for 'SuppressMessageAttribute'</source>
<target state="new">Invalid scope for 'SuppressMessageAttribute'</target>
<note />
</trans-unit>
<trans-unit id="Make_field_readonly">
<source>Make field readonly</source>
<target state="new">Make field readonly</target>
......
......@@ -25,6 +25,7 @@
<Compile Include="$(MSBuildThisFileDirectory)PopulateSwitch\AbstractPopulateSwitchStatementCodeFixProvider.cs" />
<Compile Include="$(MSBuildThisFileDirectory)PredefinedCodeFixProviderNames.cs" />
<Compile Include="$(MSBuildThisFileDirectory)QualifyMemberAccess\AbstractQualifyMemberAccessCodeFixProvider.cs" />
<Compile Include="$(MSBuildThisFileDirectory)RemoveUnnecessarySuppressions\RemoveUnnecessarySuppressionsCodeFixProvider.cs" />
<Compile Include="$(MSBuildThisFileDirectory)RemoveUnnecessaryImports\AbstractRemoveUnnecessaryImportsCodeFixProvider.cs" />
<Compile Include="$(MSBuildThisFileDirectory)RemoveUnnecessaryParentheses\AbstractRemoveUnnecessaryParenthesesCodeFixProvider.cs" />
<Compile Include="$(MSBuildThisFileDirectory)RemoveUnusedMembers\AbstractRemoveUnusedMembersCodeFixProvider.cs" />
......
......@@ -138,4 +138,7 @@
<data name="Remove_redundant_assignment" xml:space="preserve">
<value>Remove redundant assignment</value>
</data>
<data name="Remove_redundant_suppression" xml:space="preserve">
<value>Remove redundant suppression</value>
</data>
</root>
\ No newline at end of file
......@@ -51,6 +51,7 @@ internal static class PredefinedCodeFixProviderNames
public const string RemoveUnnecessaryCast = nameof(RemoveUnnecessaryCast);
public const string DeclareAsNullable = nameof(DeclareAsNullable);
public const string RemoveUnnecessaryImports = nameof(RemoveUnnecessaryImports);
public const string RemoveUnnecessarySuppressions = nameof(RemoveUnnecessarySuppressions);
public const string RemoveUnreachableCode = nameof(RemoveUnreachableCode);
public const string RemoveUnusedValues = nameof(RemoveUnusedValues);
public const string RemoveUnusedLocalFunction = nameof(RemoveUnusedLocalFunction);
......
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Immutable;
using System.Composition;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.Host.Mef;
namespace Microsoft.CodeAnalysis.RemoveUnnecessarySuppressions
{
[ExportCodeFixProvider(LanguageNames.CSharp, LanguageNames.VisualBasic, Name = PredefinedCodeFixProviderNames.RemoveUnnecessarySuppressions), Shared]
internal sealed class RemoveUnnecessarySuppressionsCodeFixProvider : SyntaxEditorBasedCodeFixProvider
{
[ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
public RemoveUnnecessarySuppressionsCodeFixProvider()
{
}
public override ImmutableArray<string> FixableDiagnosticIds
=> ImmutableArray.Create(IDEDiagnosticIds.InvalidSuppressMessageAttributeDiagnosticId);
internal override CodeFixCategory CodeFixCategory
=> CodeFixCategory.CodeQuality;
public override Task RegisterCodeFixesAsync(CodeFixContext context)
{
foreach (var diagnostic in context.Diagnostics)
{
context.RegisterCodeFix(
new MyCodeAction(c => FixAsync(context.Document, diagnostic, c)),
diagnostic);
}
return Task.CompletedTask;
}
protected override Task FixAllAsync(Document document, ImmutableArray<Diagnostic> diagnostics, SyntaxEditor editor, CancellationToken cancellationToken)
{
foreach (var diagnostic in diagnostics)
{
var node = editor.OriginalRoot.FindNode(diagnostic.Location.SourceSpan);
if (node != null)
{
editor.RemoveNode(node);
}
}
return Task.CompletedTask;
}
private class MyCodeAction : CustomCodeActions.DocumentChangeAction
{
public MyCodeAction(Func<CancellationToken, Task<Document>> createChangedDocument)
: base(CodeFixesResources.Remove_redundant_suppression, createChangedDocument, nameof(RemoveUnnecessarySuppressionsCodeFixProvider))
{
}
}
}
}
......@@ -27,6 +27,11 @@
<target state="new">Remove redundant assignment</target>
<note />
</trans-unit>
<trans-unit id="Remove_redundant_suppression">
<source>Remove redundant suppression</source>
<target state="new">Remove redundant suppression</target>
<note />
</trans-unit>
<trans-unit id="Use_discard_underscore">
<source>Use discard '_'</source>
<target state="new">Use discard '_'</target>
......
......@@ -27,6 +27,11 @@
<target state="new">Remove redundant assignment</target>
<note />
</trans-unit>
<trans-unit id="Remove_redundant_suppression">
<source>Remove redundant suppression</source>
<target state="new">Remove redundant suppression</target>
<note />
</trans-unit>
<trans-unit id="Use_discard_underscore">
<source>Use discard '_'</source>
<target state="new">Use discard '_'</target>
......
......@@ -27,6 +27,11 @@
<target state="new">Remove redundant assignment</target>
<note />
</trans-unit>
<trans-unit id="Remove_redundant_suppression">
<source>Remove redundant suppression</source>
<target state="new">Remove redundant suppression</target>
<note />
</trans-unit>
<trans-unit id="Use_discard_underscore">
<source>Use discard '_'</source>
<target state="new">Use discard '_'</target>
......
......@@ -27,6 +27,11 @@
<target state="new">Remove redundant assignment</target>
<note />
</trans-unit>
<trans-unit id="Remove_redundant_suppression">
<source>Remove redundant suppression</source>
<target state="new">Remove redundant suppression</target>
<note />
</trans-unit>
<trans-unit id="Use_discard_underscore">
<source>Use discard '_'</source>
<target state="new">Use discard '_'</target>
......
......@@ -27,6 +27,11 @@
<target state="new">Remove redundant assignment</target>
<note />
</trans-unit>
<trans-unit id="Remove_redundant_suppression">
<source>Remove redundant suppression</source>
<target state="new">Remove redundant suppression</target>
<note />
</trans-unit>
<trans-unit id="Use_discard_underscore">
<source>Use discard '_'</source>
<target state="new">Use discard '_'</target>
......
......@@ -27,6 +27,11 @@
<target state="new">Remove redundant assignment</target>
<note />
</trans-unit>
<trans-unit id="Remove_redundant_suppression">
<source>Remove redundant suppression</source>
<target state="new">Remove redundant suppression</target>
<note />
</trans-unit>
<trans-unit id="Use_discard_underscore">
<source>Use discard '_'</source>
<target state="new">Use discard '_'</target>
......
......@@ -27,6 +27,11 @@
<target state="new">Remove redundant assignment</target>
<note />
</trans-unit>
<trans-unit id="Remove_redundant_suppression">
<source>Remove redundant suppression</source>
<target state="new">Remove redundant suppression</target>
<note />
</trans-unit>
<trans-unit id="Use_discard_underscore">
<source>Use discard '_'</source>
<target state="new">Use discard '_'</target>
......
......@@ -27,6 +27,11 @@
<target state="new">Remove redundant assignment</target>
<note />
</trans-unit>
<trans-unit id="Remove_redundant_suppression">
<source>Remove redundant suppression</source>
<target state="new">Remove redundant suppression</target>
<note />
</trans-unit>
<trans-unit id="Use_discard_underscore">
<source>Use discard '_'</source>
<target state="new">Use discard '_'</target>
......
......@@ -27,6 +27,11 @@
<target state="new">Remove redundant assignment</target>
<note />
</trans-unit>
<trans-unit id="Remove_redundant_suppression">
<source>Remove redundant suppression</source>
<target state="new">Remove redundant suppression</target>
<note />
</trans-unit>
<trans-unit id="Use_discard_underscore">
<source>Use discard '_'</source>
<target state="new">Use discard '_'</target>
......
......@@ -27,6 +27,11 @@
<target state="new">Remove redundant assignment</target>
<note />
</trans-unit>
<trans-unit id="Remove_redundant_suppression">
<source>Remove redundant suppression</source>
<target state="new">Remove redundant suppression</target>
<note />
</trans-unit>
<trans-unit id="Use_discard_underscore">
<source>Use discard '_'</source>
<target state="new">Use discard '_'</target>
......
......@@ -27,6 +27,11 @@
<target state="new">Remove redundant assignment</target>
<note />
</trans-unit>
<trans-unit id="Remove_redundant_suppression">
<source>Remove redundant suppression</source>
<target state="new">Remove redundant suppression</target>
<note />
</trans-unit>
<trans-unit id="Use_discard_underscore">
<source>Use discard '_'</source>
<target state="new">Use discard '_'</target>
......
......@@ -27,6 +27,11 @@
<target state="new">Remove redundant assignment</target>
<note />
</trans-unit>
<trans-unit id="Remove_redundant_suppression">
<source>Remove redundant suppression</source>
<target state="new">Remove redundant suppression</target>
<note />
</trans-unit>
<trans-unit id="Use_discard_underscore">
<source>Use discard '_'</source>
<target state="new">Use discard '_'</target>
......
......@@ -27,6 +27,11 @@
<target state="new">Remove redundant assignment</target>
<note />
</trans-unit>
<trans-unit id="Remove_redundant_suppression">
<source>Remove redundant suppression</source>
<target state="new">Remove redundant suppression</target>
<note />
</trans-unit>
<trans-unit id="Use_discard_underscore">
<source>Use discard '_'</source>
<target state="new">Use discard '_'</target>
......
' Licensed to the .NET Foundation under one or more agreements.
' The .NET Foundation licenses this file to you under the MIT license.
' See the LICENSE file in the project root for more information.
Imports Microsoft.CodeAnalysis.Diagnostics
Imports Microsoft.CodeAnalysis.RemoveUnnecessarySuppressions
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Namespace Microsoft.CodeAnalysis.VisualBasic.RemoveUnnecessarySuppressions
<DiagnosticAnalyzer(LanguageNames.VisualBasic)>
Friend NotInheritable Class VisualBasicRemoveUnnecessarySuppressionsDiagnosticAnalyzer
Inherits AbstractRemoveUnnecessarySuppressionsDiagnosticAnalyzer
Protected Overrides Sub RegisterAttributeSyntaxAction(context As CompilationStartAnalysisContext, compilationAnalyzer As CompilationAnalyzer)
context.RegisterSyntaxNodeAction(
Sub(syntaxContext As SyntaxNodeAnalysisContext)
Dim attribute = DirectCast(syntaxContext.Node, AttributeSyntax)
Select Case attribute.Target?.AttributeModifier.Kind()
Case SyntaxKind.AssemblyKeyword, SyntaxKind.ModuleKeyword
compilationAnalyzer.AnalyzeAssemblyOrModuleAttribute(attribute, syntaxContext.SemanticModel, AddressOf syntaxContext.ReportDiagnostic, syntaxContext.CancellationToken)
End Select
End Sub,
SyntaxKind.Attribute)
End Sub
End Class
End Namespace
......@@ -24,6 +24,7 @@
<Compile Include="$(MSBuildThisFileDirectory)PopulateSwitch\VisualBasicPopulateSwitchStatementDiagnosticAnalyzer.vb" />
<Compile Include="$(MSBuildThisFileDirectory)QualifyMemberAccess\VisualBasicQualifyMemberAccessDiagnosticAnalyzer.vb" />
<Compile Include="$(MSBuildThisFileDirectory)RemoveUnnecessaryCast\VisualBasicRemoveUnnecessaryCastDiagnosticAnalyzer.vb" />
<Compile Include="$(MSBuildThisFileDirectory)RemoveUnnecessarySuppressions\VisualBasicRemoveUnnecessarySuppressionsDiagnosticAnalyzer.vb" />
<Compile Include="$(MSBuildThisFileDirectory)RemoveUnnecessaryImports\VisualBasicRemoveUnnecessaryImportsDiagnosticAnalyzer.vb" />
<Compile Include="$(MSBuildThisFileDirectory)RemoveUnnecessaryParentheses\VisualBasicRemoveUnnecessaryParenthesesDiagnosticAnalyzer.vb" />
<Compile Include="$(MSBuildThisFileDirectory)RemoveUnusedMembers\VisualBasicRemoveUnusedMembersDiagnosticAnalyzer.vb" />
......
' Licensed to the .NET Foundation under one or more agreements.
' The .NET Foundation licenses this file to you under the MIT license.
' See the LICENSE file in the project root for more information.
Imports VerifyVB = Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions.VisualBasicCodeFixVerifier(Of
Microsoft.CodeAnalysis.VisualBasic.RemoveUnnecessarySuppressions.VisualBasicRemoveUnnecessarySuppressionsDiagnosticAnalyzer,
Microsoft.CodeAnalysis.RemoveUnnecessarySuppressions.RemoveUnnecessarySuppressionsCodeFixProvider)
Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.RemoveUnnecessarySuppressions
<Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessarySuppressions)>
<WorkItem(44176, "https://github.com/dotnet/roslyn/issues/44176")>
Public Class RemoveUnnecessarySuppressionsTests
<Fact>
Public Sub TestStandardProperties()
VerifyVB.VerifyStandardProperties()
End Sub
<Theory>
<InlineData("Scope:=""member""", "Target:=""~F:N.C.F""", "Assembly")>
<InlineData("Scope:=""member""", "Target:=""~P:N.C.P""", "Assembly")>
<InlineData("Scope:=""member""", "Target:=""~M:N.C.M()""", "Assembly")>
<InlineData("Scope:=""member""", "Target:=""~T:N.C""", "Assembly")>
<InlineData("Scope:=""namespace""", "Target:=""~N:N""", "Assembly")>
<InlineData("Scope:=""namespaceanddescendants""", "Target:=""~N:N""", "Assembly")>
<InlineData(Nothing, Nothing, "Assembly")>
<InlineData("Scope:=""module""", Nothing, "Assembly")>
<InlineData("Scope:=""module""", "Target:=Nothing", "Assembly")>
<InlineData("Scope:=""resource""", "Target:=""""", "Assembly")>
<InlineData("Scope:=""member""", "Target:=""~M:N.C.M()""", "Module")>
<InlineData("Scope:=""type""", "Target:=""~M:N.C.M()""", "Assembly")>
<InlineData("Scope:=""namespace""", "Target:=""~F:N.C.F""", "Assembly")>
<InlineData("Scope:=""Member""", "Target:=""~F:N.C.F""", "Assembly")>
<InlineData("Scope:=""MEMBER""", "Target:=""~F:N.C.F""", "Assembly")>
Public Async Function ValidSuppressions(scope As String, target As String, attributeTarget As String) As Task
Dim scopeString = If(scope IsNot Nothing, $", {scope}", String.Empty)
Dim targetString = If(target IsNot Nothing, $", {target}", String.Empty)
Dim input = $"
<{attributeTarget}: System.Diagnostics.CodeAnalysis.SuppressMessage(""Category"", ""Id: Title"", Justification:=""Pending""{scopeString}{targetString})>
Namespace N
Class C
Public F As Integer
Public ReadOnly Property P As Integer
Public Sub M()
End Sub
End Class
End Namespace
"
Await VerifyVB.VerifyCodeFixAsync(input, input)
End Function
<Theory>
<InlineData("Scope:=""member""", "Target:=""~F:N.C.F2""", "Assembly")>
<InlineData("Scope:=""Member""", "Target:=""~F:N.C.F2""", "Assembly")>
<InlineData("Scope:=""MEMBER""", "Target:=""~F:N.C.F2""", "Assembly")>
<InlineData("Scope:=""invalid""", "Target:=""~P:N.C.P""", "Assembly")>
<InlineData("Scope:=""member""", "Target:=""~M:N.C.M(System.Int32)""", "Assembly")>
<InlineData("Scope:=""module""", "Target:=""~M:N.C.M()""", "Assembly")>
<InlineData("Scope:=Nothing", "Target:=""~M:N.C.M()""", "Assembly")>
<InlineData(Nothing, "Target:=""~M:N.C.M()""", "Assembly")>
<InlineData("Scope:=""member""", "Target:=Nothing", "Assembly")>
<InlineData("Scope:=""member""", Nothing, "Assembly")>
<InlineData("Scope:=""type""", "Target:=""~T:N2.C""", "Assembly")>
<InlineData("Scope:=""namespace""", "Target:=""~N:N.N2""", "Assembly")>
<InlineData("Scope:=""namespaceanddescendants""", "Target:=""""", "Assembly")>
<InlineData(Nothing, "Target:=""""", "Assembly")>
<InlineData(Nothing, "Target:=""~T:N.C""", "Assembly")>
<InlineData("Scope:=""module""", "Target:=""""", "Assembly")>
<InlineData("Scope:=""module""", "Target:=""~T:N.C""", "Assembly")>
Public Async Function InvalidSuppressions(scope As String, target As String, attributeTarget As String) As Task
Dim scopeString = If(scope IsNot Nothing, $", {scope}", String.Empty)
Dim targetString = If(target IsNot Nothing, $", {target}", String.Empty)
Dim input = $"
<[|{attributeTarget}: System.Diagnostics.CodeAnalysis.SuppressMessage(""Category"", ""Id: Title"", Justification:=""Pending""{scopeString}{targetString})|]>
Namespace N
Class C
Public F As Integer
Public ReadOnly Property P As Integer
Public Sub M()
End Sub
End Class
End Namespace
"
Dim fixedCode = $"
Namespace N
Class C
Public F As Integer
Public ReadOnly Property P As Integer
Public Sub M()
End Sub
End Class
End Namespace
"
Await VerifyVB.VerifyCodeFixAsync(input, fixedCode)
End Function
<Fact>
Public Async Function ValidAndInvalidSuppressions() As Task
Dim attributePrefix = "Assembly: System.Diagnostics.CodeAnalysis.SuppressMessage(""Category"", ""Id: Title"", Justification:=""Pending"""
Dim validSuppression = $"{attributePrefix}, Scope:=""member"", Target:=""~T:C"")"
Dim invalidSuppression = $"[|{attributePrefix}, Scope:=""member"", Target:="""")|]"
Dim input = $"
<{validSuppression}>
<{invalidSuppression}>
<{validSuppression}, {validSuppression}>
<{invalidSuppression}, {invalidSuppression}>
<{validSuppression}, {invalidSuppression}>
<{invalidSuppression}, {validSuppression}>
<{invalidSuppression}, {validSuppression}, {invalidSuppression}, {validSuppression}>
Class C
End Class
"
Dim fixedCode = $"
<{validSuppression}>
<{validSuppression}, {validSuppression}>
<{validSuppression}>
<{validSuppression}>
<{validSuppression}, {validSuppression}>
Class C
End Class
"
Await VerifyVB.VerifyCodeFixAsync(input, fixedCode)
End Function
<Theory>
<InlineData("")>
<InlineData(", Scope:=""member"", Target:=""~M:C.M()""")>
<InlineData(", Scope:=""invalid"", Target:=""invalid""")>
Public Async Function LocalSuppressions(ByVal scopeAndTarget As String) As Task
Dim input = $"
<System.Diagnostics.CodeAnalysis.SuppressMessage(""Category"", ""Id: Title"", Justification:=""Pending""{scopeAndTarget})>
Class C
Sub M()
End Sub
End Class"
Await VerifyVB.VerifyCodeFixAsync(input, input)
End Function
End Class
End Namespace
......@@ -13,6 +13,7 @@
<Compile Include="$(MSBuildThisFileDirectory)AddRequiredParentheses\AddRequiredParenthesesTests.vb" />
<Compile Include="$(MSBuildThisFileDirectory)ConvertAnonymousTypeToTuple\ConvertAnonymousTypeToTupleTests.vb" />
<Compile Include="$(MSBuildThisFileDirectory)FileHeaders\FileHeaderTests.vb" />
<Compile Include="$(MSBuildThisFileDirectory)RemoveUnnecessarySuppressions\RemoveUnnecessarySuppressionsTests.vb" />
<Compile Include="$(MSBuildThisFileDirectory)MakeFieldReadonly\MakeFieldReadonlyTests.vb" />
<Compile Include="$(MSBuildThisFileDirectory)NamingStyles\NamingStylesTests.vb" />
<Compile Include="$(MSBuildThisFileDirectory)OrderModifiers\OrderModifiersTests.vb" />
......
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Microsoft.CodeAnalysis.Diagnostics
{
internal partial class SuppressMessageAttributeState
{
internal enum TargetScope
{
None,
Module,
Namespace,
Resource,
Type,
Member,
NamespaceAndDescendants
}
}
}
......@@ -379,16 +379,5 @@ private static bool TryDecodeSuppressMessageAttributeData(AttributeData attribut
return true;
}
internal enum TargetScope
{
None,
Module,
Namespace,
Resource,
Type,
Member,
NamespaceAndDescendants
}
}
}
......@@ -376,6 +376,9 @@ public void CSharp_VerifyIDEDiagnosticSeveritiesAreConfigurable()
# IDE0075
dotnet_style_prefer_simplified_boolean_expressions = true:suggestion
# IDE0076
dotnet_diagnostic.IDE0076.severity = %value%
# IDE1005
csharp_style_conditional_delegate_call = true:suggestion
......@@ -516,6 +519,9 @@ public void VisualBasic_VerifyIDEDiagnosticSeveritiesAreConfigurable()
# IDE0075
dotnet_style_prefer_simplified_boolean_expressions = true:suggestion
# IDE0076
dotnet_diagnostic.IDE0076.severity = %value%
# IDE1006
dotnet_diagnostic.IDE1006.severity = %value%
......@@ -882,6 +888,9 @@ public void CSharp_VerifyIDECodeStyleOptionsAreConfigurable()
# IDE0075, PreferSimplifiedBooleanExpressions
dotnet_style_prefer_simplified_boolean_expressions = true:suggestion
# IDE0076
No editorconfig based code style option
# IDE1005, PreferConditionalDelegateCall
csharp_style_conditional_delegate_call = true:suggestion
......@@ -1055,6 +1064,9 @@ public void VisualBasic_VerifyIDECodeStyleOptionsAreConfigurable()
# IDE0075, PreferSimplifiedBooleanExpressions
dotnet_style_prefer_simplified_boolean_expressions = true:suggestion
# IDE0076
No editorconfig based code style option
# IDE1006
No editorconfig based code style option
......
......@@ -133,6 +133,7 @@ public static class Features
public const string CodeActionsQualifyMemberAccess = "CodeActions.QualifyMemberAccess";
public const string CodeActionsRemoveByVal = "CodeActions.RemoveByVal";
public const string CodeActionsRemoveDocCommentNode = "CodeActions.RemoveDocCommentNode";
public const string CodeActionsRemoveUnnecessarySuppressions = "CodeActions.RemoveUnnecessarySuppressions";
public const string CodeActionsRemoveUnnecessaryCast = "CodeActions.RemoveUnnecessaryCast";
public const string CodeActionsRemoveUnnecessaryImports = "CodeActions.RemoveUnnecessaryImports";
public const string CodeActionsRemoveUnnecessaryParentheses = "CodeActions.RemoveUnnecessaryParentheses";
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册