Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to filter diagnostics by id #1007

Merged
merged 3 commits into from Feb 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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>())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would like it if we could provide a helpful message if this option is provide and we are not in a --fix-stlye or --fix-analyzers mode

},
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>