From 15305ccf113fcf801d9b075e3e7e775cc60f2457 Mon Sep 17 00:00:00 2001 From: Joey Robichaud Date: Thu, 25 Feb 2021 18:31:26 -0800 Subject: [PATCH] Add option to filter diagnostics by id --- README.md | 6 ++- docs/README.md | 14 +++++ perf/FormattedFiles.cs | 4 ++ perf/NoFilesFormatted.cs | 4 ++ perf/RealWorldSolution.cs | 3 ++ src/Analyzers/AnalyzerFormatter.cs | 18 ++++++- src/FormatCommand.cs | 5 ++ src/FormatOptions.cs | 6 +++ src/Formatters/UnnecessaryImportsFormatter.cs | 7 +++ src/Program.cs | 3 ++ src/Resources.resx | 3 ++ src/xlf/Resources.cs.xlf | 5 ++ src/xlf/Resources.de.xlf | 5 ++ src/xlf/Resources.es.xlf | 5 ++ src/xlf/Resources.fr.xlf | 5 ++ src/xlf/Resources.it.xlf | 5 ++ src/xlf/Resources.ja.xlf | 5 ++ src/xlf/Resources.ko.xlf | 5 ++ src/xlf/Resources.pl.xlf | 5 ++ src/xlf/Resources.pt-BR.xlf | 5 ++ src/xlf/Resources.ru.xlf | 5 ++ src/xlf/Resources.tr.xlf | 5 ++ src/xlf/Resources.zh-Hans.xlf | 5 ++ src/xlf/Resources.zh-Hant.xlf | 5 ++ .../CodeStyleAnalyzerFormatterTests.cs | 44 +++++++++++++++ tests/Analyzers/FilterDiagnosticsTests.cs | 49 ++++++++++++++++- tests/CodeFormatterTests.cs | 5 +- tests/Formatters/AbstractFormatterTests.cs | 34 +++++++----- tests/Formatters/FormattedFilesTests.cs | 2 + .../UnnecessaryImportsFormatterTests.cs | 53 +++++++++++++++++++ tests/ProgramTests.cs | 5 ++ 31 files changed, 310 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index aeb6105df8..b0c9893d21 100644 --- a/README.md +++ b/README.md @@ -101,6 +101,7 @@ Options: --fix-whitespace, -w Run whitespace formatting. Run by default when not applying fixes. --fix-style, -s Run code style analyzers and apply fixes. --fix-analyzers, -a Run 3rd party analyzers and apply fixes. + --diagnostics A space separated list of diagnostic ids to use as a filter when fixing code style or 3rd party analyzers. --include A list of relative file or folder paths to include in formatting. All files are formatted if empty. --exclude A list of relative file or folder paths to exclude from formatting. --check Formats files without saving changes to disk. Terminates with a non-zero exit code if any files were formatted. @@ -117,6 +118,7 @@ Add `format` after `dotnet` and before the command arguments that you want to ru | `dotnet format ` | Formats a specific project or solution. | | `dotnet format -f` | Formats a particular folder and subfolders. | | `dotnet format --fix-style warn` | Fixes only codestyle analyzer warnings. | +| `dotnet format --fix-style --diagnostics IDE0005` | Fixes only codestyle analyzer errors for the IDE0005 diagnostic. | | `dotnet format --fix-whitespace --fix-style` | Formats and fixes codestyle analyzer errors. | | `dotnet format --fix-analyzers` | Fixes only 3rd party analyzer errors. | | `dotnet format -wsa` | Formats, fixes codestyle errors, and fixes 3rd party analyzer errors. | @@ -143,8 +145,8 @@ You can build and package the tool using the following commands. The instruction ```console build -pack # The final line from the build will read something like -# Successfully created package '..\artifacts\packages\Debug\Shipping\dotnet-format.6.0.0-dev.nupkg'. -# Use the value that is in the form `6.0.0-dev` as the version in the next command. +# Successfully created package '..\artifacts\packages\Debug\Shipping\dotnet-format.5.1.0-dev.nupkg'. +# Use the value that is in the form `5.1.0-dev` as the version in the next command. dotnet tool install --add-source .\artifacts\packages\Debug\Shipping -g dotnet-format --version dotnet format ``` diff --git a/docs/README.md b/docs/README.md index 52a6d4026b..362eb74989 100644 --- a/docs/README.md +++ b/docs/README.md @@ -82,6 +82,20 @@ Running 3rd party analysis requires the use of a MSBuild solution or project fil - `--fix-analyzers ` - Runs analysis and attempts to fix issues with severity equal or greater than specified. If no severity is specified then this defaults to error. +#### Filter diagnostics to fix + +Typically when running codestyle or 3rd party analysis, all diagnostics of sufficient severity are reported and fixed. The `--diagnostics` option allows you to target a particular diagnostic or set of diagnostics of sufficient severity. + +- `--diagnostics ` - When used in conjunction with `--fix-style` or `--fix-analyzer`, allows you to apply targeted fixes for particular analyzers. + +*Example:* + +Run code-style analysis and fix unused using directive errors. + +```console +dotnet-format ./format.sln --fix-style --diagnostics IDE0005 +``` + ### Filter files to format You can further narrow the list of files to be formatted by specifying a list of paths to include or exclude. When specifying folder paths the path must end with a directory separator. File globbing is supported. diff --git a/perf/FormattedFiles.cs b/perf/FormattedFiles.cs index 16f74f506f..8252e700a0 100644 --- a/perf/FormattedFiles.cs +++ b/perf/FormattedFiles.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information. using System; +using System.Collections.Immutable; using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Jobs; using Microsoft.CodeAnalysis.Tools.Utilities; @@ -36,6 +37,7 @@ public void FilesFormattedFolder() fixCategory: FixCategory.Whitespace, codeStyleSeverity: DiagnosticSeverity.Error, analyzerSeverity: DiagnosticSeverity.Error, + diagnostics: ImmutableHashSet.Empty, saveFormattedFiles: false, changesAreErrors: false, AllFileMatcher, @@ -55,6 +57,7 @@ public void FilesFormattedProject() fixCategory: FixCategory.Whitespace, codeStyleSeverity: DiagnosticSeverity.Error, analyzerSeverity: DiagnosticSeverity.Error, + diagnostics: ImmutableHashSet.Empty, saveFormattedFiles: false, changesAreErrors: false, AllFileMatcher, @@ -74,6 +77,7 @@ public void FilesFormattedSolution() fixCategory: FixCategory.Whitespace, codeStyleSeverity: DiagnosticSeverity.Error, analyzerSeverity: DiagnosticSeverity.Error, + diagnostics: ImmutableHashSet.Empty, saveFormattedFiles: false, changesAreErrors: false, AllFileMatcher, diff --git a/perf/NoFilesFormatted.cs b/perf/NoFilesFormatted.cs index 7dfbfc2cd4..2d68b474e5 100644 --- a/perf/NoFilesFormatted.cs +++ b/perf/NoFilesFormatted.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information. using System; +using System.Collections.Immutable; using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Jobs; using Microsoft.CodeAnalysis.Tools.Utilities; @@ -36,6 +37,7 @@ public void NoFilesFormattedFolder() fixCategory: FixCategory.Whitespace, codeStyleSeverity: DiagnosticSeverity.Error, analyzerSeverity: DiagnosticSeverity.Error, + diagnostics: ImmutableHashSet.Empty, saveFormattedFiles: false, changesAreErrors: false, AllFileMatcher, @@ -55,6 +57,7 @@ public void NoFilesFormattedProject() fixCategory: FixCategory.Whitespace, codeStyleSeverity: DiagnosticSeverity.Error, analyzerSeverity: DiagnosticSeverity.Error, + diagnostics: ImmutableHashSet.Empty, saveFormattedFiles: false, changesAreErrors: false, AllFileMatcher, @@ -74,6 +77,7 @@ public void NoFilesFormattedSolution() fixCategory: FixCategory.Whitespace, codeStyleSeverity: DiagnosticSeverity.Error, analyzerSeverity: DiagnosticSeverity.Error, + diagnostics: ImmutableHashSet.Empty, saveFormattedFiles: false, changesAreErrors: false, AllFileMatcher, diff --git a/perf/RealWorldSolution.cs b/perf/RealWorldSolution.cs index 1427082ebf..e778cda2ec 100644 --- a/perf/RealWorldSolution.cs +++ b/perf/RealWorldSolution.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information. using System; +using System.Collections.Immutable; using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Configs; using BenchmarkDotNet.Diagnosers; @@ -38,6 +39,7 @@ public void FilesFormattedSolution() fixCategory: FixCategory.Whitespace, codeStyleSeverity: DiagnosticSeverity.Error, analyzerSeverity: DiagnosticSeverity.Error, + diagnostics: ImmutableHashSet.Empty, saveFormattedFiles: false, changesAreErrors: false, AllFileMatcher, @@ -57,6 +59,7 @@ public void FilesFormattedFolder() fixCategory: FixCategory.Whitespace, codeStyleSeverity: DiagnosticSeverity.Error, analyzerSeverity: DiagnosticSeverity.Error, + diagnostics: ImmutableHashSet.Empty, saveFormattedFiles: false, changesAreErrors: false, AllFileMatcher, diff --git a/src/Analyzers/AnalyzerFormatter.cs b/src/Analyzers/AnalyzerFormatter.cs index 067864326f..8554c76862 100644 --- a/src/Analyzers/AnalyzerFormatter.cs +++ b/src/Analyzers/AnalyzerFormatter.cs @@ -72,6 +72,12 @@ internal class AnalyzerFormatter : ICodeFormatter .SelectMany(codefix => codefix.FixableDiagnosticIds.Where(id => id.StartsWith("CS") || id.StartsWith("BC"))) .ToImmutableHashSet(); + // Filter compiler diagnostics + if (!fixableCompilerDiagnostics.IsEmpty && !formatOptions.Diagnostics.IsEmpty) + { + fixableCompilerDiagnostics.Intersect(formatOptions.Diagnostics); + } + var analysisStopwatch = Stopwatch.StartNew(); logger.LogTrace(Resources.Running_0_analysis, _name); @@ -83,7 +89,7 @@ internal class AnalyzerFormatter : ICodeFormatter var severity = _informationProvider.GetSeverity(formatOptions); // Filter to analyzers that report diagnostics with equal or greater severity. - var projectAnalyzers = await FilterBySeverityAsync(solution, projectAnalyzersAndFixers, formattablePaths, severity, cancellationToken).ConfigureAwait(false); + var projectAnalyzers = await FilterAnalyzersAsync(solution, projectAnalyzersAndFixers, formattablePaths, severity, formatOptions.Diagnostics, cancellationToken).ConfigureAwait(false); // Determine which diagnostics are being reported for each project. var projectDiagnostics = await GetProjectDiagnosticsAsync(solution, projectAnalyzers, formattablePaths, formatOptions, severity, fixableCompilerDiagnostics, logger, formattedFiles, cancellationToken).ConfigureAwait(false); @@ -248,11 +254,12 @@ static void LogDiagnosticLocations(Solution solution, IEnumerable di } } - internal static async Task>> FilterBySeverityAsync( + internal static async Task>> FilterAnalyzersAsync( Solution solution, ImmutableDictionary projectAnalyzersAndFixers, ImmutableHashSet formattablePaths, DiagnosticSeverity minimumSeverity, + ImmutableHashSet diagnostics, CancellationToken cancellationToken) { // We only want to run analyzers for each project that have the potential for reporting a diagnostic with @@ -273,6 +280,13 @@ static void LogDiagnosticLocations(Solution solution, IEnumerable di .Where(analyzer => DoesAnalyzerSupportLanguage(analyzer, project.Language)); foreach (var analyzer in filteredAnalyzer) { + // Filter by diagnostics + if (!diagnostics.IsEmpty && + !analyzer.SupportedDiagnostics.Any(descriptor => diagnostics.Contains(descriptor.Id))) + { + continue; + } + // Always run naming style analyzers because we cannot determine potential severity. // The reported diagnostics will be filtered by severity when they are run. if (analyzer.GetType().FullName?.EndsWith("NamingStyleDiagnosticAnalyzer") == true) diff --git a/src/FormatCommand.cs b/src/FormatCommand.cs index 3c5ea14810..d37173252b 100644 --- a/src/FormatCommand.cs +++ b/src/FormatCommand.cs @@ -18,6 +18,7 @@ internal static class FormatCommand bool fixWhitespace, string? fixStyle, string? fixAnalyzers, + string[] diagnostics, string? verbosity, bool check, string[] include, @@ -49,6 +50,10 @@ internal static RootCommand CreateCommandLineOptions() { Argument = new Argument("severity") { Arity = ArgumentArity.ZeroOrOne }.FromAmong(SeverityLevels) }, + new Option(new[] { "--diagnostics" }, Resources.A_space_separated_list_of_diagnostic_ids_to_use_as_a_filter_when_fixing_code_style_or_3rd_party_issues) + { + Argument = new Argument(() => Array.Empty()) + }, new Option(new[] { "--include" }, Resources.A_list_of_relative_file_or_folder_paths_to_include_in_formatting_All_files_are_formatted_if_empty) { Argument = new Argument(() => Array.Empty()) diff --git a/src/FormatOptions.cs b/src/FormatOptions.cs index 55edf9fa10..20a82c8867 100644 --- a/src/FormatOptions.cs +++ b/src/FormatOptions.cs @@ -1,5 +1,6 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information. +using System.Collections.Immutable; using Microsoft.CodeAnalysis.Tools.Utilities; using Microsoft.Extensions.Logging; @@ -13,6 +14,7 @@ internal class FormatOptions public FixCategory FixCategory { get; } public DiagnosticSeverity CodeStyleSeverity { get; } public DiagnosticSeverity AnalyzerSeverity { get; } + public ImmutableHashSet Diagnostics { get; } public bool SaveFormattedFiles { get; } public bool ChangesAreErrors { get; } public SourceFileMatcher FileMatcher { get; } @@ -26,6 +28,7 @@ internal class FormatOptions FixCategory fixCategory, DiagnosticSeverity codeStyleSeverity, DiagnosticSeverity analyzerSeverity, + ImmutableHashSet diagnostics, bool saveFormattedFiles, bool changesAreErrors, SourceFileMatcher fileMatcher, @@ -38,6 +41,7 @@ internal class FormatOptions FixCategory = fixCategory; CodeStyleSeverity = codeStyleSeverity; AnalyzerSeverity = analyzerSeverity; + Diagnostics = diagnostics; SaveFormattedFiles = saveFormattedFiles; ChangesAreErrors = changesAreErrors; FileMatcher = fileMatcher; @@ -52,6 +56,7 @@ internal class FormatOptions out FixCategory fixCategory, out DiagnosticSeverity codeStyleSeverity, out DiagnosticSeverity analyzerSeverity, + out ImmutableHashSet diagnostics, out bool saveFormattedFiles, out bool changesAreErrors, out SourceFileMatcher fileMatcher, @@ -64,6 +69,7 @@ internal class FormatOptions fixCategory = FixCategory; codeStyleSeverity = CodeStyleSeverity; analyzerSeverity = AnalyzerSeverity; + diagnostics = Diagnostics; saveFormattedFiles = SaveFormattedFiles; changesAreErrors = ChangesAreErrors; fileMatcher = FileMatcher; diff --git a/src/Formatters/UnnecessaryImportsFormatter.cs b/src/Formatters/UnnecessaryImportsFormatter.cs index 533bbcdc8b..d9d895ef6c 100644 --- a/src/Formatters/UnnecessaryImportsFormatter.cs +++ b/src/Formatters/UnnecessaryImportsFormatter.cs @@ -41,6 +41,13 @@ internal sealed class UnnecessaryImportsFormatter : DocumentFormatter return sourceText; } + // If diagnostics are being filtered and IDE0005 isn't specified, then make no changes. + if (!formatOptions.Diagnostics.IsEmpty && + !formatOptions.Diagnostics.Contains(IDE0005)) + { + return sourceText; + } + var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); if (tree is null) { diff --git a/src/Program.cs b/src/Program.cs index 83ca628e2a..c3bc353899 100644 --- a/src/Program.cs +++ b/src/Program.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information. using System; +using System.Collections.Immutable; using System.CommandLine; using System.CommandLine.Invocation; using System.CommandLine.Parsing; @@ -47,6 +48,7 @@ private static async Task Main(string[] args) bool fixWhitespace, string? fixStyle, string? fixAnalyzers, + string[] diagnostics, string? verbosity, bool check, string[] include, @@ -164,6 +166,7 @@ private static async Task Main(string[] args) fixType, codeStyleSeverity: GetSeverity(fixStyle ?? FixSeverity.Error), analyzerSeverity: GetSeverity(fixAnalyzers ?? FixSeverity.Error), + diagnostics: diagnostics.ToImmutableHashSet(), saveFormattedFiles: !check, changesAreErrors: check, fileMatcher, diff --git a/src/Resources.resx b/src/Resources.resx index 7982a8dfc5..13a22a5352 100644 --- a/src/Resources.resx +++ b/src/Resources.resx @@ -297,4 +297,7 @@ The dotnet format version is '{0}'. + + A space separated list of diagnostic ids to use as a filter when fixing code style or 3rd party issues. + \ No newline at end of file diff --git a/src/xlf/Resources.cs.xlf b/src/xlf/Resources.cs.xlf index a558bcbedf..99b221a665 100644 --- a/src/xlf/Resources.cs.xlf +++ b/src/xlf/Resources.cs.xlf @@ -17,6 +17,11 @@ Cesta k souboru řešení, souboru projektu nebo složce obsahující soubor řešení nebo projektu. Pokud cesta není zadaná, použije se aktuální adresář. + + A space separated list of diagnostic ids to use as a filter when fixing code style or 3rd party issues. + A space separated list of diagnostic ids to use as a filter when fixing code style or 3rd party issues. + + Accepts a file path, which if provided, will produce a json report in the given directory. Přijímá cestu k souboru. Pokud se zadá, vytvoří se v daném adresáři sestava JSON. diff --git a/src/xlf/Resources.de.xlf b/src/xlf/Resources.de.xlf index be1f8c18ac..249c273e3c 100644 --- a/src/xlf/Resources.de.xlf +++ b/src/xlf/Resources.de.xlf @@ -17,6 +17,11 @@ Ein Pfad zu einer Projektmappendatei, einer Projektdatei oder einem Ordner, die bzw. der eine Projektmappe oder Projektdatei enthält. Wenn kein Pfad angegeben wird, wird das aktuelle Verzeichnis verwendet. + + A space separated list of diagnostic ids to use as a filter when fixing code style or 3rd party issues. + A space separated list of diagnostic ids to use as a filter when fixing code style or 3rd party issues. + + Accepts a file path, which if provided, will produce a json report in the given directory. Akzeptiert einen Dateipfad, der bei Bereitstellung einen JSON-Bericht im angegebenen Verzeichnis erstellt. diff --git a/src/xlf/Resources.es.xlf b/src/xlf/Resources.es.xlf index 24738b5336..8c347e62b3 100644 --- a/src/xlf/Resources.es.xlf +++ b/src/xlf/Resources.es.xlf @@ -17,6 +17,11 @@ Ruta de acceso a un archivo de solución, a un archivo del proyecto o a una carpeta que contiene archivo de proyecto o solución. Si no se especifica ninguna ruta de acceso, se usa el directorio actual. + + A space separated list of diagnostic ids to use as a filter when fixing code style or 3rd party issues. + A space separated list of diagnostic ids to use as a filter when fixing code style or 3rd party issues. + + Accepts a file path, which if provided, will produce a json report in the given directory. Acepta una ruta de acceso de archivo que, si se proporciona, generará un informe JSON en el directorio dado. diff --git a/src/xlf/Resources.fr.xlf b/src/xlf/Resources.fr.xlf index 9c41a66598..a82888360f 100644 --- a/src/xlf/Resources.fr.xlf +++ b/src/xlf/Resources.fr.xlf @@ -17,6 +17,11 @@ Chemin d'un fichier solution, d'un fichier projet ou d'un dossier contenant un fichier solution ou un fichier projet. Si aucun chemin n'est spécifié, le répertoire actif est utilisé. + + A space separated list of diagnostic ids to use as a filter when fixing code style or 3rd party issues. + A space separated list of diagnostic ids to use as a filter when fixing code style or 3rd party issues. + + Accepts a file path, which if provided, will produce a json report in the given directory. Accepte un chemin de fichier, qui, s'il est fourni, produit un rapport JSON dans le répertoire donné. diff --git a/src/xlf/Resources.it.xlf b/src/xlf/Resources.it.xlf index 4f8e29bcc2..e42bb11d58 100644 --- a/src/xlf/Resources.it.xlf +++ b/src/xlf/Resources.it.xlf @@ -17,6 +17,11 @@ Percorso di un file di soluzione, un file di progetto o una cartella contenente una soluzione o un file di progetto. Se non si specifica alcun percorso, viene usata la directory corrente. + + A space separated list of diagnostic ids to use as a filter when fixing code style or 3rd party issues. + A space separated list of diagnostic ids to use as a filter when fixing code style or 3rd party issues. + + Accepts a file path, which if provided, will produce a json report in the given directory. Accetta un percorso file che, se specificato, produrrà un report JSON nella directory specificata. diff --git a/src/xlf/Resources.ja.xlf b/src/xlf/Resources.ja.xlf index 515540a891..fbc29791b3 100644 --- a/src/xlf/Resources.ja.xlf +++ b/src/xlf/Resources.ja.xlf @@ -17,6 +17,11 @@ ソリューション ファイル、プロジェクト ファイル、またはソリューション ファイルかプロジェクト ファイルを含むフォルダーへのパス。パスが指定されていない場合は、現在のディレクトリが使用されます。 + + A space separated list of diagnostic ids to use as a filter when fixing code style or 3rd party issues. + A space separated list of diagnostic ids to use as a filter when fixing code style or 3rd party issues. + + Accepts a file path, which if provided, will produce a json report in the given directory. ファイル パスを受け入れると (指定されている場合)、指定されたディレクトリに JSON レポートが生成されます。 diff --git a/src/xlf/Resources.ko.xlf b/src/xlf/Resources.ko.xlf index 6e6e344fbd..ed61b7cc3f 100644 --- a/src/xlf/Resources.ko.xlf +++ b/src/xlf/Resources.ko.xlf @@ -17,6 +17,11 @@ 솔루션 파일, 프로젝트 파일이나 솔루션 또는 프로젝트 파일이 포함된 폴더의 경로입니다. 경로를 지정하지 않으면 현재 디렉터리가 사용됩니다. + + A space separated list of diagnostic ids to use as a filter when fixing code style or 3rd party issues. + A space separated list of diagnostic ids to use as a filter when fixing code style or 3rd party issues. + + Accepts a file path, which if provided, will produce a json report in the given directory. 제공된 경우 지정된 디렉터리에 json 보고서를 생성할 파일 경로를 허용합니다. diff --git a/src/xlf/Resources.pl.xlf b/src/xlf/Resources.pl.xlf index 9be4b307d0..e075eca397 100644 --- a/src/xlf/Resources.pl.xlf +++ b/src/xlf/Resources.pl.xlf @@ -17,6 +17,11 @@ Ścieżka do pliku rozwiązania, pliku projektu albo folderu zawierającego plik rozwiązania lub plik projektu. Jeśli ścieżka nie zostanie określona, zostanie użyty bieżący katalog. + + A space separated list of diagnostic ids to use as a filter when fixing code style or 3rd party issues. + A space separated list of diagnostic ids to use as a filter when fixing code style or 3rd party issues. + + Accepts a file path, which if provided, will produce a json report in the given directory. Akceptuje ścieżkę pliku, która, jeśli zostanie podana, wygeneruje raport JSON w danym katalogu. diff --git a/src/xlf/Resources.pt-BR.xlf b/src/xlf/Resources.pt-BR.xlf index c44fb3ec4f..fceabd1938 100644 --- a/src/xlf/Resources.pt-BR.xlf +++ b/src/xlf/Resources.pt-BR.xlf @@ -17,6 +17,11 @@ Um caminho para um arquivo de solução, um arquivo de projeto ou uma pasta contendo um arquivo de solução ou de projeto. Se não for especificado um caminho, o diretório atual será usado. + + A space separated list of diagnostic ids to use as a filter when fixing code style or 3rd party issues. + A space separated list of diagnostic ids to use as a filter when fixing code style or 3rd party issues. + + Accepts a file path, which if provided, will produce a json report in the given directory. Aceita um caminho de arquivo, que, se fornecido, produzirá um relatório JSON no diretório especificado. diff --git a/src/xlf/Resources.ru.xlf b/src/xlf/Resources.ru.xlf index b783798e70..6ef10772c4 100644 --- a/src/xlf/Resources.ru.xlf +++ b/src/xlf/Resources.ru.xlf @@ -17,6 +17,11 @@ Путь к файлу решения, файлу проекта или папке, содержащей файл решения или проекта. Если путь не указан, используется текущий каталог. + + A space separated list of diagnostic ids to use as a filter when fixing code style or 3rd party issues. + A space separated list of diagnostic ids to use as a filter when fixing code style or 3rd party issues. + + Accepts a file path, which if provided, will produce a json report in the given directory. Принимает путь к файлу. Если путь к файлу указан, создает отчет JSON в указанном каталоге. diff --git a/src/xlf/Resources.tr.xlf b/src/xlf/Resources.tr.xlf index c7d3d5dcdf..80eab93590 100644 --- a/src/xlf/Resources.tr.xlf +++ b/src/xlf/Resources.tr.xlf @@ -17,6 +17,11 @@ Çözüm dosyasının, proje dosyasının veya çözüm ya da proje dosyasını içeren klasörün yolu. Yol belirtilmezse geçerli dizin kullanılır. + + A space separated list of diagnostic ids to use as a filter when fixing code style or 3rd party issues. + A space separated list of diagnostic ids to use as a filter when fixing code style or 3rd party issues. + + Accepts a file path, which if provided, will produce a json report in the given directory. Sağlanırsa, verilen dizinde json raporu oluşturacak bir dosya yolunu kabul eder. diff --git a/src/xlf/Resources.zh-Hans.xlf b/src/xlf/Resources.zh-Hans.xlf index edb5ec33b4..a1ca40ca9d 100644 --- a/src/xlf/Resources.zh-Hans.xlf +++ b/src/xlf/Resources.zh-Hans.xlf @@ -17,6 +17,11 @@ 指向解决方案文件、项目文件或包含解决方案或项目文件的文件夹的路径。如果未指定路径,则使用当前目录。 + + A space separated list of diagnostic ids to use as a filter when fixing code style or 3rd party issues. + A space separated list of diagnostic ids to use as a filter when fixing code style or 3rd party issues. + + Accepts a file path, which if provided, will produce a json report in the given directory. 接受文件路径(若提供)将在给定目录中生成 json 报表。 diff --git a/src/xlf/Resources.zh-Hant.xlf b/src/xlf/Resources.zh-Hant.xlf index fae3baef68..55504ed495 100644 --- a/src/xlf/Resources.zh-Hant.xlf +++ b/src/xlf/Resources.zh-Hant.xlf @@ -17,6 +17,11 @@ 解決方案檔、專案檔,或包含解決方案或專案檔之資料夾的路徑。若未指定路徑,就會使用目前的目錄。 + + A space separated list of diagnostic ids to use as a filter when fixing code style or 3rd party issues. + A space separated list of diagnostic ids to use as a filter when fixing code style or 3rd party issues. + + Accepts a file path, which if provided, will produce a json report in the given directory. 接受檔案路徑 (如果有提供) 將在指定的目錄中產生 json 報告。 diff --git a/tests/Analyzers/CodeStyleAnalyzerFormatterTests.cs b/tests/Analyzers/CodeStyleAnalyzerFormatterTests.cs index 01dd7b51f5..08ee41c7df 100644 --- a/tests/Analyzers/CodeStyleAnalyzerFormatterTests.cs +++ b/tests/Analyzers/CodeStyleAnalyzerFormatterTests.cs @@ -74,5 +74,49 @@ public int M() await AssertNoReportedFileChangesAsync(testCode, "root = true", fixCategory: FixCategory.CodeStyle, codeStyleSeverity: DiagnosticSeverity.Warning); } + + [Fact] + public async Task TestUnusedImport_AppliesWhenIDE0005InDiagnosticsList() + { + var testCode = @" +using System.Buffers; +using System.Collections.Generic; + +class C +{ + void M() + { + object obj = new object(); + List list = new List(); + int count = 5; + } +}"; + + var expectedCode = @" +using System.Collections.Generic; + +class C +{ + void M() + { + object obj = new object(); + List list = new List(); + int count = 5; + } +}"; + + var editorConfig = new Dictionary() + { + /// IDE0005: Using directive is unnecessary + ["dotnet_diagnostic.IDE0005.severity"] = "error", + /// Prefer "var" everywhere + ["dotnet_diagnostic.IDE0007.severity"] = "error", + ["csharp_style_var_for_built_in_types"] = "true:error", + ["csharp_style_var_when_type_is_apparent"] = "true:error", + ["csharp_style_var_elsewhere"] = "true:error", + }; + + await AssertCodeChangedAsync(testCode, expectedCode, editorConfig, fixCategory: FixCategory.CodeStyle, diagnostics: new[] { "IDE0005" }); + } } } diff --git a/tests/Analyzers/FilterDiagnosticsTests.cs b/tests/Analyzers/FilterDiagnosticsTests.cs index 00c5c88524..02f1c7d5cd 100644 --- a/tests/Analyzers/FilterDiagnosticsTests.cs +++ b/tests/Analyzers/FilterDiagnosticsTests.cs @@ -24,11 +24,13 @@ public async Task TestFilterWarning() var project = solution.Projects.First(); var formattablePaths = ImmutableHashSet.Create(project.Documents.First().FilePath); var minimumSeverity = DiagnosticSeverity.Warning; - var result = await AnalyzerFormatter.FilterBySeverityAsync( + var diagnostics = ImmutableHashSet.Empty; + var result = await AnalyzerFormatter.FilterAnalyzersAsync( solution, projectAnalyzersAndFixers, formattablePaths, minimumSeverity, + diagnostics, CancellationToken.None); var (_, analyzers) = Assert.Single(result); Assert.Single(analyzers); @@ -42,16 +44,59 @@ public async Task TestFilterError() var project = solution.Projects.First(); var formattablePaths = ImmutableHashSet.Create(project.Documents.First().FilePath); var minimumSeverity = DiagnosticSeverity.Error; - var result = await AnalyzerFormatter.FilterBySeverityAsync( + var diagnostics = ImmutableHashSet.Empty; + var result = await AnalyzerFormatter.FilterAnalyzersAsync( solution, projectAnalyzersAndFixers, formattablePaths, minimumSeverity, + diagnostics, CancellationToken.None); var (_, analyzers) = Assert.Single(result); Assert.Empty(analyzers); } + [Fact] + public async Task TestFilterDiagnostics_NotInDiagnosticsList() + { + var solution = await GetSolutionAsync(); + var projectAnalyzersAndFixers = await GetProjectAnalyzersAndFixersAsync(solution); + var project = solution.Projects.First(); + var formattablePaths = ImmutableHashSet.Create(project.Documents.First().FilePath); + var minimumSeverity = DiagnosticSeverity.Warning; + var diagnostics = ImmutableHashSet.Create("IDE0005"); + var result = await AnalyzerFormatter.FilterAnalyzersAsync( + solution, + projectAnalyzersAndFixers, + formattablePaths, + minimumSeverity, + diagnostics, + CancellationToken.None); + var (_, analyzers) = Assert.Single(result); + Assert.Empty(analyzers); + } + + [Fact] + public async Task TestFilterDiagnostics_InDiagnosticsList() + { + var solution = await GetSolutionAsync(); + var projectAnalyzersAndFixers = await GetProjectAnalyzersAndFixersAsync(solution); + var project = solution.Projects.First(); + var formattablePaths = ImmutableHashSet.Create(project.Documents.First().FilePath); + var minimumSeverity = DiagnosticSeverity.Warning; + var diagnostics = ImmutableHashSet.Create("DiagnosticAnalyzerId"); + var result = await AnalyzerFormatter.FilterAnalyzersAsync( + solution, + projectAnalyzersAndFixers, + formattablePaths, + minimumSeverity, + diagnostics, + CancellationToken.None); + var (_, analyzers) = Assert.Single(result); + Assert.Single(analyzers); + } + + private static async Task GetAnalyzersAndFixersAsync() { var assemblies = new[] diff --git a/tests/CodeFormatterTests.cs b/tests/CodeFormatterTests.cs index 814f6cb274..3f627ed5ad 100644 --- a/tests/CodeFormatterTests.cs +++ b/tests/CodeFormatterTests.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information. using System; +using System.Collections.Immutable; using System.IO; using System.Linq; using System.Text.RegularExpressions; @@ -508,7 +509,8 @@ public async Task FilesFormattedInAnalyzersSolution_WhenFixingAnalyzerErrors() int expectedFileCount, FixCategory fixCategory = FixCategory.Whitespace, DiagnosticSeverity codeStyleSeverity = DiagnosticSeverity.Error, - DiagnosticSeverity analyzerSeverity = DiagnosticSeverity.Error) + DiagnosticSeverity analyzerSeverity = DiagnosticSeverity.Error, + string[] diagnostics = null) { var currentDirectory = Environment.CurrentDirectory; Environment.CurrentDirectory = TestProjectsPathHelper.GetProjectsDirectory(); @@ -541,6 +543,7 @@ public async Task FilesFormattedInAnalyzersSolution_WhenFixingAnalyzerErrors() fixCategory, codeStyleSeverity, analyzerSeverity, + diagnostics?.ToImmutableHashSet() ?? default, saveFormattedFiles: false, changesAreErrors: false, fileMatcher, diff --git a/tests/Formatters/AbstractFormatterTests.cs b/tests/Formatters/AbstractFormatterTests.cs index d744749348..86ac28f2e9 100644 --- a/tests/Formatters/AbstractFormatterTests.cs +++ b/tests/Formatters/AbstractFormatterTests.cs @@ -93,9 +93,10 @@ protected AbstractFormatterTest() FixCategory fixCategory = FixCategory.Whitespace, IEnumerable? analyzerReferences = null, DiagnosticSeverity codeStyleSeverity = DiagnosticSeverity.Error, - DiagnosticSeverity analyzerSeverity = DiagnosticSeverity.Error) + DiagnosticSeverity analyzerSeverity = DiagnosticSeverity.Error, + string[]? diagnostics = null) { - return AssertNoReportedFileChangesAsync(code, ToEditorConfig(editorConfig), encoding, fixCategory, analyzerReferences, codeStyleSeverity, analyzerSeverity); + return AssertNoReportedFileChangesAsync(code, ToEditorConfig(editorConfig), encoding, fixCategory, analyzerReferences, codeStyleSeverity, analyzerSeverity, diagnostics); } private protected async Task AssertNoReportedFileChangesAsync( @@ -105,9 +106,10 @@ protected AbstractFormatterTest() FixCategory fixCategory = FixCategory.Whitespace, IEnumerable? analyzerReferences = null, DiagnosticSeverity codeStyleSeverity = DiagnosticSeverity.Error, - DiagnosticSeverity analyzerSeverity = DiagnosticSeverity.Error) + DiagnosticSeverity analyzerSeverity = DiagnosticSeverity.Error, + string[]? diagnostics = null) { - var (formattedText, formattedFiles, logger) = await ApplyFormatterAsync(code, editorConfig, encoding, fixCategory, analyzerReferences, codeStyleSeverity, analyzerSeverity); + var (formattedText, formattedFiles, logger) = await ApplyFormatterAsync(code, editorConfig, encoding, fixCategory, analyzerReferences, codeStyleSeverity, analyzerSeverity, diagnostics); try { @@ -133,9 +135,10 @@ protected AbstractFormatterTest() FixCategory fixCategory = FixCategory.Whitespace, IEnumerable? analyzerReferences = null, DiagnosticSeverity codeStyleSeverity = DiagnosticSeverity.Error, - DiagnosticSeverity analyzerSeverity = DiagnosticSeverity.Error) + DiagnosticSeverity analyzerSeverity = DiagnosticSeverity.Error, + string[]? diagnostics = null) { - return AssertCodeUnchangedAsync(code, ToEditorConfig(editorConfig), encoding, fixCategory, analyzerReferences, codeStyleSeverity, analyzerSeverity); + return AssertCodeUnchangedAsync(code, ToEditorConfig(editorConfig), encoding, fixCategory, analyzerReferences, codeStyleSeverity, analyzerSeverity, diagnostics); } private protected async Task AssertCodeUnchangedAsync( @@ -145,9 +148,10 @@ protected AbstractFormatterTest() FixCategory fixCategory = FixCategory.Whitespace, IEnumerable? analyzerReferences = null, DiagnosticSeverity codeStyleSeverity = DiagnosticSeverity.Error, - DiagnosticSeverity analyzerSeverity = DiagnosticSeverity.Error) + DiagnosticSeverity analyzerSeverity = DiagnosticSeverity.Error, + string[]? diagnostics = null) { - var (formattedText, _, logger) = await ApplyFormatterAsync(code, editorConfig, encoding, fixCategory, analyzerReferences, codeStyleSeverity, analyzerSeverity); + var (formattedText, _, logger) = await ApplyFormatterAsync(code, editorConfig, encoding, fixCategory, analyzerReferences, codeStyleSeverity, analyzerSeverity, diagnostics); try { @@ -171,9 +175,10 @@ protected AbstractFormatterTest() FixCategory fixCategory = FixCategory.Whitespace, IEnumerable? analyzerReferences = null, DiagnosticSeverity codeStyleSeverity = DiagnosticSeverity.Error, - DiagnosticSeverity analyzerSeverity = DiagnosticSeverity.Error) + DiagnosticSeverity analyzerSeverity = DiagnosticSeverity.Error, + string[]? diagnostics = null) { - return AssertCodeChangedAsync(testCode, expectedCode, ToEditorConfig(editorConfig), encoding, fixCategory, analyzerReferences, codeStyleSeverity, analyzerSeverity); + return AssertCodeChangedAsync(testCode, expectedCode, ToEditorConfig(editorConfig), encoding, fixCategory, analyzerReferences, codeStyleSeverity, analyzerSeverity, diagnostics); } private protected async Task AssertCodeChangedAsync( @@ -184,9 +189,10 @@ protected AbstractFormatterTest() FixCategory fixCategory = FixCategory.Whitespace, IEnumerable? analyzerReferences = null, DiagnosticSeverity codeStyleSeverity = DiagnosticSeverity.Error, - DiagnosticSeverity analyzerSeverity = DiagnosticSeverity.Error) + DiagnosticSeverity analyzerSeverity = DiagnosticSeverity.Error, + string[]? diagnostics = null) { - var (formattedText, _, logger) = await ApplyFormatterAsync(testCode, editorConfig, encoding, fixCategory, analyzerReferences, codeStyleSeverity, analyzerSeverity); + var (formattedText, _, logger) = await ApplyFormatterAsync(testCode, editorConfig, encoding, fixCategory, analyzerReferences, codeStyleSeverity, analyzerSeverity, diagnostics); try { @@ -208,7 +214,8 @@ protected AbstractFormatterTest() FixCategory fixCategory = FixCategory.Whitespace, IEnumerable? analyzerReferences = null, DiagnosticSeverity codeStyleSeverity = DiagnosticSeverity.Error, - DiagnosticSeverity analyzerSeverity = DiagnosticSeverity.Error) + DiagnosticSeverity analyzerSeverity = DiagnosticSeverity.Error, + string[]? diagnostics = null) { var text = SourceText.From(code, encoding ?? Encoding.UTF8); TestState.Sources.Add(text); @@ -225,6 +232,7 @@ protected AbstractFormatterTest() fixCategory, codeStyleSeverity, analyzerSeverity, + (diagnostics ?? Array.Empty()).ToImmutableHashSet(), saveFormattedFiles: true, changesAreErrors: false, fileMatcher, diff --git a/tests/Formatters/FormattedFilesTests.cs b/tests/Formatters/FormattedFilesTests.cs index ddf267a836..145a073597 100644 --- a/tests/Formatters/FormattedFilesTests.cs +++ b/tests/Formatters/FormattedFilesTests.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -67,6 +68,7 @@ private async Task> TestFormattedFiles(string testCode) fixCategory: FixCategory.Whitespace, codeStyleSeverity: DiagnosticSeverity.Error, analyzerSeverity: DiagnosticSeverity.Error, + diagnostics: ImmutableHashSet.Empty, saveFormattedFiles: false, changesAreErrors: false, fileMatcher, diff --git a/tests/Formatters/UnnecessaryImportsFormatterTests.cs b/tests/Formatters/UnnecessaryImportsFormatterTests.cs index 66b33e088c..39692c0fc9 100644 --- a/tests/Formatters/UnnecessaryImportsFormatterTests.cs +++ b/tests/Formatters/UnnecessaryImportsFormatterTests.cs @@ -105,5 +105,58 @@ class C await AssertCodeChangedAsync(testCode, expectedCode, editorConfig, fixCategory: FixCategory.Whitespace | FixCategory.CodeStyle, codeStyleSeverity: DiagnosticSeverity.Warning); } + + [Theory] + [InlineData(RemoveUnnecessaryImportDiagnosticKey, Severity.Warning)] + [InlineData(RemoveUnnecessaryImportDiagnosticKey, Severity.Error)] + [InlineData(RemoveUnnecessaryImportCategoryKey, Severity.Warning)] + [InlineData(RemoveUnnecessaryImportCategoryKey, Severity.Error)] + [InlineData(AnalyzerOptionsExtensions.DotnetAnalyzerDiagnosticSeverityKey, Severity.Warning)] + [InlineData(AnalyzerOptionsExtensions.DotnetAnalyzerDiagnosticSeverityKey, Severity.Error)] + public async Task WhenIDE0005SeverityEqualOrGreaterThanFixSeverity_AndHasUnusedImports_AndIncludedInDiagnosticsList_ImportRemoved(string key, string severity) + { + var testCode = +@"using System; + +class C +{ +}"; + + var expectedCode = +@"class C +{ +}"; + + var editorConfig = new Dictionary() + { + [key] = severity + }; + + await AssertCodeChangedAsync(testCode, expectedCode, editorConfig, fixCategory: FixCategory.Whitespace | FixCategory.CodeStyle, codeStyleSeverity: DiagnosticSeverity.Warning, diagnostics: new[] { UnnecessaryImportsFormatter.IDE0005 }); + } + + [Theory] + [InlineData(RemoveUnnecessaryImportDiagnosticKey, Severity.Warning)] + [InlineData(RemoveUnnecessaryImportDiagnosticKey, Severity.Error)] + [InlineData(RemoveUnnecessaryImportCategoryKey, Severity.Warning)] + [InlineData(RemoveUnnecessaryImportCategoryKey, Severity.Error)] + [InlineData(AnalyzerOptionsExtensions.DotnetAnalyzerDiagnosticSeverityKey, Severity.Warning)] + [InlineData(AnalyzerOptionsExtensions.DotnetAnalyzerDiagnosticSeverityKey, Severity.Error)] + public async Task WhenIDE0005SeverityEqualOrGreaterThanFixSeverity_AndHasUnusedImports_AndNotIncludedInDiagnosticsList_ImportNotRemoved(string key, string severity) + { + var testCode = +@"using System; + +class C +{ +}"; + + var editorConfig = new Dictionary() + { + [key] = severity + }; + + await AssertCodeUnchangedAsync(testCode, editorConfig, fixCategory: FixCategory.Whitespace | FixCategory.CodeStyle, codeStyleSeverity: DiagnosticSeverity.Warning, diagnostics: new[] { "IDE0073" }); + } } } diff --git a/tests/ProgramTests.cs b/tests/ProgramTests.cs index 4e2b00b963..cdd40cb2bf 100644 --- a/tests/ProgramTests.cs +++ b/tests/ProgramTests.cs @@ -184,6 +184,7 @@ public async Task CommandLine_AllArguments_Bind() bool fixWhitespace, string fixStyle, string fixAnalyzers, + string[] diagnostics, string verbosity, bool check, string[] include, @@ -197,6 +198,7 @@ public async Task CommandLine_AllArguments_Bind() Assert.True(fixWhitespace); Assert.Equal("warn", fixStyle); Assert.Equal("info", fixAnalyzers); + Assert.Equal(new[] { "IDE0005", "IDE0073" }, diagnostics); Assert.Equal("diag", verbosity); Assert.True(check); Assert.Equal(new[] { "*.cs" }, include); @@ -214,6 +216,9 @@ public async Task CommandLine_AllArguments_Bind() warn --fix-analyzers info +--diagnostics +IDE0005 +IDE0073 --verbosity diag --check