Skip to content

Commit

Permalink
Merge pull request #1007 from JoeRobich/add-diagnostics-filter
Browse files Browse the repository at this point in the history
Add option to filter diagnostics by id
  • Loading branch information
JoeRobich committed Feb 26, 2021
2 parents c8793cb + 7f62199 commit d4bedaf
Show file tree
Hide file tree
Showing 30 changed files with 477 additions and 22 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
9 changes: 7 additions & 2 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 Expand Up @@ -84,7 +89,7 @@ internal static RootCommand CreateCommandLineOptions()
var folder = symbolResult.ValueForOption<bool>("--folder");
var fixAnalyzers = symbolResult.OptionResult("--fix-analyzers");
return folder && fixAnalyzers != null
? "Cannot specify the '--folder' option when running analyzers."
? Resources.Cannot_specify_the_folder_option_when_running_analyzers
: null;
}

Expand All @@ -93,7 +98,7 @@ internal static RootCommand CreateCommandLineOptions()
var folder = symbolResult.ValueForOption<bool>("--folder");
var fixStyle = symbolResult.OptionResult("--fix-style");
return folder && fixStyle != null
? "Cannot specify the '--folder' option when fixing style."
? Resources.Cannot_specify_the_folder_option_when_fixing_style
: null;
}

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
8 changes: 8 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 @@ -148,6 +150,11 @@ private static async Task<int> Main(string[] args)
fixType |= FixCategory.Analyzers;
}

if (fixType == FixCategory.None && diagnostics.Length > 0)
{
logger.LogWarning(Resources.The_diagnostics_option_only_applies_when_fixing_style_or_running_analyzers);
}

if (fixType == FixCategory.None || fixWhitespace)
{
fixType |= FixCategory.Whitespace;
Expand All @@ -164,6 +171,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
12 changes: 12 additions & 0 deletions src/Resources.resx
Expand Up @@ -297,4 +297,16 @@
<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>
<data name="The_diagnostics_option_only_applies_when_fixing_style_or_running_analyzers" xml:space="preserve">
<value>The '--diagnostics' option only applies when fixing style or running analyzers.</value>
</data>
<data name="Cannot_specify_the_folder_option_when_running_analyzers" xml:space="preserve">
<value>Cannot specify the '--folder' option when running analyzers.</value>
</data>
<data name="Cannot_specify_the_folder_option_when_fixing_style" xml:space="preserve">
<value>Cannot specify the '--folder' option when fixing style.</value>
</data>
</root>

0 comments on commit d4bedaf

Please sign in to comment.