diff --git a/src/Analyzers/CSharp/Tests/CSharpAnalyzers.UnitTests.projitems b/src/Analyzers/CSharp/Tests/CSharpAnalyzers.UnitTests.projitems index 378c593c2b82e..612d5dc05bb57 100644 --- a/src/Analyzers/CSharp/Tests/CSharpAnalyzers.UnitTests.projitems +++ b/src/Analyzers/CSharp/Tests/CSharpAnalyzers.UnitTests.projitems @@ -25,6 +25,7 @@ + diff --git a/src/Analyzers/CSharp/Tests/UpdateLegacySuppressions/UpdateLegacySuppressionsTests.cs b/src/Analyzers/CSharp/Tests/UpdateLegacySuppressions/UpdateLegacySuppressionsTests.cs new file mode 100644 index 0000000000000..2fe5f09af0b5b --- /dev/null +++ b/src/Analyzers/CSharp/Tests/UpdateLegacySuppressions/UpdateLegacySuppressionsTests.cs @@ -0,0 +1,87 @@ +// 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.RemoveUnnecessarySuppressions; +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.UpdateLegacySuppressions.UpdateLegacySuppressionsCodeFixProvider>; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.UpdateLegacySuppressions +{ + [Trait(Traits.Feature, Traits.Features.CodeActionsUpdateLegacySuppressions)] + [WorkItem(44362, "https://github.com/dotnet/roslyn/issues/44362")] + public class UpdateLegacySuppressionsTests + { + [Fact] + public void TestStandardProperties() + => VerifyCS.VerifyStandardProperties(); + + // Namespace + [InlineData("namespace", "N", "~N:N")] + // Type + [InlineData("type", "N.C+D", "~T:N.C.D")] + // Field + [InlineData("member", "N.C.#F", "~F:N.C.F")] + // Property + [InlineData("member", "N.C.#P", "~P:N.C.P")] + // Method + [InlineData("member", "N.C.#M", "~M:N.C.M")] + // Generic method with parameters + [InlineData("member", "N.C.#M2(!!0)", "~M:N.C.M2``1(``0)~System.Int32")] + // Event + [InlineData("member", "e:N.C.#E", "~E:N.C.E")] + [Theory] + public async Task LegacySuppressions(string scope, string target, string fixedTarget) + { + var input = $@" +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage(""Category"", ""Id: Title"", Scope = ""{scope}"", Target = {{|#0:""{target}""|}})] + +namespace N +{{ + class C + {{ + private int F; + public int P {{ get; set; }} + public void M() {{ }} + public int M2(T t) => 0; + public event System.EventHandler E; + + class D + {{ + }} + }} +}}"; + + var expectedDiagnostic = VerifyCS.Diagnostic(AbstractRemoveUnnecessarySuppressionsDiagnosticAnalyzer.LegacyFormatTargetDescriptor) + .WithLocation(0) + .WithArguments(target); + + var fixedCode = $@" +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage(""Category"", ""Id: Title"", Scope = ""{scope}"", Target = ""{fixedTarget}"")] + +namespace N +{{ + class C + {{ + private int F; + public int P {{ get; set; }} + public void M() {{ }} + public int M2(T t) => 0; + public event System.EventHandler E; + + class D + {{ + }} + }} +}}"; + await VerifyCS.VerifyCodeFixAsync(input, expectedDiagnostic, fixedCode); + } + } +} diff --git a/src/Analyzers/Core/Analyzers/AnalyzersResources.resx b/src/Analyzers/Core/Analyzers/AnalyzersResources.resx index bf31c2eeb98f0..efd6179a64a00 100644 --- a/src/Analyzers/Core/Analyzers/AnalyzersResources.resx +++ b/src/Analyzers/Core/Analyzers/AnalyzersResources.resx @@ -316,4 +316,10 @@ Invalid or missing target for 'SuppressMessageAttribute' + + Avoid legacy format target in 'SuppressMessageAttribute' + + + Avoid legacy format target '{0}' in 'SuppressMessageAttribute' + \ No newline at end of file diff --git a/src/Analyzers/Core/Analyzers/IDEDiagnosticIds.cs b/src/Analyzers/Core/Analyzers/IDEDiagnosticIds.cs index 87a3f3edabded..7976ecd37a3eb 100644 --- a/src/Analyzers/Core/Analyzers/IDEDiagnosticIds.cs +++ b/src/Analyzers/Core/Analyzers/IDEDiagnosticIds.cs @@ -131,6 +131,7 @@ internal static class IDEDiagnosticIds public const string SimplifyConditionalExpressionDiagnosticId = "IDE0075"; public const string InvalidSuppressMessageAttributeDiagnosticId = "IDE0076"; + public const string LegacyFormatSuppressMessageAttributeDiagnosticId = "IDE0077"; // Analyzer error Ids public const string AnalyzerChangedId = "IDE1001"; diff --git a/src/Analyzers/Core/Analyzers/RemoveUnnecessarySuppressions/AbstractRemoveUnnecessarySuppressionsDiagnosticAnalyzer.cs b/src/Analyzers/Core/Analyzers/RemoveUnnecessarySuppressions/AbstractRemoveUnnecessarySuppressionsDiagnosticAnalyzer.cs index ecc33dab9b7a3..18ea628b51e7d 100644 --- a/src/Analyzers/Core/Analyzers/RemoveUnnecessarySuppressions/AbstractRemoveUnnecessarySuppressionsDiagnosticAnalyzer.cs +++ b/src/Analyzers/Core/Analyzers/RemoveUnnecessarySuppressions/AbstractRemoveUnnecessarySuppressionsDiagnosticAnalyzer.cs @@ -10,12 +10,15 @@ using Microsoft.CodeAnalysis.CodeQuality; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Shared.Extensions; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.RemoveUnnecessarySuppressions { internal abstract class AbstractRemoveUnnecessarySuppressionsDiagnosticAnalyzer : AbstractCodeQualityDiagnosticAnalyzer { + internal const string DocCommentIdKey = nameof(DocCommentIdKey); + 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( @@ -28,8 +31,15 @@ internal abstract class AbstractRemoveUnnecessarySuppressionsDiagnosticAnalyzer private static readonly DiagnosticDescriptor s_invalidOrMissingTargetDescriptor = CreateDescriptor( IDEDiagnosticIds.InvalidSuppressMessageAttributeDiagnosticId, s_localizableTitle, s_localizableInvalidOrMissingTargetMessage, isUnnecessary: true); + private static readonly LocalizableResourceString s_localizableLegacyFormatTitle = new LocalizableResourceString( + nameof(AnalyzersResources.Avoid_legacy_format_target_in_SuppressMessageAttribute), AnalyzersResources.ResourceManager, typeof(AnalyzersResources)); + private static readonly LocalizableResourceString s_localizableLegacyFormatMessage = new LocalizableResourceString( + nameof(AnalyzersResources.Avoid_legacy_format_target_0_in_SuppressMessageAttribute), AnalyzersResources.ResourceManager, typeof(AnalyzersResources)); + internal static readonly DiagnosticDescriptor LegacyFormatTargetDescriptor = CreateDescriptor( + IDEDiagnosticIds.LegacyFormatSuppressMessageAttributeDiagnosticId, s_localizableLegacyFormatTitle, s_localizableLegacyFormatMessage, isUnnecessary: false); + public AbstractRemoveUnnecessarySuppressionsDiagnosticAnalyzer() - : base(ImmutableArray.Create(s_invalidScopeDescriptor, s_invalidOrMissingTargetDescriptor), GeneratedCodeAnalysisFlags.None) + : base(ImmutableArray.Create(s_invalidScopeDescriptor, s_invalidOrMissingTargetDescriptor, LegacyFormatTargetDescriptor), GeneratedCodeAnalysisFlags.None) { } @@ -66,21 +76,41 @@ public void AnalyzeAssemblyOrModuleAttribute(SyntaxNode attributeSyntax, Semanti return; } - DiagnosticDescriptor rule; - if (SuppressMessageAttributeState.HasInvalidScope(namedAttributeArguments, out var targetScope)) + if (!SuppressMessageAttributeState.HasValidScope(namedAttributeArguments, out var targetScope)) { - rule = s_invalidScopeDescriptor; + reportDiagnostic(Diagnostic.Create(s_invalidScopeDescriptor, attributeSyntax.GetLocation())); + return; } - else if (_state.HasInvalidOrMissingTarget(namedAttributeArguments, targetScope)) + + if (!_state.HasValidTarget(namedAttributeArguments, targetScope, out var targetHasDocCommentIdFormat, + out var targetSymbolString, out var targetValueOperation, out var resolvedSymbols)) { - rule = s_invalidOrMissingTargetDescriptor; + reportDiagnostic(Diagnostic.Create(s_invalidOrMissingTargetDescriptor, attributeSyntax.GetLocation())); + return; } - else + + // We want to flag valid target which uses legacy format to update to Roslyn based DocCommentId format. + if (resolvedSymbols.Length > 0 && !targetHasDocCommentIdFormat) { + RoslynDebug.Assert(!string.IsNullOrEmpty(targetSymbolString)); + RoslynDebug.Assert(targetValueOperation != null); + + var properties = ImmutableDictionary.Empty; + if (resolvedSymbols.Length == 1) + { + // We provide a code fix for the case where the target resolved to a single symbol. + var docCommentId = DocumentationCommentId.CreateDeclarationId(resolvedSymbols[0]); + if (!string.IsNullOrEmpty(docCommentId)) + { + // Suppression target has an optional "~" prefix to distinguish it from legacy FxCop suppressions. + // IDE suppression code fixes emit this prefix, so we we also add this prefix to new suppression target string. + properties = properties.Add(DocCommentIdKey, "~" + docCommentId); + } + } + + reportDiagnostic(Diagnostic.Create(LegacyFormatTargetDescriptor, targetValueOperation.Syntax.GetLocation(), properties!, targetSymbolString)); return; } - - reportDiagnostic(Diagnostic.Create(rule, attributeSyntax.GetLocation())); } } } diff --git a/src/Analyzers/Core/Analyzers/RemoveUnnecessarySuppressions/SuppressMessageAttributeState.cs b/src/Analyzers/Core/Analyzers/RemoveUnnecessarySuppressions/SuppressMessageAttributeState.cs index 6ebb231fd15b2..f4e7b3990db5f 100644 --- a/src/Analyzers/Core/Analyzers/RemoveUnnecessarySuppressions/SuppressMessageAttributeState.cs +++ b/src/Analyzers/Core/Analyzers/RemoveUnnecessarySuppressions/SuppressMessageAttributeState.cs @@ -5,8 +5,8 @@ #nullable enable using System; -using System.Collections.Generic; using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; using System.Threading; using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis.PooledObjects; @@ -20,7 +20,6 @@ internal partial class SuppressMessageAttributeState internal const string SuppressMessageTarget = "Target"; private static readonly ImmutableDictionary s_targetScopesMap = CreateTargetScopesMap(); - private static readonly ObjectPool> s_listPool = new ObjectPool>(() => new List()); private readonly Compilation _compilation; private readonly INamedTypeSymbol _suppressMessageAttributeType; @@ -82,9 +81,9 @@ simpleAssignment.Target is IPropertyReferenceOperation propertyReference && return namedAttributeArguments.Length > 0; } - public static bool HasInvalidScope(ImmutableArray<(string name, IOperation value)> namedAttributeArguments, out TargetScope targetScope) + public static bool HasValidScope(ImmutableArray<(string name, IOperation value)> namedAttributeArguments, out TargetScope targetScope) { - if (!TryGetNamedArgument(namedAttributeArguments, SuppressMessageScope, out var scopeString) || + if (!TryGetNamedArgument(namedAttributeArguments, SuppressMessageScope, out var scopeString, out _) || RoslynString.IsNullOrEmpty(scopeString)) { // Missing/Null/Empty scope values are treated equivalent to a compilation wide suppression. @@ -93,21 +92,32 @@ public static bool HasInvalidScope(ImmutableArray<(string name, IOperation value else if (!s_targetScopesMap.TryGetValue(scopeString, out targetScope)) { targetScope = TargetScope.None; - return true; + return false; } - return false; + return true; } - public bool HasInvalidOrMissingTarget(ImmutableArray<(string name, IOperation value)> namedAttributeArguments, TargetScope targetScope) + public bool HasValidTarget( + ImmutableArray<(string name, IOperation value)> namedAttributeArguments, + TargetScope targetScope, + out bool targetHasDocCommentIdFormat, + out string? targetSymbolString, + out IOperation? targetValueOperation, + out ImmutableArray resolvedSymbols) { + targetHasDocCommentIdFormat = false; + targetSymbolString = null; + targetValueOperation = null; + resolvedSymbols = ImmutableArray.Empty; + if (targetScope == TargetScope.Resource) { // Legacy scope which we do not handle. - return false; + return true; } - if (!TryGetNamedArgument(namedAttributeArguments, SuppressMessageTarget, out var targetSymbolString)) + if (!TryGetNamedArgument(namedAttributeArguments, SuppressMessageTarget, out targetSymbolString, out targetValueOperation)) { targetSymbolString = null; } @@ -115,24 +125,19 @@ public bool HasInvalidOrMissingTarget(ImmutableArray<(string name, IOperation va if (targetScope == TargetScope.Module) { // Compilation wide suppression with a non-null target is considered invalid. - return targetSymbolString != null; + 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); - } + var resolver = new TargetSymbolResolver(_compilation, targetScope, targetSymbolString); + resolvedSymbols = resolver.Resolve(out targetHasDocCommentIdFormat); + return !resolvedSymbols.IsEmpty; } - private static bool TryGetNamedArgument(ImmutableArray<(string name, IOperation value)> namedAttributeArguments, string argumentName, out string? argumentValue) + private static bool TryGetNamedArgument( + ImmutableArray<(string name, IOperation value)> namedAttributeArguments, + string argumentName, + out string? argumentValue, + [NotNullWhen(returnValue: true)] out IOperation? argumentValueOperation) { foreach (var (name, value) in namedAttributeArguments) { @@ -141,11 +146,13 @@ private static bool TryGetNamedArgument(ImmutableArray<(string name, IOperation value.ConstantValue.Value is string stringValue) { argumentValue = stringValue; + argumentValueOperation = value; return true; } } argumentValue = null; + argumentValueOperation = null; return false; } } diff --git a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.cs.xlf b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.cs.xlf index ddb52544bb1e9..1a2a05442ee6f 100644 --- a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.cs.xlf +++ b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.cs.xlf @@ -37,6 +37,16 @@ Přidat kvalifikaci „this“ nebo „Me“ + + Avoid legacy format target '{0}' in 'SuppressMessageAttribute' + Avoid legacy format target '{0}' in 'SuppressMessageAttribute' + + + + Avoid legacy format target in 'SuppressMessageAttribute' + Avoid legacy format target in 'SuppressMessageAttribute' + + Avoid unnecessary value assignments in your code, as these likely indicate redundant value computations. If the value computation is not redundant and you intend to retain the assignment, then change the assignment target to a local variable whose name starts with an underscore and is optionally followed by an integer, such as '_', '_1', '_2', etc. These are treated as special discard symbol names. Vyhněte se v kódu přiřazením nepotřebných hodnot, protože ta pravděpodobně indikují nadbytečné výpočty hodnot. Pokud výpočet hodnoty není nadbytečný a chcete dané přiřazení zachovat, změňte cíl přiřazení na místní proměnnou, jejíž název začíná podtržítkem, za kterým volitelně následuje celé číslo, například _, _1, _2 atd. Tyto řetězce se považují za názvy speciálních symbolů pro vyřazení. diff --git a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.de.xlf b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.de.xlf index 5f110fdcbeba5..92c7b0e0572f7 100644 --- a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.de.xlf +++ b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.de.xlf @@ -37,6 +37,16 @@ Qualifizierung "this" oder "Me" hinzufügen. + + Avoid legacy format target '{0}' in 'SuppressMessageAttribute' + Avoid legacy format target '{0}' in 'SuppressMessageAttribute' + + + + Avoid legacy format target in 'SuppressMessageAttribute' + Avoid legacy format target in 'SuppressMessageAttribute' + + Avoid unnecessary value assignments in your code, as these likely indicate redundant value computations. If the value computation is not redundant and you intend to retain the assignment, then change the assignment target to a local variable whose name starts with an underscore and is optionally followed by an integer, such as '_', '_1', '_2', etc. These are treated as special discard symbol names. Vermeiden Sie unnötige Wertzuweisungen in Ihrem Code, weil diese wahrscheinlich auf redundante Wertberechnungen hinweisen. Wenn die Wertberechnung nicht redundant ist und die Zuweisung beibehalten werden soll, ändern Sie das Zuweisungsziel in eine lokale Variable, deren Name mit einem Unterstrich beginnt, dem optional eine Zahl angefügt wird. Beispiel: "_", "_1", "_2" usw. Diese werden als spezielle Symbolnamen für Ausschussvariablen behandelt. diff --git a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.es.xlf b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.es.xlf index b0fa1d99f1127..eebfacec59dd5 100644 --- a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.es.xlf +++ b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.es.xlf @@ -37,6 +37,16 @@ Agregar cualificación 'this' o 'Me'. + + Avoid legacy format target '{0}' in 'SuppressMessageAttribute' + Avoid legacy format target '{0}' in 'SuppressMessageAttribute' + + + + Avoid legacy format target in 'SuppressMessageAttribute' + Avoid legacy format target in 'SuppressMessageAttribute' + + Avoid unnecessary value assignments in your code, as these likely indicate redundant value computations. If the value computation is not redundant and you intend to retain the assignment, then change the assignment target to a local variable whose name starts with an underscore and is optionally followed by an integer, such as '_', '_1', '_2', etc. These are treated as special discard symbol names. Evite las asignaciones de valores innecesarias en el código, ya que probablemente indican cálculos de valores redundantes. Si el cálculo de valor no es redundante y tiene intención de retener la asignación, cambie el destino de la asignación a una variable local cuyo nombre empiece por un carácter de subrayado, seguido opcionalmente por un entero, como "_", "_1", "_2", etc. Estos se tratan como nombres de símbolos de descarte especiales. diff --git a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.fr.xlf b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.fr.xlf index b3083a37453fb..531262c46c52a 100644 --- a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.fr.xlf +++ b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.fr.xlf @@ -37,6 +37,16 @@ Ajoutez la qualification 'this' ou 'Me'. + + Avoid legacy format target '{0}' in 'SuppressMessageAttribute' + Avoid legacy format target '{0}' in 'SuppressMessageAttribute' + + + + Avoid legacy format target in 'SuppressMessageAttribute' + Avoid legacy format target in 'SuppressMessageAttribute' + + Avoid unnecessary value assignments in your code, as these likely indicate redundant value computations. If the value computation is not redundant and you intend to retain the assignment, then change the assignment target to a local variable whose name starts with an underscore and is optionally followed by an integer, such as '_', '_1', '_2', etc. These are treated as special discard symbol names. Évitez les assignations de valeurs inutiles dans votre code, car elles représentent probablement des calculs de valeurs redondants. Si un calcul de valeur n'est pas redondant et si vous souhaitez conserver l'assignation, remplacez la cible de l'assignation par une variable locale dont le nom commence par un trait de soulignement éventuellement suivi d'un entier, par exemple '_', '_1', '_2', etc. Ces types d'élément sont traités en tant que noms de symboles discard spéciaux. diff --git a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.it.xlf b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.it.xlf index 44270f01ca6a9..b1fb2127c50ac 100644 --- a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.it.xlf +++ b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.it.xlf @@ -37,6 +37,16 @@ Aggiunge la qualificazione 'this' o 'Me'. + + Avoid legacy format target '{0}' in 'SuppressMessageAttribute' + Avoid legacy format target '{0}' in 'SuppressMessageAttribute' + + + + Avoid legacy format target in 'SuppressMessageAttribute' + Avoid legacy format target in 'SuppressMessageAttribute' + + Avoid unnecessary value assignments in your code, as these likely indicate redundant value computations. If the value computation is not redundant and you intend to retain the assignment, then change the assignment target to a local variable whose name starts with an underscore and is optionally followed by an integer, such as '_', '_1', '_2', etc. These are treated as special discard symbol names. Evitare assegnazioni di valori non necessarie nel codice perché indicano probabilmente calcoli di valori ridondanti. Se il calcolo del valore non è ridondante e si intende mantenere l'assegnazione, modificare la destinazione dell'assegnazione in una variabile locale il cui nome inizia con un carattere di sottolineatura e, facoltativamente, è seguito da un numero intero, ad esempio '_', '_1', '_2' e così via. Questi vengono considerati come nomi di simboli speciali di rimozione. diff --git a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.ja.xlf b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.ja.xlf index d19aaf2ad71a1..f1ebac6259199 100644 --- a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.ja.xlf +++ b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.ja.xlf @@ -37,6 +37,16 @@ this' または 'Me' 修飾子を追加します。 + + Avoid legacy format target '{0}' in 'SuppressMessageAttribute' + Avoid legacy format target '{0}' in 'SuppressMessageAttribute' + + + + Avoid legacy format target in 'SuppressMessageAttribute' + Avoid legacy format target in 'SuppressMessageAttribute' + + Avoid unnecessary value assignments in your code, as these likely indicate redundant value computations. If the value computation is not redundant and you intend to retain the assignment, then change the assignment target to a local variable whose name starts with an underscore and is optionally followed by an integer, such as '_', '_1', '_2', etc. These are treated as special discard symbol names. コード内における不必要な値代入は、値計算が重複する原因になり得るため、避けてください。値計算が重複しておらず、代入を保持する場合は、代入先をアンダースコアの後にオプションで整数が続く名前 ('_'、'_1'、'_2' など) のローカル変数に変更してください。これらは、特別なディスカード シンボル名として扱われます。 diff --git a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.ko.xlf b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.ko.xlf index 55ad31a5de636..ebb0839385785 100644 --- a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.ko.xlf +++ b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.ko.xlf @@ -37,6 +37,16 @@ this' 또는 'Me' 한정자를 추가합니다. + + Avoid legacy format target '{0}' in 'SuppressMessageAttribute' + Avoid legacy format target '{0}' in 'SuppressMessageAttribute' + + + + Avoid legacy format target in 'SuppressMessageAttribute' + Avoid legacy format target in 'SuppressMessageAttribute' + + Avoid unnecessary value assignments in your code, as these likely indicate redundant value computations. If the value computation is not redundant and you intend to retain the assignment, then change the assignment target to a local variable whose name starts with an underscore and is optionally followed by an integer, such as '_', '_1', '_2', etc. These are treated as special discard symbol names. 코드에 불필요한 값을 할당하면 값의 중복 계산으로 표시될 수 있으므로 이와 같은 할당을 사용하지 않도록 합니다. 값의 중복 계산이 아닌 할당을 유지하려는 경우 할당 대상을 이름이 밑줄로 시작하고 필요에 따라 뒤에 정수가 있는(예: '_', '_1', '_2' 등) 지역 변수로 변경합니다. 해당 이름은 특수 무시 기호 이름으로 처리됩니다. diff --git a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.pl.xlf b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.pl.xlf index 1005362beab5b..2bef739117b29 100644 --- a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.pl.xlf +++ b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.pl.xlf @@ -37,6 +37,16 @@ Dodaj kwalifikacje „this” lub „Me”. + + Avoid legacy format target '{0}' in 'SuppressMessageAttribute' + Avoid legacy format target '{0}' in 'SuppressMessageAttribute' + + + + Avoid legacy format target in 'SuppressMessageAttribute' + Avoid legacy format target in 'SuppressMessageAttribute' + + Avoid unnecessary value assignments in your code, as these likely indicate redundant value computations. If the value computation is not redundant and you intend to retain the assignment, then change the assignment target to a local variable whose name starts with an underscore and is optionally followed by an integer, such as '_', '_1', '_2', etc. These are treated as special discard symbol names. Unikaj niepotrzebnych przypisań wartości w kodzie, ponieważ mogą one wskazywać nadmiarowe obliczenia wartości. Jeśli obliczenie wartości nie jest nadmiarowe i zamierzasz zachować przypisanie, zmień wartość docelową przypisania na zmienną lokalną, której nazwa rozpoczyna się od znaku podkreślenia, a opcjonalnie następuje po niej liczba całkowita, taka jak „_”, „_1”, „_2” itp. Są one traktowane jako specjalne nazwy symboli odrzucenia. diff --git a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.pt-BR.xlf b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.pt-BR.xlf index 0565b05376f56..fb00c9526e87d 100644 --- a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.pt-BR.xlf +++ b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.pt-BR.xlf @@ -37,6 +37,16 @@ Adicionar a qualificação 'this' ou 'Me'. + + Avoid legacy format target '{0}' in 'SuppressMessageAttribute' + Avoid legacy format target '{0}' in 'SuppressMessageAttribute' + + + + Avoid legacy format target in 'SuppressMessageAttribute' + Avoid legacy format target in 'SuppressMessageAttribute' + + Avoid unnecessary value assignments in your code, as these likely indicate redundant value computations. If the value computation is not redundant and you intend to retain the assignment, then change the assignment target to a local variable whose name starts with an underscore and is optionally followed by an integer, such as '_', '_1', '_2', etc. These are treated as special discard symbol names. Evite atribuições de valor desnecessárias no código, pois isso pode indicar cálculos de valor redundantes. Se o cálculo do valor não for redundante e você pretender reter a atribuição, altere o destino da atribuição para uma variável local cujo nome comece com um sublinhado e seja seguido opcionalmente por um inteiro, como '_', '_1', '_2' etc. Esses nomes são tratados como nomes de símbolo de descarte especiais. diff --git a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.ru.xlf b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.ru.xlf index 192b60c36e57e..ca0b30e2b1e35 100644 --- a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.ru.xlf +++ b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.ru.xlf @@ -37,6 +37,16 @@ Добавьте квалификацию "this" или "Me". + + Avoid legacy format target '{0}' in 'SuppressMessageAttribute' + Avoid legacy format target '{0}' in 'SuppressMessageAttribute' + + + + Avoid legacy format target in 'SuppressMessageAttribute' + Avoid legacy format target in 'SuppressMessageAttribute' + + Avoid unnecessary value assignments in your code, as these likely indicate redundant value computations. If the value computation is not redundant and you intend to retain the assignment, then change the assignment target to a local variable whose name starts with an underscore and is optionally followed by an integer, such as '_', '_1', '_2', etc. These are treated as special discard symbol names. Избегайте ненужных операций присваивания значений в коде, так как это может свидетельствовать об избыточных вычислениях значений. Если вычисление значения не является избыточным и предполагается сохранить присваивание, измените целевой объект присваивания на локальную переменную, имя которой начинается с символа подчеркивания, за которым при необходимости следует целое число, например, "_", "_1", "_2" и т. д. Эти имена рассматриваются как специальные имена для освобождаемых переменных. diff --git a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.tr.xlf b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.tr.xlf index 7c883b3c49845..f41b6fd011436 100644 --- a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.tr.xlf +++ b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.tr.xlf @@ -37,6 +37,16 @@ 'this' veya 'Me' niteliği ekle. + + Avoid legacy format target '{0}' in 'SuppressMessageAttribute' + Avoid legacy format target '{0}' in 'SuppressMessageAttribute' + + + + Avoid legacy format target in 'SuppressMessageAttribute' + Avoid legacy format target in 'SuppressMessageAttribute' + + Avoid unnecessary value assignments in your code, as these likely indicate redundant value computations. If the value computation is not redundant and you intend to retain the assignment, then change the assignment target to a local variable whose name starts with an underscore and is optionally followed by an integer, such as '_', '_1', '_2', etc. These are treated as special discard symbol names. Kodunuzda gereksiz değer atamaları yapmaktan kaçının; bunlar genelde gereksiz değer hesaplamalarını belirtir. Değer hesaplaması gereksiz değilse ve atamayı korumak istiyorsanız, atama hedefini adı bir alt çizgiyle başlayan ve isteğe bağlı olarak tamsayı ile devam eden yerel bir değişkene çevirin, örneğin '_', '_1', '_2' vb. Bunlar özel atma sembol adları olarak değerlendirilir. diff --git a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.zh-Hans.xlf b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.zh-Hans.xlf index 4a99f9d6f4200..69cd4602e685f 100644 --- a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.zh-Hans.xlf +++ b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.zh-Hans.xlf @@ -37,6 +37,16 @@ 添加 "this" 或 "Me" 限定。 + + Avoid legacy format target '{0}' in 'SuppressMessageAttribute' + Avoid legacy format target '{0}' in 'SuppressMessageAttribute' + + + + Avoid legacy format target in 'SuppressMessageAttribute' + Avoid legacy format target in 'SuppressMessageAttribute' + + Avoid unnecessary value assignments in your code, as these likely indicate redundant value computations. If the value computation is not redundant and you intend to retain the assignment, then change the assignment target to a local variable whose name starts with an underscore and is optionally followed by an integer, such as '_', '_1', '_2', etc. These are treated as special discard symbol names. 请避免在代码中使用不必要的值赋值,因为这些值极有可能指示冗余的值计算。如果值计算不是冗余的,并且打算保留该赋值,请将分配目标更改为名称以下划线开头或在下划线后面跟一个整数的局部变量(如 "_"、"_1"、"_2" 等)。这些被视为特殊丢弃符号名。 diff --git a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.zh-Hant.xlf b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.zh-Hant.xlf index 67a7fbfe54df9..e2d46f6f63375 100644 --- a/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.zh-Hant.xlf +++ b/src/Analyzers/Core/Analyzers/xlf/AnalyzersResources.zh-Hant.xlf @@ -37,6 +37,16 @@ 新增 'this' 或 'Me' 限定性條件。 + + Avoid legacy format target '{0}' in 'SuppressMessageAttribute' + Avoid legacy format target '{0}' in 'SuppressMessageAttribute' + + + + Avoid legacy format target in 'SuppressMessageAttribute' + Avoid legacy format target in 'SuppressMessageAttribute' + + Avoid unnecessary value assignments in your code, as these likely indicate redundant value computations. If the value computation is not redundant and you intend to retain the assignment, then change the assignment target to a local variable whose name starts with an underscore and is optionally followed by an integer, such as '_', '_1', '_2', etc. These are treated as special discard symbol names. 請避免在您的程式碼中指派非必要的值,因為這可能表示值會重複計算。如果值未重複計算,而且您想要保留指派,請將指派目標變更為名稱以底線開頭的區域變數,並可選擇在後面接著整數,例如 '_'、'_1'、'_2' 等。這些會視為特殊的捨棄符號名稱。 diff --git a/src/Analyzers/Core/CodeFixes/CodeFixes.projitems b/src/Analyzers/Core/CodeFixes/CodeFixes.projitems index 098c29321c07a..67f85b37164c7 100644 --- a/src/Analyzers/Core/CodeFixes/CodeFixes.projitems +++ b/src/Analyzers/Core/CodeFixes/CodeFixes.projitems @@ -25,6 +25,7 @@ + diff --git a/src/Analyzers/Core/CodeFixes/CodeFixesResources.resx b/src/Analyzers/Core/CodeFixes/CodeFixesResources.resx index 3c5b2db86ac11..e9a3f126470a2 100644 --- a/src/Analyzers/Core/CodeFixes/CodeFixesResources.resx +++ b/src/Analyzers/Core/CodeFixes/CodeFixesResources.resx @@ -141,4 +141,7 @@ Remove redundant suppression + + Update suppression format + \ No newline at end of file diff --git a/src/Analyzers/Core/CodeFixes/PredefinedCodeFixProviderNames.cs b/src/Analyzers/Core/CodeFixes/PredefinedCodeFixProviderNames.cs index dedb006d4f0c2..017897942bbf4 100644 --- a/src/Analyzers/Core/CodeFixes/PredefinedCodeFixProviderNames.cs +++ b/src/Analyzers/Core/CodeFixes/PredefinedCodeFixProviderNames.cs @@ -64,6 +64,7 @@ internal static class PredefinedCodeFixProviderNames public const string AddOverloads = nameof(AddOverloads); public const string AddNew = nameof(AddNew); public const string RemoveNew = nameof(RemoveNew); + public const string UpdateLegacySuppressions = nameof(UpdateLegacySuppressions); public const string UnsealClass = nameof(UnsealClass); public const string UseImplicitType = nameof(UseImplicitType); public const string UseExplicitType = nameof(UseExplicitType); diff --git a/src/Analyzers/Core/CodeFixes/UpdateLegacySuppressions/UpdateLegacySuppressionsCodeFixProvider.cs b/src/Analyzers/Core/CodeFixes/UpdateLegacySuppressions/UpdateLegacySuppressionsCodeFixProvider.cs new file mode 100644 index 0000000000000..3d4c04f9edd3f --- /dev/null +++ b/src/Analyzers/Core/CodeFixes/UpdateLegacySuppressions/UpdateLegacySuppressionsCodeFixProvider.cs @@ -0,0 +1,69 @@ +// 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; +using Microsoft.CodeAnalysis.RemoveUnnecessarySuppressions; + +namespace Microsoft.CodeAnalysis.UpdateLegacySuppressions +{ + [ExportCodeFixProvider(LanguageNames.CSharp, LanguageNames.VisualBasic, Name = PredefinedCodeFixProviderNames.UpdateLegacySuppressions), Shared] + internal sealed class UpdateLegacySuppressionsCodeFixProvider : SyntaxEditorBasedCodeFixProvider + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public UpdateLegacySuppressionsCodeFixProvider() + { + } + + public override ImmutableArray FixableDiagnosticIds + => ImmutableArray.Create(IDEDiagnosticIds.LegacyFormatSuppressMessageAttributeDiagnosticId); + + internal override CodeFixCategory CodeFixCategory + => CodeFixCategory.CodeQuality; + + public override async Task RegisterCodeFixesAsync(CodeFixContext context) + { + var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); + foreach (var diagnostic in context.Diagnostics) + { + if (diagnostic.Properties?.ContainsKey(AbstractRemoveUnnecessarySuppressionsDiagnosticAnalyzer.DocCommentIdKey) == true && + root.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true) != null) + { + context.RegisterCodeFix( + new MyCodeAction(c => FixAsync(context.Document, diagnostic, c)), + diagnostic); + } + } + } + + protected override Task FixAllAsync(Document document, ImmutableArray diagnostics, SyntaxEditor editor, CancellationToken cancellationToken) + { + foreach (var diagnostic in diagnostics) + { + var node = editor.OriginalRoot.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true); + var newDocCommentId = diagnostic.Properties[AbstractRemoveUnnecessarySuppressionsDiagnosticAnalyzer.DocCommentIdKey]; + editor.ReplaceNode(node, editor.Generator.LiteralExpression(newDocCommentId).WithTriviaFrom(node)); + } + + return Task.CompletedTask; + } + + private class MyCodeAction : CustomCodeActions.DocumentChangeAction + { + public MyCodeAction(Func> createChangedDocument) + : base(CodeFixesResources.Update_suppression_format, createChangedDocument, nameof(UpdateLegacySuppressionsCodeFixProvider)) + { + } + } + } +} diff --git a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.cs.xlf b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.cs.xlf index 9782d34ed8dbc..cd061882f7983 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.cs.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.cs.xlf @@ -32,6 +32,11 @@ Remove redundant suppression + + Update suppression format + Update suppression format + + Use discard '_' Použít zahození _ diff --git a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.de.xlf b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.de.xlf index baeb79d1b82b8..84f30a0d7ac09 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.de.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.de.xlf @@ -32,6 +32,11 @@ Remove redundant suppression + + Update suppression format + Update suppression format + + Use discard '_' Ausschussvariable "_" verwenden diff --git a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.es.xlf b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.es.xlf index b2d9787ff38a0..e3bab6060cd2d 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.es.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.es.xlf @@ -32,6 +32,11 @@ Remove redundant suppression + + Update suppression format + Update suppression format + + Use discard '_' Usar opción de descarte "_" diff --git a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.fr.xlf b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.fr.xlf index e680cc3ab327c..ad61f4b158c7a 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.fr.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.fr.xlf @@ -32,6 +32,11 @@ Remove redundant suppression + + Update suppression format + Update suppression format + + Use discard '_' Utiliser Ignorer '_' diff --git a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.it.xlf b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.it.xlf index 4fd93b3cc818c..850af7d21630c 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.it.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.it.xlf @@ -32,6 +32,11 @@ Remove redundant suppression + + Update suppression format + Update suppression format + + Use discard '_' Usa '_' rimosso diff --git a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ja.xlf b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ja.xlf index 201e81e18adb5..fc11013cbe364 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ja.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ja.xlf @@ -32,6 +32,11 @@ Remove redundant suppression + + Update suppression format + Update suppression format + + Use discard '_' 破棄 '_' を使用 diff --git a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ko.xlf b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ko.xlf index e8b0e0f2d7025..18a51f63cbeb7 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ko.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ko.xlf @@ -32,6 +32,11 @@ Remove redundant suppression + + Update suppression format + Update suppression format + + Use discard '_' 무시 항목 '_' 사용 diff --git a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.pl.xlf b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.pl.xlf index 41ac3d2d1f08f..5869f632ddab2 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.pl.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.pl.xlf @@ -32,6 +32,11 @@ Remove redundant suppression + + Update suppression format + Update suppression format + + Use discard '_' Użyj odrzucenia „_” diff --git a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.pt-BR.xlf b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.pt-BR.xlf index 577d6b2cdc442..42e71e7285aea 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.pt-BR.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.pt-BR.xlf @@ -32,6 +32,11 @@ Remove redundant suppression + + Update suppression format + Update suppression format + + Use discard '_' Usar o descarte de '_' diff --git a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ru.xlf b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ru.xlf index 4f6af8852265c..425bbebcff550 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ru.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.ru.xlf @@ -32,6 +32,11 @@ Remove redundant suppression + + Update suppression format + Update suppression format + + Use discard '_' Используйте символ удаления "_" diff --git a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.tr.xlf b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.tr.xlf index b3e81d92db44b..00f988073eda4 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.tr.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.tr.xlf @@ -32,6 +32,11 @@ Remove redundant suppression + + Update suppression format + Update suppression format + + Use discard '_' '_' atmasını kullan diff --git a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.zh-Hans.xlf b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.zh-Hans.xlf index ab5fc6f2e54ec..6274a8ee616a9 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.zh-Hans.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.zh-Hans.xlf @@ -32,6 +32,11 @@ Remove redundant suppression + + Update suppression format + Update suppression format + + Use discard '_' 使用丢弃 "_" diff --git a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.zh-Hant.xlf b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.zh-Hant.xlf index 8295210e99ca7..4800fc56979e5 100644 --- a/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.zh-Hant.xlf +++ b/src/Analyzers/Core/CodeFixes/xlf/CodeFixesResources.zh-Hant.xlf @@ -32,6 +32,11 @@ Remove redundant suppression + + Update suppression format + Update suppression format + + Use discard '_' 使用捨棄 '_’ diff --git a/src/Analyzers/VisualBasic/Tests/UpdateLegacySuppressions/UpdateLegacySuppressionsTests.vb b/src/Analyzers/VisualBasic/Tests/UpdateLegacySuppressions/UpdateLegacySuppressionsTests.vb new file mode 100644 index 0000000000000..048d179d9bfe5 --- /dev/null +++ b/src/Analyzers/VisualBasic/Tests/UpdateLegacySuppressions/UpdateLegacySuppressionsTests.vb @@ -0,0 +1,80 @@ +' 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.RemoveUnnecessarySuppressions +Imports VerifyVB = Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions.VisualBasicCodeFixVerifier(Of + Microsoft.CodeAnalysis.VisualBasic.RemoveUnnecessarySuppressions.VisualBasicRemoveUnnecessarySuppressionsDiagnosticAnalyzer, + Microsoft.CodeAnalysis.UpdateLegacySuppressions.UpdateLegacySuppressionsCodeFixProvider) + +Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.UpdateLegacySuppressions + + + + Public Class UpdateLegacySuppressionsTests + + Public Sub TestStandardProperties() + VerifyVB.VerifyStandardProperties() + End Sub + + + + + + + + + + Public Async Function LegacySuppressions(scope As String, target As String, fixedTarget As String) As Task + Dim input = $" + + +Namespace N + Class C + Private F As Integer + Public Property P As Integer + + Public Sub M() + End Sub + + Public Function M2(Of T)(tParam As T) As Integer + Return 0 + End Function + + Public Event E As System.EventHandler(Of Integer) + + Class D + End Class + End Class +End Namespace +" + Dim expectedDiagnostic = VerifyVB.Diagnostic(AbstractRemoveUnnecessarySuppressionsDiagnosticAnalyzer.LegacyFormatTargetDescriptor). + WithLocation(0). + WithArguments(target) + + Dim fixedCode = $" + + +Namespace N + Class C + Private F As Integer + Public Property P As Integer + + Public Sub M() + End Sub + + Public Function M2(Of T)(tParam As T) As Integer + Return 0 + End Function + + Public Event E As System.EventHandler(Of Integer) + + Class D + End Class + End Class +End Namespace +" + Await VerifyVB.VerifyCodeFixAsync(input, expectedDiagnostic, fixedCode) + End Function + End Class +End Namespace diff --git a/src/Analyzers/VisualBasic/Tests/VisualBasicAnalyzers.UnitTests.projitems b/src/Analyzers/VisualBasic/Tests/VisualBasicAnalyzers.UnitTests.projitems index c32285c78af73..14a9159341919 100644 --- a/src/Analyzers/VisualBasic/Tests/VisualBasicAnalyzers.UnitTests.projitems +++ b/src/Analyzers/VisualBasic/Tests/VisualBasicAnalyzers.UnitTests.projitems @@ -13,6 +13,7 @@ + diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/SuppressMessageAttributeState.TargetSymbolResolver.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/SuppressMessageAttributeState.TargetSymbolResolver.cs index e30eaa4f5dee0..8ee3f4fb6b0f9 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/SuppressMessageAttributeState.TargetSymbolResolver.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/SuppressMessageAttributeState.TargetSymbolResolver.cs @@ -55,11 +55,17 @@ private static string RemovePrefix(string id, string prefix) return id; } - public void Resolve(IList results) + /// + /// Attempts to resolve the "Target" argument of the global SuppressMessageAttribute to symbols in compilation. + /// + /// Indicates if resolved "Target" argument is in Roslyn's format. + /// Resolved symbols for the the "Target" argument of the global SuppressMessageAttribute. + public ImmutableArray Resolve(out bool resolvedWithDocCommentIdFormat) { + resolvedWithDocCommentIdFormat = false; if (string.IsNullOrEmpty(_name)) { - return; + return ImmutableArray.Empty; } // Try to parse the name as declaration ID generated from symbol's documentation comment Id. @@ -67,14 +73,12 @@ public void Resolve(IList results) var docIdResults = DocumentationCommentId.GetSymbolsForDeclarationId(nameWithoutPrefix, _compilation); if (docIdResults.Length > 0) { - foreach (var result in docIdResults) - { - results.Add(result); - } - - return; + resolvedWithDocCommentIdFormat = true; + return docIdResults; } + var results = ArrayBuilder.GetInstance(); + // Parse 'e:' prefix used by FxCop to differentiate between event and non-event symbols of the same name. bool isEvent = false; if (_name.Length >= 2 && _name[0] == 'e' && _name[1] == ':') @@ -104,7 +108,7 @@ public void Resolve(IList results) var candidateMembers = containingSymbol.GetMembers(segment); if (candidateMembers.Length == 0) { - return; + break; } if (segmentIsNamedTypeName.HasValue) @@ -135,7 +139,7 @@ public void Resolve(IList results) if (parameters == null) { // Failed to resolve parameter list - return; + break; } } else if (nextChar == '.' || nextChar == '+') @@ -159,7 +163,7 @@ public void Resolve(IList results) { // If we cannot resolve the name on the left of the delimiter, we have no // hope of finding the symbol. - return; + break; } if (containingSymbol.Kind == SymbolKind.NamedType) @@ -186,7 +190,7 @@ public void Resolve(IList results) results.Add(method); } - return; + break; } ISymbol singleResult; @@ -226,9 +230,9 @@ public void Resolve(IList results) { results.Add(singleResult); } - - return; } + + return results.ToImmutableAndFree(); } private string ParseNextNameSegment() diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/SuppressMessageAttributeState.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/SuppressMessageAttributeState.cs index 556f4a5333d57..e6be2feeea9ce 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/SuppressMessageAttributeState.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/SuppressMessageAttributeState.cs @@ -324,24 +324,20 @@ private static void DecodeGlobalSuppressMessageAttributes(Compilation compilatio } } - internal static IEnumerable ResolveTargetSymbols(Compilation compilation, string target, TargetScope scope) + internal static ImmutableArray ResolveTargetSymbols(Compilation compilation, string target, TargetScope scope) { switch (scope) { case TargetScope.Namespace: case TargetScope.Type: case TargetScope.Member: - { - var results = new List(); - new TargetSymbolResolver(compilation, scope, target).Resolve(results); - return results; - } + return new TargetSymbolResolver(compilation, scope, target).Resolve(out _); case TargetScope.NamespaceAndDescendants: return ResolveTargetSymbols(compilation, target, TargetScope.Namespace); default: - return SpecializedCollections.EmptyEnumerable(); + return ImmutableArray.Empty; } } diff --git a/src/EditorFeatures/Test/Diagnostics/IDEDiagnosticIDConfigurationTests.cs b/src/EditorFeatures/Test/Diagnostics/IDEDiagnosticIDConfigurationTests.cs index 9256a9e593d31..deed9b2b1ba7d 100644 --- a/src/EditorFeatures/Test/Diagnostics/IDEDiagnosticIDConfigurationTests.cs +++ b/src/EditorFeatures/Test/Diagnostics/IDEDiagnosticIDConfigurationTests.cs @@ -379,6 +379,9 @@ public void CSharp_VerifyIDEDiagnosticSeveritiesAreConfigurable() # IDE0076 dotnet_diagnostic.IDE0076.severity = %value% +# IDE0077 +dotnet_diagnostic.IDE0077.severity = %value% + # IDE1005 csharp_style_conditional_delegate_call = true:suggestion @@ -522,6 +525,9 @@ public void VisualBasic_VerifyIDEDiagnosticSeveritiesAreConfigurable() # IDE0076 dotnet_diagnostic.IDE0076.severity = %value% +# IDE0077 +dotnet_diagnostic.IDE0077.severity = %value% + # IDE1006 dotnet_diagnostic.IDE1006.severity = %value% @@ -891,6 +897,9 @@ No editorconfig based code style option # IDE0076 No editorconfig based code style option +# IDE0077 +No editorconfig based code style option + # IDE1005, PreferConditionalDelegateCall csharp_style_conditional_delegate_call = true:suggestion @@ -1067,6 +1076,9 @@ No editorconfig based code style option # IDE0076 No editorconfig based code style option +# IDE0077 +No editorconfig based code style option + # IDE1006 No editorconfig based code style option diff --git a/src/Test/Utilities/Portable/Traits/Traits.cs b/src/Test/Utilities/Portable/Traits/Traits.cs index 361ddb14bb240..b251d099b5b05 100644 --- a/src/Test/Utilities/Portable/Traits/Traits.cs +++ b/src/Test/Utilities/Portable/Traits/Traits.cs @@ -159,6 +159,7 @@ public static class Features public const string CodeActionsSuppression = "CodeActions.Suppression"; public const string CodeActionsSyncNamespace = "CodeActions.SyncNamespace"; public const string CodeActionsUnsealClass = "CodeActions.UnsealClass"; + public const string CodeActionsUpdateLegacySuppressions = "CodeActions.UpdateLegacySuppressions"; public const string CodeActionsUpdateProjectToAllowUnsafe = "CodeActions.UpdateProjectToAllowUnsafe"; public const string CodeActionsUpgradeProject = "CodeActions.UpgradeProject"; public const string CodeActionsUseAutoProperty = "CodeActions.UseAutoProperty";