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 for whitespace formatting #774

Merged
merged 4 commits into from Sep 9, 2020
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
29 changes: 16 additions & 13 deletions README.md
Expand Up @@ -72,8 +72,9 @@ Arguments:

Options:
--folder, -f Whether to treat the `<workspace>` argument as a simple folder of files.
--fix-style <severity> Run code style analyzers and apply fixes.
--fix-analyzers <severity> Run 3rd party analyzers and apply fixes.
--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.
--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 @@ -84,17 +85,19 @@ Options:

Add `format` after `dotnet` and before the command arguments that you want to run:

| Examples | Description |
| ---------------------------------------------------------- |---------------------------------------------------------------------------------------------- |
| dotnet **format** | Formats the project or solution in the current directory. |
| dotnet **format** &lt;workspace&gt; | Formats a specific project or solution. |
| dotnet **format** &lt;workspace&gt; -f | Formats a particular folder and subfolders. |
| dotnet **format** &lt;workspace&gt; --fix-style warn | Formats and fixes codestyle analyzer warnings. |
| dotnet **format** &lt;workspace&gt; --fix-analyzers | Formats and fixes 3rd party analyzer errors. |
| dotnet **format** -v diag | Formats with very verbose logging. |
| dotnet **format** --include Programs.cs Utility\Logging.cs | Formats the files Program.cs and Utility\Logging.cs |
| dotnet **format** --check | Formats but does not save. Returns a non-zero exit code if any files would have been changed. |
| dotnet **format** --report &lt;report-path&gt; | Formats and saves a json report file to the given directory. |
| Examples | Description |
| ---------------------------------------------------------------- |---------------------------------------------------------------------------------------------- |
| dotnet **format** | Formats the project or solution in the current directory. |
| dotnet **format** &lt;workspace&gt; | Formats a specific project or solution. |
| dotnet **format** &lt;workspace&gt; -f | Formats a particular folder and subfolders. |
| dotnet **format** &lt;workspace&gt; --fix-style warn | Fixes only codestyle analyzer warnings. |
| dotnet **format** &lt;workspace&gt; --fix-whitespace --fix-style | Formats and fixes codestyle analyzer errors. |
| dotnet **format** &lt;workspace&gt; --fix-analyzers | Fixes only 3rd party analyzer errors. |
| dotnet **format** &lt;workspace&gt; -wsa | Formats, fixes codestyle errors, and fixes 3rd party analyzer errors. |
| dotnet **format** -v diag | Formats with very verbose logging. |
| dotnet **format** --include Programs.cs Utility\Logging.cs | Formats the files Program.cs and Utility\Logging.cs |
| dotnet **format** --check | Formats but does not save. Returns a non-zero exit code if any files would have been changed. |
| dotnet **format** --report &lt;report-path&gt; | Formats and saves a json report file to the given directory. |

### How To Uninstall

Expand Down
18 changes: 17 additions & 1 deletion docs/README.md
Expand Up @@ -32,6 +32,22 @@ Format the code files from the `./src` folder.
dotnet-format ./src --folder
```

### Whitespace formatting

Whitespace formatting includes the core .editorconfig settings along with the placement of spaces and newlines. The whitespace formatter is run by default when not running analysis. When you want to run analysis and fix formatting issues you must specify both.

Whitespace formatting run by default.

```console
dotnet-format ./format.sln
```

Running the whitespace formatter along with code-style analysis.

```console
dotnet-format ./format.sln --fix-whitespace --fix-style
```

### Running analysis

#### CodeStyle analysis
Expand All @@ -42,7 +58,7 @@ Running codestyle analysis requires the use of a MSBuild solution or project fil

*Example:*

Run analysis against the format solution and fix errors.
Run code-style analysis against the format solution and fix errors.

```console
dotnet-format ./format.sln --fix-style
Expand Down
2 changes: 1 addition & 1 deletion eng/format-verifier.ps1
Expand Up @@ -62,7 +62,7 @@ try {

if ($stage -eq "format-workspace") {
Write-Output "$(Get-Date) - $solutionFile - Formatting Workspace"
$output = dotnet.exe run -p "$currentLocation\src\dotnet-format.csproj" -c Release -- $solution --fix-style --fix-analyzers -v diag --check | Out-String
$output = dotnet.exe run -p "$currentLocation\src\dotnet-format.csproj" -c Release -- $solution -wsa -v diag --check | Out-String
Write-Output $output.TrimEnd()

# Ignore CheckFailedExitCode since we don't expect these repos to be properly formatted.
Expand Down
9 changes: 3 additions & 6 deletions perf/FormattedFiles.cs
Expand Up @@ -33,9 +33,8 @@ public void FilesFormattedFolder()
workspacePath,
workspaceType,
LogLevel.Error,
fixCodeStyle: false,
fixCategory: FixCategory.Whitespace,
codeStyleSeverity: DiagnosticSeverity.Error,
fixAnalyzers: false,
analyzerSeverity: DiagnosticSeverity.Error,
saveFormattedFiles: false,
changesAreErrors: false,
Expand All @@ -53,9 +52,8 @@ public void FilesFormattedProject()
workspacePath,
workspaceType,
LogLevel.Error,
fixCodeStyle: false,
fixCategory: FixCategory.Whitespace,
codeStyleSeverity: DiagnosticSeverity.Error,
fixAnalyzers: false,
analyzerSeverity: DiagnosticSeverity.Error,
saveFormattedFiles: false,
changesAreErrors: false,
Expand All @@ -73,9 +71,8 @@ public void FilesFormattedSolution()
workspacePath,
workspaceType,
LogLevel.Error,
fixCodeStyle: false,
fixCategory: FixCategory.Whitespace,
codeStyleSeverity: DiagnosticSeverity.Error,
fixAnalyzers: false,
analyzerSeverity: DiagnosticSeverity.Error,
saveFormattedFiles: false,
changesAreErrors: false,
Expand Down
9 changes: 3 additions & 6 deletions perf/NoFilesFormatted.cs
Expand Up @@ -33,9 +33,8 @@ public void NoFilesFormattedFolder()
workspacePath,
workspaceType,
LogLevel.Error,
fixCodeStyle: false,
fixCategory: FixCategory.Whitespace,
codeStyleSeverity: DiagnosticSeverity.Error,
fixAnalyzers: false,
analyzerSeverity: DiagnosticSeverity.Error,
saveFormattedFiles: false,
changesAreErrors: false,
Expand All @@ -53,9 +52,8 @@ public void NoFilesFormattedProject()
workspacePath,
workspaceType,
LogLevel.Error,
fixCodeStyle: false,
fixCategory: FixCategory.Whitespace,
codeStyleSeverity: DiagnosticSeverity.Error,
fixAnalyzers: false,
analyzerSeverity: DiagnosticSeverity.Error,
saveFormattedFiles: false,
changesAreErrors: false,
Expand All @@ -73,9 +71,8 @@ public void NoFilesFormattedSolution()
workspacePath,
workspaceType,
LogLevel.Error,
fixCodeStyle: false,
fixCategory: FixCategory.Whitespace,
codeStyleSeverity: DiagnosticSeverity.Error,
fixAnalyzers: false,
analyzerSeverity: DiagnosticSeverity.Error,
saveFormattedFiles: false,
changesAreErrors: false,
Expand Down
6 changes: 2 additions & 4 deletions perf/RealWorldSolution.cs
Expand Up @@ -35,9 +35,8 @@ public void FilesFormattedSolution()
workspacePath,
workspaceType,
LogLevel.Error,
fixCodeStyle: false,
fixCategory: FixCategory.Whitespace,
codeStyleSeverity: DiagnosticSeverity.Error,
fixAnalyzers: false,
analyzerSeverity: DiagnosticSeverity.Error,
saveFormattedFiles: false,
changesAreErrors: false,
Expand All @@ -55,9 +54,8 @@ public void FilesFormattedFolder()
workspacePath,
workspaceType,
LogLevel.Error,
fixCodeStyle: false,
fixCategory: FixCategory.Whitespace,
codeStyleSeverity: DiagnosticSeverity.Error,
fixAnalyzers: false,
analyzerSeverity: DiagnosticSeverity.Error,
saveFormattedFiles: false,
changesAreErrors: false,
Expand Down
4 changes: 4 additions & 0 deletions src/Analyzers/AnalyzerFormatter.cs
Expand Up @@ -21,13 +21,17 @@ internal class AnalyzerFormatter : ICodeFormatter
private readonly IAnalyzerRunner _runner;
private readonly ICodeFixApplier _applier;

public FixCategory Category { get; }

public AnalyzerFormatter(
string name,
FixCategory category,
IAnalyzerInformationProvider informationProvider,
IAnalyzerRunner runner,
ICodeFixApplier applier)
{
_name = name;
Category = category;
_informationProvider = informationProvider;
_runner = runner;
_applier = applier;
Expand Down
5 changes: 0 additions & 5 deletions src/Analyzers/AnalyzerReferenceInformationProvider.cs
Expand Up @@ -17,11 +17,6 @@ internal class AnalyzerReferenceInformationProvider : IAnalyzerInformationProvid
FormatOptions formatOptions,
ILogger logger)
{
if (!formatOptions.FixAnalyzers)
{
return ImmutableDictionary<ProjectId, AnalyzersAndFixers>.Empty;
}

return solution.Projects
.ToImmutableDictionary(project => project.Id, GetAnalyzersAndFixers);
}
Expand Down
7 changes: 1 addition & 6 deletions src/Analyzers/CodeStyleInformationProvider.cs
Expand Up @@ -18,14 +18,9 @@ internal class CodeStyleInformationProvider : IAnalyzerInformationProvider

public ImmutableDictionary<ProjectId, AnalyzersAndFixers> GetAnalyzersAndFixers(
Solution solution,
FormatOptions options,
FormatOptions formatOptions,
ILogger logger)
{
if (!options.FixCodeStyle)
{
return ImmutableDictionary<ProjectId, AnalyzersAndFixers>.Empty;
}

var assemblies = new[]
{
_featuresPath,
Expand Down
10 changes: 8 additions & 2 deletions src/CodeFormatter.cs
Expand Up @@ -25,8 +25,8 @@ internal static class CodeFormatter
new CharsetFormatter(),
new OrganizeImportsFormatter(),
new UnnecessaryImportsFormatter(),
new AnalyzerFormatter(Resources.Code_Style, new CodeStyleInformationProvider(), new AnalyzerRunner(), new SolutionCodeFixApplier()),
new AnalyzerFormatter(Resources.Analyzer_Reference, new AnalyzerReferenceInformationProvider(), new AnalyzerRunner(), new SolutionCodeFixApplier()));
new AnalyzerFormatter(Resources.Code_Style, FixCategory.CodeStyle, new CodeStyleInformationProvider(), new AnalyzerRunner(), new SolutionCodeFixApplier()),
new AnalyzerFormatter(Resources.Analyzer_Reference, FixCategory.Analyzers, new AnalyzerReferenceInformationProvider(), new AnalyzerRunner(), new SolutionCodeFixApplier()));

public static async Task<WorkspaceFormatResult> FormatWorkspaceAsync(
FormatOptions formatOptions,
Expand Down Expand Up @@ -132,6 +132,12 @@ private static Workspace OpenFolderWorkspace(string workspacePath, SourceFileMat

for (var index = 0; index < s_codeFormatters.Length; index++)
{
// Only run the formatter if it belongs to one of the categories being fixed.
if (!formatOptions.FixCategory.HasFlag(s_codeFormatters[index].Category))
{
continue;
}

formattedSolution = await s_codeFormatters[index].FormatAsync(formattedSolution, formattableDocuments, formatOptions, logger, formattedFiles, cancellationToken).ConfigureAwait(false);
}

Expand Down
15 changes: 15 additions & 0 deletions src/FixCategory.cs
@@ -0,0 +1,15 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information.

using System;

namespace Microsoft.CodeAnalysis.Tools
{
[Flags]
internal enum FixCategory
{
None = 0,
Whitespace = 1,
CodeStyle = 2,
Analyzers = 4
}
}
5 changes: 3 additions & 2 deletions src/FormatCommand.cs
Expand Up @@ -22,11 +22,12 @@ internal static RootCommand CreateCommandLineOptions()
Description = Resources.A_path_to_a_solution_file_a_project_file_or_a_folder_containing_a_solution_or_project_file_If_a_path_is_not_specified_then_the_current_directory_is_used
}.LegalFilePathsOnly(),
new Option(new[] { "--folder", "-f" }, Resources.Whether_to_treat_the_workspace_argument_as_a_simple_folder_of_files),
new Option(new[] { "--fix-style" }, Resources.Run_code_style_analyzers_and_apply_fixes)
new Option(new[] { "--fix-whitespace", "-w" }, Resources.Run_whitespace_formatting_Run_by_default_when_not_applying_fixes),
new Option(new[] { "--fix-style", "-s" }, Resources.Run_code_style_analyzers_and_apply_fixes)
{
Argument = new Argument<string?>("severity") { Arity = ArgumentArity.ZeroOrOne }.FromAmong(SeverityLevels)
},
new Option(new[] { "--fix-analyzers" }, Resources.Run_3rd_party_analyzers_and_apply_fixes)
new Option(new[] { "--fix-analyzers", "-a" }, Resources.Run_3rd_party_analyzers_and_apply_fixes)
{
Argument = new Argument<string?>("severity") { Arity = ArgumentArity.ZeroOrOne }.FromAmong(SeverityLevels)
},
Expand Down
15 changes: 5 additions & 10 deletions src/FormatOptions.cs
Expand Up @@ -10,9 +10,8 @@ internal class FormatOptions
public string WorkspaceFilePath { get; }
public WorkspaceType WorkspaceType { get; }
public LogLevel LogLevel { get; }
public bool FixCodeStyle { get; }
public FixCategory FixCategory { get; }
public DiagnosticSeverity CodeStyleSeverity { get; }
public bool FixAnalyzers { get; }
public DiagnosticSeverity AnalyzerSeverity { get; }
public bool SaveFormattedFiles { get; }
public bool ChangesAreErrors { get; }
Expand All @@ -24,9 +23,8 @@ internal class FormatOptions
string workspaceFilePath,
WorkspaceType workspaceType,
LogLevel logLevel,
bool fixCodeStyle,
FixCategory fixCategory,
DiagnosticSeverity codeStyleSeverity,
bool fixAnalyzers,
DiagnosticSeverity analyzerSeverity,
bool saveFormattedFiles,
bool changesAreErrors,
Expand All @@ -37,9 +35,8 @@ internal class FormatOptions
WorkspaceFilePath = workspaceFilePath;
WorkspaceType = workspaceType;
LogLevel = logLevel;
FixCodeStyle = fixCodeStyle;
FixCategory = fixCategory;
CodeStyleSeverity = codeStyleSeverity;
FixAnalyzers = fixAnalyzers;
AnalyzerSeverity = analyzerSeverity;
SaveFormattedFiles = saveFormattedFiles;
ChangesAreErrors = changesAreErrors;
Expand All @@ -52,9 +49,8 @@ internal class FormatOptions
out string workspaceFilePath,
out WorkspaceType workspaceType,
out LogLevel logLevel,
out bool fixCodeStyle,
out FixCategory fixCategory,
out DiagnosticSeverity codeStyleSeverity,
out bool fixAnalyzers,
out DiagnosticSeverity analyzerSeverity,
out bool saveFormattedFiles,
out bool changesAreErrors,
Expand All @@ -65,9 +61,8 @@ internal class FormatOptions
workspaceFilePath = WorkspaceFilePath;
workspaceType = WorkspaceType;
logLevel = LogLevel;
fixCodeStyle = FixCodeStyle;
fixCategory = FixCategory;
codeStyleSeverity = CodeStyleSeverity;
fixAnalyzers = FixAnalyzers;
analyzerSeverity = AnalyzerSeverity;
saveFormattedFiles = SaveFormattedFiles;
changesAreErrors = ChangesAreErrors;
Expand Down
2 changes: 2 additions & 0 deletions src/Formatters/CharsetFormatter.cs
Expand Up @@ -20,6 +20,8 @@ internal sealed class CharsetFormatter : DocumentFormatter
private static Encoding Utf8 => new UTF8Encoding(encoderShouldEmitUTF8Identifier: false);
private static Encoding Latin1 => Encoding.GetEncoding("iso-8859-1");

public override FixCategory Category => FixCategory.Whitespace;

internal override Task<SourceText> FormatFileAsync(
Document document,
SourceText sourceText,
Expand Down
5 changes: 5 additions & 0 deletions src/Formatters/DocumentFormatter.cs
Expand Up @@ -20,6 +20,11 @@ internal abstract class DocumentFormatter : ICodeFormatter
{
protected abstract string FormatWarningDescription { get; }

/// <summary>
/// Gets the fix category this formatter belongs to.
/// </summary>
public abstract FixCategory Category { get; }

/// <summary>
/// Applies formatting and returns a formatted <see cref="Solution"/>
/// </summary>
Expand Down
2 changes: 2 additions & 0 deletions src/Formatters/EndOfLineFormatter.cs
Expand Up @@ -15,6 +15,8 @@ internal sealed class EndOfLineFormatter : DocumentFormatter
{
protected override string FormatWarningDescription => Resources.Fix_end_of_line_marker;

public override FixCategory Category => FixCategory.Whitespace;

internal override Task<SourceText> FormatFileAsync(
Document document,
SourceText sourceText,
Expand Down
2 changes: 2 additions & 0 deletions src/Formatters/FinalNewlineFormatter.cs
Expand Up @@ -14,6 +14,8 @@ internal sealed class FinalNewlineFormatter : DocumentFormatter
{
protected override string FormatWarningDescription => Resources.Fix_final_newline;

public override FixCategory Category => FixCategory.Whitespace;

internal override async Task<SourceText> FormatFileAsync(
Document document,
SourceText sourceText,
Expand Down
5 changes: 5 additions & 0 deletions src/Formatters/ICodeFormatter.cs
Expand Up @@ -10,6 +10,11 @@ namespace Microsoft.CodeAnalysis.Tools.Formatters
{
internal interface ICodeFormatter
{
/// <summary>
/// Gets the fix category this formatter belongs to.
/// </summary>
FixCategory Category { get; }

/// <summary>
/// Applies formatting and returns a formatted <see cref="Solution"/>.
/// </summary>
Expand Down