Skip to content

Commit

Permalink
Add option to filter diagnostics by id
Browse files Browse the repository at this point in the history
  • Loading branch information
JoeRobich committed Feb 26, 2021
1 parent 366fd67 commit 15305cc
Show file tree
Hide file tree
Showing 31 changed files with 310 additions and 20 deletions.
6 changes: 4 additions & 2 deletions README.md
Expand Up @@ -101,6 +101,7 @@ Options:
--fix-whitespace, -w Run whitespace formatting. Run by default when not applying fixes.
--fix-style, -s <severity> Run code style analyzers and apply fixes.
--fix-analyzers, -a <severity> Run 3rd party analyzers and apply fixes.
--diagnostics <diagnostic ids> A space separated list of diagnostic ids to use as a filter when fixing code style or 3rd party analyzers.
--include <include> A list of relative file or folder paths to include in formatting. All files are formatted if empty.
--exclude <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.
Expand All @@ -117,6 +118,7 @@ Add `format` after `dotnet` and before the command arguments that you want to ru
| `dotnet format <workspace>` | Formats a specific project or solution. |
| `dotnet format <workspace> -f` | Formats a particular folder and subfolders. |
| `dotnet format <workspace> --fix-style warn` | Fixes only codestyle analyzer warnings. |
| `dotnet format <workspace> --fix-style --diagnostics IDE0005` | Fixes only codestyle analyzer errors for the IDE0005 diagnostic. |
| `dotnet format <workspace> --fix-whitespace --fix-style` | Formats and fixes codestyle analyzer errors. |
| `dotnet format <workspace> --fix-analyzers` | Fixes only 3rd party analyzer errors. |
| `dotnet format <workspace> -wsa` | Formats, fixes codestyle errors, and fixes 3rd party analyzer errors. |
Expand All @@ -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 <version>
dotnet format
```
Expand Down
14 changes: 14 additions & 0 deletions docs/README.md
Expand Up @@ -82,6 +82,20 @@ Running 3rd party analysis requires the use of a MSBuild solution or project fil

- `--fix-analyzers <severity>` - 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 <diagnostic ids>` - 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.
Expand Down
4 changes: 4 additions & 0 deletions 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;
Expand Down Expand Up @@ -36,6 +37,7 @@ public void FilesFormattedFolder()
fixCategory: FixCategory.Whitespace,
codeStyleSeverity: DiagnosticSeverity.Error,
analyzerSeverity: DiagnosticSeverity.Error,
diagnostics: ImmutableHashSet<string>.Empty,
saveFormattedFiles: false,
changesAreErrors: false,
AllFileMatcher,
Expand All @@ -55,6 +57,7 @@ public void FilesFormattedProject()
fixCategory: FixCategory.Whitespace,
codeStyleSeverity: DiagnosticSeverity.Error,
analyzerSeverity: DiagnosticSeverity.Error,
diagnostics: ImmutableHashSet<string>.Empty,
saveFormattedFiles: false,
changesAreErrors: false,
AllFileMatcher,
Expand All @@ -74,6 +77,7 @@ public void FilesFormattedSolution()
fixCategory: FixCategory.Whitespace,
codeStyleSeverity: DiagnosticSeverity.Error,
analyzerSeverity: DiagnosticSeverity.Error,
diagnostics: ImmutableHashSet<string>.Empty,
saveFormattedFiles: false,
changesAreErrors: false,
AllFileMatcher,
Expand Down
4 changes: 4 additions & 0 deletions 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;
Expand Down Expand Up @@ -36,6 +37,7 @@ public void NoFilesFormattedFolder()
fixCategory: FixCategory.Whitespace,
codeStyleSeverity: DiagnosticSeverity.Error,
analyzerSeverity: DiagnosticSeverity.Error,
diagnostics: ImmutableHashSet<string>.Empty,
saveFormattedFiles: false,
changesAreErrors: false,
AllFileMatcher,
Expand All @@ -55,6 +57,7 @@ public void NoFilesFormattedProject()
fixCategory: FixCategory.Whitespace,
codeStyleSeverity: DiagnosticSeverity.Error,
analyzerSeverity: DiagnosticSeverity.Error,
diagnostics: ImmutableHashSet<string>.Empty,
saveFormattedFiles: false,
changesAreErrors: false,
AllFileMatcher,
Expand All @@ -74,6 +77,7 @@ public void NoFilesFormattedSolution()
fixCategory: FixCategory.Whitespace,
codeStyleSeverity: DiagnosticSeverity.Error,
analyzerSeverity: DiagnosticSeverity.Error,
diagnostics: ImmutableHashSet<string>.Empty,
saveFormattedFiles: false,
changesAreErrors: false,
AllFileMatcher,
Expand Down
3 changes: 3 additions & 0 deletions 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;
Expand Down Expand Up @@ -38,6 +39,7 @@ public void FilesFormattedSolution()
fixCategory: FixCategory.Whitespace,
codeStyleSeverity: DiagnosticSeverity.Error,
analyzerSeverity: DiagnosticSeverity.Error,
diagnostics: ImmutableHashSet<string>.Empty,
saveFormattedFiles: false,
changesAreErrors: false,
AllFileMatcher,
Expand All @@ -57,6 +59,7 @@ public void FilesFormattedFolder()
fixCategory: FixCategory.Whitespace,
codeStyleSeverity: DiagnosticSeverity.Error,
analyzerSeverity: DiagnosticSeverity.Error,
diagnostics: ImmutableHashSet<string>.Empty,
saveFormattedFiles: false,
changesAreErrors: false,
AllFileMatcher,
Expand Down
18 changes: 16 additions & 2 deletions src/Analyzers/AnalyzerFormatter.cs
Expand Up @@ -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);

Expand All @@ -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);
Expand Down Expand Up @@ -248,11 +254,12 @@ static void LogDiagnosticLocations(Solution solution, IEnumerable<Diagnostic> di
}
}

internal static async Task<ImmutableDictionary<ProjectId, ImmutableArray<DiagnosticAnalyzer>>> FilterBySeverityAsync(
internal static async Task<ImmutableDictionary<ProjectId, ImmutableArray<DiagnosticAnalyzer>>> FilterAnalyzersAsync(
Solution solution,
ImmutableDictionary<ProjectId, AnalyzersAndFixers> projectAnalyzersAndFixers,
ImmutableHashSet<string> formattablePaths,
DiagnosticSeverity minimumSeverity,
ImmutableHashSet<string> diagnostics,
CancellationToken cancellationToken)
{
// We only want to run analyzers for each project that have the potential for reporting a diagnostic with
Expand All @@ -273,6 +280,13 @@ static void LogDiagnosticLocations(Solution solution, IEnumerable<Diagnostic> 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)
Expand Down
5 changes: 5 additions & 0 deletions src/FormatCommand.cs
Expand Up @@ -18,6 +18,7 @@ internal static class FormatCommand
bool fixWhitespace,
string? fixStyle,
string? fixAnalyzers,
string[] diagnostics,
string? verbosity,
bool check,
string[] include,
Expand Down Expand Up @@ -49,6 +50,10 @@ internal static RootCommand CreateCommandLineOptions()
{
Argument = new Argument<string?>("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<string[]>(() => Array.Empty<string>())
},
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<string[]>(() => Array.Empty<string>())
Expand Down
6 changes: 6 additions & 0 deletions 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;

Expand All @@ -13,6 +14,7 @@ internal class FormatOptions
public FixCategory FixCategory { get; }
public DiagnosticSeverity CodeStyleSeverity { get; }
public DiagnosticSeverity AnalyzerSeverity { get; }
public ImmutableHashSet<string> Diagnostics { get; }
public bool SaveFormattedFiles { get; }
public bool ChangesAreErrors { get; }
public SourceFileMatcher FileMatcher { get; }
Expand All @@ -26,6 +28,7 @@ internal class FormatOptions
FixCategory fixCategory,
DiagnosticSeverity codeStyleSeverity,
DiagnosticSeverity analyzerSeverity,
ImmutableHashSet<string> diagnostics,
bool saveFormattedFiles,
bool changesAreErrors,
SourceFileMatcher fileMatcher,
Expand All @@ -38,6 +41,7 @@ internal class FormatOptions
FixCategory = fixCategory;
CodeStyleSeverity = codeStyleSeverity;
AnalyzerSeverity = analyzerSeverity;
Diagnostics = diagnostics;
SaveFormattedFiles = saveFormattedFiles;
ChangesAreErrors = changesAreErrors;
FileMatcher = fileMatcher;
Expand All @@ -52,6 +56,7 @@ internal class FormatOptions
out FixCategory fixCategory,
out DiagnosticSeverity codeStyleSeverity,
out DiagnosticSeverity analyzerSeverity,
out ImmutableHashSet<string> diagnostics,
out bool saveFormattedFiles,
out bool changesAreErrors,
out SourceFileMatcher fileMatcher,
Expand All @@ -64,6 +69,7 @@ internal class FormatOptions
fixCategory = FixCategory;
codeStyleSeverity = CodeStyleSeverity;
analyzerSeverity = AnalyzerSeverity;
diagnostics = Diagnostics;
saveFormattedFiles = SaveFormattedFiles;
changesAreErrors = ChangesAreErrors;
fileMatcher = FileMatcher;
Expand Down
7 changes: 7 additions & 0 deletions src/Formatters/UnnecessaryImportsFormatter.cs
Expand Up @@ -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)
{
Expand Down
3 changes: 3 additions & 0 deletions 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;
Expand Down Expand Up @@ -47,6 +48,7 @@ private static async Task<int> Main(string[] args)
bool fixWhitespace,
string? fixStyle,
string? fixAnalyzers,
string[] diagnostics,
string? verbosity,
bool check,
string[] include,
Expand Down Expand Up @@ -164,6 +166,7 @@ private static async Task<int> Main(string[] args)
fixType,
codeStyleSeverity: GetSeverity(fixStyle ?? FixSeverity.Error),
analyzerSeverity: GetSeverity(fixAnalyzers ?? FixSeverity.Error),
diagnostics: diagnostics.ToImmutableHashSet(),
saveFormattedFiles: !check,
changesAreErrors: check,
fileMatcher,
Expand Down
3 changes: 3 additions & 0 deletions src/Resources.resx
Expand Up @@ -297,4 +297,7 @@
<data name="The_dotnet_format_version_is_0" xml:space="preserve">
<value>The dotnet format version is '{0}'.</value>
</data>
<data name="A_space_separated_list_of_diagnostic_ids_to_use_as_a_filter_when_fixing_code_style_or_3rd_party_issues" xml:space="preserve">
<value>A space separated list of diagnostic ids to use as a filter when fixing code style or 3rd party issues.</value>
</data>
</root>
5 changes: 5 additions & 0 deletions src/xlf/Resources.cs.xlf
Expand Up @@ -17,6 +17,11 @@
<target state="translated">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ář.</target>
<note />
</trans-unit>
<trans-unit id="A_space_separated_list_of_diagnostic_ids_to_use_as_a_filter_when_fixing_code_style_or_3rd_party_issues">
<source>A space separated list of diagnostic ids to use as a filter when fixing code style or 3rd party issues.</source>
<target state="new">A space separated list of diagnostic ids to use as a filter when fixing code style or 3rd party issues.</target>
<note />
</trans-unit>
<trans-unit id="Accepts_a_file_path_which_if_provided_will_produce_a_format_report_json_file_in_the_given_directory">
<source>Accepts a file path, which if provided, will produce a json report in the given directory.</source>
<target state="translated">Přijímá cestu k souboru. Pokud se zadá, vytvoří se v daném adresáři sestava JSON.</target>
Expand Down
5 changes: 5 additions & 0 deletions src/xlf/Resources.de.xlf
Expand Up @@ -17,6 +17,11 @@
<target state="translated">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.</target>
<note />
</trans-unit>
<trans-unit id="A_space_separated_list_of_diagnostic_ids_to_use_as_a_filter_when_fixing_code_style_or_3rd_party_issues">
<source>A space separated list of diagnostic ids to use as a filter when fixing code style or 3rd party issues.</source>
<target state="new">A space separated list of diagnostic ids to use as a filter when fixing code style or 3rd party issues.</target>
<note />
</trans-unit>
<trans-unit id="Accepts_a_file_path_which_if_provided_will_produce_a_format_report_json_file_in_the_given_directory">
<source>Accepts a file path, which if provided, will produce a json report in the given directory.</source>
<target state="translated">Akzeptiert einen Dateipfad, der bei Bereitstellung einen JSON-Bericht im angegebenen Verzeichnis erstellt.</target>
Expand Down
5 changes: 5 additions & 0 deletions src/xlf/Resources.es.xlf
Expand Up @@ -17,6 +17,11 @@
<target state="translated">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.</target>
<note />
</trans-unit>
<trans-unit id="A_space_separated_list_of_diagnostic_ids_to_use_as_a_filter_when_fixing_code_style_or_3rd_party_issues">
<source>A space separated list of diagnostic ids to use as a filter when fixing code style or 3rd party issues.</source>
<target state="new">A space separated list of diagnostic ids to use as a filter when fixing code style or 3rd party issues.</target>
<note />
</trans-unit>
<trans-unit id="Accepts_a_file_path_which_if_provided_will_produce_a_format_report_json_file_in_the_given_directory">
<source>Accepts a file path, which if provided, will produce a json report in the given directory.</source>
<target state="translated">Acepta una ruta de acceso de archivo que, si se proporciona, generará un informe JSON en el directorio dado.</target>
Expand Down

0 comments on commit 15305cc

Please sign in to comment.