diff --git a/.vscode/launch.json b/.vscode/launch.json
index 7a7d90462e..a2d619556a 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -40,6 +40,45 @@
"console": "internalConsole",
"stopAtEntry": false
},
+ {
+ "name": "format format.sln --fix-style --check",
+ "type": "coreclr",
+ "request": "launch",
+ "preLaunchTask": "publish",
+ // If you have changed target frameworks, make sure to update the program path.
+ "program": "${workspaceFolder}/artifacts/bin/dotnet-format/Debug/netcoreapp2.1/publish/dotnet-format.dll",
+ "args": [
+ "format.sln",
+ "--fix-style",
+ "-v",
+ "diag",
+ "--check"
+ ],
+ "cwd": "${workspaceFolder}",
+ // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
+ "console": "internalConsole",
+ "stopAtEntry": false
+ },
+ {
+ "name": "format format.sln --fix-analyzers warn --check",
+ "type": "coreclr",
+ "request": "launch",
+ "preLaunchTask": "publish",
+ // If you have changed target frameworks, make sure to update the program path.
+ "program": "${workspaceFolder}/artifacts/bin/dotnet-format/Debug/netcoreapp2.1/publish/dotnet-format.dll",
+ "args": [
+ "format.sln",
+ "--fix-analyzers",
+ "warn",
+ "-v",
+ "diag",
+ "--check"
+ ],
+ "cwd": "${workspaceFolder}",
+ // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
+ "console": "internalConsole",
+ "stopAtEntry": false
+ },
{
"name": ".NET Core Attach",
"type": "coreclr",
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
index 121f98c008..42e5fa8037 100644
--- a/.vscode/tasks.json
+++ b/.vscode/tasks.json
@@ -1,42 +1,44 @@
{
- "version": "2.0.0",
- "tasks": [
- {
- "label": "build",
- "command": "dotnet",
- "type": "process",
- "args": [
- "build",
- "${workspaceFolder}/src/dotnet-format.csproj",
- "/property:GenerateFullPaths=true",
- "/consoleloggerparameters:NoSummary"
- ],
- "problemMatcher": "$msCompile"
- },
- {
- "label": "publish",
- "command": "dotnet",
- "type": "process",
- "args": [
- "publish",
- "${workspaceFolder}/src/dotnet-format.csproj",
- "/property:GenerateFullPaths=true",
- "/consoleloggerparameters:NoSummary"
- ],
- "problemMatcher": "$msCompile"
- },
- {
- "label": "watch",
- "command": "dotnet",
- "type": "process",
- "args": [
- "watch",
- "run",
- "${workspaceFolder}/src/dotnet-format.csproj",
- "/property:GenerateFullPaths=true",
- "/consoleloggerparameters:NoSummary"
- ],
- "problemMatcher": "$msCompile"
- }
- ]
+ "version": "2.0.0",
+ "tasks": [
+ {
+ "label": "build",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "build",
+ "${workspaceFolder}/src/dotnet-format.csproj",
+ "/property:GenerateFullPaths=true",
+ "/consoleloggerparameters:NoSummary"
+ ],
+ "problemMatcher": "$msCompile"
+ },
+ {
+ "label": "publish",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "publish",
+ "${workspaceFolder}/src/dotnet-format.csproj",
+ "-c",
+ "Debug",
+ "/property:GenerateFullPaths=true",
+ "/consoleloggerparameters:NoSummary"
+ ],
+ "problemMatcher": "$msCompile"
+ },
+ {
+ "label": "watch",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "watch",
+ "run",
+ "${workspaceFolder}/src/dotnet-format.csproj",
+ "/property:GenerateFullPaths=true",
+ "/consoleloggerparameters:NoSummary"
+ ],
+ "problemMatcher": "$msCompile"
+ }
+ ]
}
\ No newline at end of file
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index 2ee8396e1a..15b01af228 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -111,7 +111,9 @@ jobs:
vmImage: 'vs2017-win2016'
timeoutInMinutes: 5
steps:
- - script: dotnet run --project ./src/dotnet-format.csproj -- @validate.rsp
+ - script: dotnet publish ./src/dotnet-format.csproj -c Release
+ displayName: Publish dotnet-format
+ - script: dotnet ./artifacts/bin/dotnet-format/Release/netcoreapp2.1/publish/dotnet-format.dll @validate.rsp
displayName: Run dotnet-format
- task: PublishBuildArtifacts@1
displayName: Publish Logs
diff --git a/eng/Signing.props b/eng/Signing.props
deleted file mode 100644
index f8bf051e1b..0000000000
--- a/eng/Signing.props
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/eng/Versions.props b/eng/Versions.props
index 0d0676b084..a2923f0c84 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -1,7 +1,7 @@
- 4
+ 5
0
diff --git a/perf/FormattedFiles.cs b/perf/FormattedFiles.cs
index 8ba5783c70..b5d57b377f 100644
--- a/perf/FormattedFiles.cs
+++ b/perf/FormattedFiles.cs
@@ -34,7 +34,10 @@ public void FilesFormattedFolder()
workspacePath,
workspaceType,
LogLevel.Error,
- FormatType.All,
+ fixCodeStyle: false,
+ codeStyleSeverity: DiagnosticSeverity.Error,
+ fixAnalyzers: false,
+ analyerSeverity: DiagnosticSeverity.Error,
saveFormattedFiles: false,
changesAreErrors: false,
AllFileMatcher,
@@ -51,7 +54,10 @@ public void FilesFormattedProject()
workspacePath,
workspaceType,
LogLevel.Error,
- FormatType.All,
+ fixCodeStyle: false,
+ codeStyleSeverity: DiagnosticSeverity.Error,
+ fixAnalyzers: false,
+ analyerSeverity: DiagnosticSeverity.Error,
saveFormattedFiles: false,
changesAreErrors: false,
AllFileMatcher,
@@ -68,7 +74,10 @@ public void FilesFormattedSolution()
workspacePath,
workspaceType,
LogLevel.Error,
- FormatType.All,
+ fixCodeStyle: false,
+ codeStyleSeverity: DiagnosticSeverity.Error,
+ fixAnalyzers: false,
+ analyerSeverity: DiagnosticSeverity.Error,
saveFormattedFiles: false,
changesAreErrors: false,
AllFileMatcher,
diff --git a/perf/NoFilesFormatted.cs b/perf/NoFilesFormatted.cs
index a88f05f667..2d66554efd 100644
--- a/perf/NoFilesFormatted.cs
+++ b/perf/NoFilesFormatted.cs
@@ -34,7 +34,10 @@ public void NoFilesFormattedFolder()
workspacePath,
workspaceType,
LogLevel.Error,
- FormatType.All,
+ fixCodeStyle: false,
+ codeStyleSeverity: DiagnosticSeverity.Error,
+ fixAnalyzers: false,
+ analyerSeverity: DiagnosticSeverity.Error,
saveFormattedFiles: false,
changesAreErrors: false,
AllFileMatcher,
@@ -51,7 +54,10 @@ public void NoFilesFormattedProject()
workspacePath,
workspaceType,
LogLevel.Error,
- FormatType.All,
+ fixCodeStyle: false,
+ codeStyleSeverity: DiagnosticSeverity.Error,
+ fixAnalyzers: false,
+ analyerSeverity: DiagnosticSeverity.Error,
saveFormattedFiles: false,
changesAreErrors: false,
AllFileMatcher,
@@ -68,7 +74,10 @@ public void NoFilesFormattedSolution()
workspacePath,
workspaceType,
LogLevel.Error,
- FormatType.All,
+ fixCodeStyle: false,
+ codeStyleSeverity: DiagnosticSeverity.Error,
+ fixAnalyzers: false,
+ analyerSeverity: DiagnosticSeverity.Error,
saveFormattedFiles: false,
changesAreErrors: false,
AllFileMatcher,
diff --git a/perf/RealWorldSolution.cs b/perf/RealWorldSolution.cs
index c7358d7539..999ba730e5 100644
--- a/perf/RealWorldSolution.cs
+++ b/perf/RealWorldSolution.cs
@@ -36,7 +36,10 @@ public void FilesFormattedSolution()
workspacePath,
workspaceType,
LogLevel.Error,
- FormatType.All,
+ fixCodeStyle: false,
+ codeStyleSeverity: DiagnosticSeverity.Error,
+ fixAnalyzers: false,
+ analyerSeverity: DiagnosticSeverity.Error,
saveFormattedFiles: false,
changesAreErrors: false,
AllFileMatcher,
@@ -53,7 +56,10 @@ public void FilesFormattedFolder()
workspacePath,
workspaceType,
LogLevel.Error,
- FormatType.All,
+ fixCodeStyle: false,
+ codeStyleSeverity: DiagnosticSeverity.Error,
+ fixAnalyzers: false,
+ analyerSeverity: DiagnosticSeverity.Error,
saveFormattedFiles: false,
changesAreErrors: false,
AllFileMatcher,
diff --git a/src/Analyzers/AnalyzerFinderHelpers.cs b/src/Analyzers/AnalyzerFinderHelpers.cs
new file mode 100644
index 0000000000..21ab8eaa09
--- /dev/null
+++ b/src/Analyzers/AnalyzerFinderHelpers.cs
@@ -0,0 +1,83 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information.
+
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Linq;
+using System.Reflection;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.Extensions.Logging;
+
+namespace Microsoft.CodeAnalysis.Tools.Analyzers
+{
+ internal static class AnalyzerFinderHelpers
+ {
+ public static ImmutableArray<(DiagnosticAnalyzer Analyzer, CodeFixProvider? Fixer)> LoadAnalyzersAndFixers(
+ IEnumerable assemblies,
+ ILogger logger)
+ {
+ var types = assemblies
+ .SelectMany(assembly => assembly.GetTypes()
+ .Where(type => !type.GetTypeInfo().IsInterface &&
+ !type.GetTypeInfo().IsAbstract &&
+ !type.GetTypeInfo().ContainsGenericParameters));
+
+ var codeFixProviders = types
+ .Where(t => typeof(CodeFixProvider).IsAssignableFrom(t))
+ .Select(type => type.TryCreateInstance(out var instance) ? instance : null)
+ .OfType()
+ .ToImmutableArray();
+
+ var diagnosticAnalyzers = types
+ .Where(t => typeof(DiagnosticAnalyzer).IsAssignableFrom(t))
+ .Select(type => type.TryCreateInstance(out var instance) ? instance : null)
+ .OfType()
+ .ToImmutableArray();
+
+ var builder = ImmutableArray.CreateBuilder<(DiagnosticAnalyzer Analyzer, CodeFixProvider? Fixer)>();
+ foreach (var diagnosticAnalyzer in diagnosticAnalyzers)
+ {
+ var diagnosticIds = diagnosticAnalyzer.SupportedDiagnostics.Select(diagnostic => diagnostic.Id).ToImmutableHashSet();
+ var codeFixProvider = codeFixProviders.FirstOrDefault(codeFixProvider => codeFixProvider.FixableDiagnosticIds.Any(id => diagnosticIds.Contains(id)));
+
+ if (codeFixProvider is null)
+ {
+ continue;
+ }
+
+ builder.Add((diagnosticAnalyzer, codeFixProvider));
+ }
+
+ return builder.ToImmutableArray();
+ }
+
+ public static async Task>> FilterBySeverityAsync(
+ IEnumerable projects,
+ ImmutableArray allAnalyzers,
+ ImmutableHashSet formattablePaths,
+ DiagnosticSeverity minimumSeverity,
+ CancellationToken cancellationToken)
+ {
+ var projectAnalyzers = ImmutableDictionary.CreateBuilder>();
+ foreach (var project in projects)
+ {
+ var analyzers = ImmutableArray.CreateBuilder();
+
+ foreach (var analyzer in allAnalyzers)
+ {
+ var severity = await analyzer.GetSeverityAsync(project, formattablePaths, cancellationToken).ConfigureAwait(false);
+ if (severity >= minimumSeverity)
+ {
+ analyzers.Add(analyzer);
+ }
+ }
+
+ projectAnalyzers.Add(project, analyzers.ToImmutableArray());
+ }
+
+ return projectAnalyzers.ToImmutableDictionary();
+ }
+ }
+}
diff --git a/src/Analyzers/AnalyzerFormatter.cs b/src/Analyzers/AnalyzerFormatter.cs
index 8b1fb8d504..ffabcba3a4 100644
--- a/src/Analyzers/AnalyzerFormatter.cs
+++ b/src/Analyzers/AnalyzerFormatter.cs
@@ -7,6 +7,8 @@
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Tools.Formatters;
using Microsoft.Extensions.Logging;
@@ -14,17 +16,18 @@ namespace Microsoft.CodeAnalysis.Tools.Analyzers
{
internal class AnalyzerFormatter : ICodeFormatter
{
- public FormatType FormatType => FormatType.CodeStyle;
-
+ private readonly string _name;
private readonly IAnalyzerFinder _finder;
private readonly IAnalyzerRunner _runner;
private readonly ICodeFixApplier _applier;
public AnalyzerFormatter(
+ string name,
IAnalyzerFinder finder,
IAnalyzerRunner runner,
ICodeFixApplier applier)
{
+ _name = name;
_finder = finder;
_runner = runner;
_applier = applier;
@@ -33,47 +36,71 @@ internal class AnalyzerFormatter : ICodeFormatter
public async Task FormatAsync(
Solution solution,
ImmutableArray formattableDocuments,
- FormatOptions options,
+ FormatOptions formatOptions,
ILogger logger,
List formattedFiles,
CancellationToken cancellationToken)
{
- var analysisStopwatch = Stopwatch.StartNew();
- logger.LogTrace($"Analyzing code style.");
-
- if (!options.SaveFormattedFiles)
+ var analyzersAndFixers = _finder.GetAnalyzersAndFixers(solution, formatOptions, logger);
+ if (analyzersAndFixers.Length == 0)
{
- await LogDiagnosticsAsync(solution, formattableDocuments, options, logger, cancellationToken);
- }
- else
- {
- solution = await FixDiagnosticsAsync(solution, formattableDocuments, logger, cancellationToken);
+ return solution;
}
+ var analysisStopwatch = Stopwatch.StartNew();
+ logger.LogTrace($"Running {_name} analysis.");
+
+ var formattablePaths = formattableDocuments.Select(id => solution.GetDocument(id)!.FilePath)
+ .OfType().ToImmutableHashSet();
+
+ logger.LogTrace("Determining diagnostics...");
+
+ var allAnalyzers = analyzersAndFixers.Select(pair => pair.Analyzer).ToImmutableArray();
+ var projectAnalyzers = await _finder.FilterBySeverityAsync(solution.Projects, allAnalyzers, formattablePaths, formatOptions, cancellationToken).ConfigureAwait(false);
+
+ var projectDiagnostics = await GetProjectDiagnosticsAsync(solution, projectAnalyzers, formattablePaths, formatOptions, logger, formattedFiles, cancellationToken).ConfigureAwait(false);
+
+ var projectDiagnosticsMS = analysisStopwatch.ElapsedMilliseconds;
+ logger.LogTrace(Resources.Complete_in_0_ms, projectDiagnosticsMS);
+
+ logger.LogTrace("Fixing diagnostics...");
+
+ solution = await FixDiagnosticsAsync(solution, analyzersAndFixers, projectDiagnostics, formattablePaths, logger, cancellationToken).ConfigureAwait(false);
+
+ var fixDiagnosticsMS = analysisStopwatch.ElapsedMilliseconds - projectDiagnosticsMS;
+ logger.LogTrace(Resources.Complete_in_0_ms, fixDiagnosticsMS);
+
logger.LogTrace("Analysis complete in {0}ms.", analysisStopwatch.ElapsedMilliseconds);
return solution;
}
- private async Task LogDiagnosticsAsync(Solution solution, ImmutableArray formattableDocuments, FormatOptions options, ILogger logger, CancellationToken cancellationToken)
+ private async Task>> GetProjectDiagnosticsAsync(
+ Solution solution,
+ ImmutableDictionary> projectAnalyzers,
+ ImmutableHashSet formattablePaths,
+ FormatOptions options,
+ ILogger logger,
+ List formattedFiles,
+ CancellationToken cancellationToken)
{
- var pairs = _finder.GetAnalyzersAndFixers();
- var paths = formattableDocuments.Select(id => solution.GetDocument(id)?.FilePath)
- .OfType().ToImmutableArray();
-
- // no need to run codefixes as we won't persist the changes
- var analyzers = pairs.Select(x => x.Analyzer).ToImmutableArray();
var result = new CodeAnalysisResult();
- await solution.Projects.ForEachAsync(async (project, token) =>
+ foreach (var project in solution.Projects)
{
- await _runner.RunCodeAnalysisAsync(result, analyzers, project, paths, logger, token);
- }, cancellationToken);
+ var analyzers = projectAnalyzers[project];
+ if (analyzers.Length == 0)
+ {
+ continue;
+ }
+
+ await _runner.RunCodeAnalysisAsync(result, analyzers, project, formattablePaths, logger, cancellationToken).ConfigureAwait(false);
+ }
- LogDiagnosticLocations(result.Diagnostics.SelectMany(kvp => kvp.Value), options.WorkspaceFilePath, options.ChangesAreErrors, logger);
+ LogDiagnosticLocations(solution, result.Diagnostics.SelectMany(kvp => kvp.Value), options.WorkspaceFilePath, options.ChangesAreErrors, logger, formattedFiles);
- return;
+ return result.Diagnostics.ToImmutableDictionary(kvp => kvp.Key.Id, kvp => kvp.Value.Select(diagnostic => diagnostic.Id).ToImmutableHashSet());
- static void LogDiagnosticLocations(IEnumerable diagnostics, string workspacePath, bool changesAreErrors, ILogger logger)
+ static void LogDiagnosticLocations(Solution solution, IEnumerable diagnostics, string workspacePath, bool changesAreErrors, ILogger logger, List formattedFiles)
{
var workspaceFolder = Path.GetDirectoryName(workspacePath);
@@ -81,11 +108,13 @@ static void LogDiagnosticLocations(IEnumerable diagnostics, string w
{
var message = diagnostic.GetMessage();
var filePath = diagnostic.Location.SourceTree?.FilePath;
+ var document = solution.GetDocument(diagnostic.Location.SourceTree);
var mappedLineSpan = diagnostic.Location.GetMappedLineSpan();
var changePosition = mappedLineSpan.StartLinePosition;
var formatMessage = $"{Path.GetRelativePath(workspaceFolder, filePath)}({changePosition.Line + 1},{changePosition.Character + 1}): {message}";
+ formattedFiles.Add(new FormattedFile(document!, new[] { new FileChange(changePosition, message) }));
if (changesAreErrors)
{
@@ -99,27 +128,34 @@ static void LogDiagnosticLocations(IEnumerable diagnostics, string w
}
}
- private async Task FixDiagnosticsAsync(Solution solution, ImmutableArray formattableDocuments, ILogger logger, CancellationToken cancellationToken)
+ private async Task FixDiagnosticsAsync(
+ Solution solution,
+ ImmutableArray<(DiagnosticAnalyzer Analyzer, CodeFixProvider? Fixer)> analyzersAndFixers,
+ ImmutableDictionary> projectDiagnostics,
+ ImmutableHashSet formattablePaths,
+ ILogger logger,
+ CancellationToken cancellationToken)
{
- var pairs = _finder.GetAnalyzersAndFixers();
- var paths = formattableDocuments.Select(id => solution.GetDocument(id)?.FilePath)
- .OfType().ToImmutableArray();
-
// we need to run each codefix iteratively so ensure that all diagnostics are found and fixed
- foreach (var (analyzer, codefix) in pairs)
+ foreach (var (analyzer, codefix) in analyzersAndFixers)
{
var result = new CodeAnalysisResult();
- await solution.Projects.ForEachAsync(async (project, token) =>
+ foreach (var project in solution.Projects)
{
- await _runner.RunCodeAnalysisAsync(result, analyzer, project, paths, logger, token);
- }, cancellationToken);
+ if (!projectDiagnostics.TryGetValue(project.Id, out var diagnosticIds) ||
+ !analyzer.SupportedDiagnostics.Any(diagnostic => diagnosticIds.Contains(diagnostic.Id)))
+ {
+ continue;
+ }
+
+ await _runner.RunCodeAnalysisAsync(result, analyzer, project, formattablePaths, logger, cancellationToken).ConfigureAwait(false);
+ }
var hasDiagnostics = result.Diagnostics.Any(kvp => kvp.Value.Count > 0);
- if (hasDiagnostics && codefix is object)
+ if (hasDiagnostics && codefix != null)
{
- logger.LogTrace($"Applying fixes for {codefix.GetType().Name}");
- solution = await _applier.ApplyCodeFixesAsync(solution, result, codefix, logger, cancellationToken);
- var changedSolution = await _applier.ApplyCodeFixesAsync(solution, result, codefix, logger, cancellationToken);
+ solution = await _applier.ApplyCodeFixesAsync(solution, result, codefix, logger, cancellationToken).ConfigureAwait(false);
+ var changedSolution = await _applier.ApplyCodeFixesAsync(solution, result, codefix, logger, cancellationToken).ConfigureAwait(false);
if (changedSolution.GetChanges(solution).Any())
{
solution = changedSolution;
diff --git a/src/Analyzers/AnalyzerOptionExtensions.cs b/src/Analyzers/AnalyzerOptionExtensions.cs
new file mode 100644
index 0000000000..157a558e5a
--- /dev/null
+++ b/src/Analyzers/AnalyzerOptionExtensions.cs
@@ -0,0 +1,118 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Linq;
+
+namespace Microsoft.CodeAnalysis.Diagnostics
+{
+ internal static class AnalyzerOptionsExtensions
+ {
+ private const string DotnetAnalyzerDiagnosticPrefix = "dotnet_analyzer_diagnostic";
+ private const string CategoryPrefix = "category";
+ private const string SeveritySuffix = "severity";
+
+ private const string DotnetAnalyzerDiagnosticSeverityKey = DotnetAnalyzerDiagnosticPrefix + "." + SeveritySuffix;
+
+ private static string GetCategoryBasedDotnetAnalyzerDiagnosticSeverityKey(string category)
+ => $"{DotnetAnalyzerDiagnosticPrefix}.{CategoryPrefix}-{category}.{SeveritySuffix}";
+
+ ///
+ /// Tries to get configured severity for the given
+ /// for the given from bulk configuration analyzer config options, i.e.
+ /// 'dotnet_analyzer_diagnostic.category-%RuleCategory%.severity = %severity%'
+ /// or
+ /// 'dotnet_analyzer_diagnostic.severity = %severity%'
+ ///
+ public static bool TryGetSeverityFromBulkConfiguration(
+ this AnalyzerOptions? analyzerOptions,
+ SyntaxTree tree,
+ Compilation compilation,
+ DiagnosticDescriptor descriptor,
+ out ReportDiagnostic severity)
+ {
+ // Analyzer bulk configuration does not apply to:
+ // 1. Disabled by default diagnostics
+ // 2. Compiler diagnostics
+ // 3. Non-configurable diagnostics
+ if (analyzerOptions == null ||
+ !descriptor.IsEnabledByDefault ||
+ descriptor.CustomTags.Any(tag => tag == WellKnownDiagnosticTags.Compiler || tag == WellKnownDiagnosticTags.NotConfigurable))
+ {
+ severity = default;
+ return false;
+ }
+
+ // If user has explicitly configured severity for this diagnostic ID, that should be respected and
+ // bulk configuration should not be applied.
+ // For example, 'dotnet_diagnostic.CA1000.severity = error'
+ if (compilation.Options.SpecificDiagnosticOptions.ContainsKey(descriptor.Id) ||
+ tree.DiagnosticOptions.ContainsKey(descriptor.Id))
+ {
+ severity = default;
+ return false;
+ }
+
+ var analyzerConfigOptions = analyzerOptions.AnalyzerConfigOptionsProvider.GetOptions(tree);
+
+ // If user has explicitly configured default severity for the diagnostic category, that should be respected.
+ // For example, 'dotnet_analyzer_diagnostic.category-security.severity = error'
+ var categoryBasedKey = GetCategoryBasedDotnetAnalyzerDiagnosticSeverityKey(descriptor.Category);
+ if (analyzerConfigOptions.TryGetValue(categoryBasedKey, out var value) &&
+ TryParseSeverity(value, out severity))
+ {
+ return true;
+ }
+
+ // Otherwise, if user has explicitly configured default severity for all analyzer diagnostics, that should be respected.
+ // For example, 'dotnet_analyzer_diagnostic.severity = error'
+ if (analyzerConfigOptions.TryGetValue(DotnetAnalyzerDiagnosticSeverityKey, out value) &&
+ TryParseSeverity(value, out severity))
+ {
+ return true;
+ }
+
+ severity = default;
+ return false;
+ }
+
+ internal static bool TryParseSeverity(string value, out ReportDiagnostic severity)
+ {
+ var comparer = StringComparer.OrdinalIgnoreCase;
+ if (comparer.Equals(value, "default"))
+ {
+ severity = ReportDiagnostic.Default;
+ return true;
+ }
+ else if (comparer.Equals(value, "error"))
+ {
+ severity = ReportDiagnostic.Error;
+ return true;
+ }
+ else if (comparer.Equals(value, "warning"))
+ {
+ severity = ReportDiagnostic.Warn;
+ return true;
+ }
+ else if (comparer.Equals(value, "suggestion"))
+ {
+ severity = ReportDiagnostic.Info;
+ return true;
+ }
+ else if (comparer.Equals(value, "silent") || comparer.Equals(value, "refactoring"))
+ {
+ severity = ReportDiagnostic.Hidden;
+ return true;
+ }
+ else if (comparer.Equals(value, "none"))
+ {
+ severity = ReportDiagnostic.Suppress;
+ return true;
+ }
+
+ severity = default;
+ return false;
+ }
+ }
+}
diff --git a/src/Analyzers/AnalyzerReferenceAnalyzerFinder.cs b/src/Analyzers/AnalyzerReferenceAnalyzerFinder.cs
new file mode 100644
index 0000000000..7e4e053f0a
--- /dev/null
+++ b/src/Analyzers/AnalyzerReferenceAnalyzerFinder.cs
@@ -0,0 +1,46 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information.
+
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Linq;
+using System.Reflection;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.Extensions.Logging;
+
+namespace Microsoft.CodeAnalysis.Tools.Analyzers
+{
+ internal class AnalyzerReferenceAnalyzerFinder : IAnalyzerFinder
+ {
+ public ImmutableArray<(DiagnosticAnalyzer Analyzer, CodeFixProvider? Fixer)> GetAnalyzersAndFixers(
+ Solution solution,
+ FormatOptions formatOptions,
+ ILogger logger)
+ {
+ if (!formatOptions.FixAnalyzers)
+ {
+ return ImmutableArray<(DiagnosticAnalyzer Analyzer, CodeFixProvider? Fixer)>.Empty;
+ }
+
+ var assemblies = solution.Projects
+ .SelectMany(project => project.AnalyzerReferences.Select(reference => reference.FullPath))
+ .Distinct()
+ .Select(path => Assembly.LoadFrom(path));
+
+ return AnalyzerFinderHelpers.LoadAnalyzersAndFixers(assemblies, logger);
+ }
+
+ public Task>> FilterBySeverityAsync(
+ IEnumerable projects,
+ ImmutableArray allAnalyzers,
+ ImmutableHashSet formattablePaths,
+ FormatOptions formatOptions,
+ CancellationToken cancellationToken)
+ {
+ return AnalyzerFinderHelpers.FilterBySeverityAsync(projects, allAnalyzers, formattablePaths, formatOptions.AnalyzerSeverity, cancellationToken);
+ }
+ }
+}
diff --git a/src/Analyzers/AnalyzerRunner.cs b/src/Analyzers/AnalyzerRunner.cs
index c3f3230829..b5419a9fef 100644
--- a/src/Analyzers/AnalyzerRunner.cs
+++ b/src/Analyzers/AnalyzerRunner.cs
@@ -1,6 +1,5 @@
// 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.Linq;
using System.Threading;
@@ -16,7 +15,7 @@ internal partial class AnalyzerRunner : IAnalyzerRunner
CodeAnalysisResult result,
DiagnosticAnalyzer analyzers,
Project project,
- ImmutableArray formattableDocumentPaths,
+ ImmutableHashSet formattableDocumentPaths,
ILogger logger,
CancellationToken cancellationToken)
=> RunCodeAnalysisAsync(result, ImmutableArray.Create(analyzers), project, formattableDocumentPaths, logger, cancellationToken);
@@ -25,28 +24,33 @@ internal partial class AnalyzerRunner : IAnalyzerRunner
CodeAnalysisResult result,
ImmutableArray analyzers,
Project project,
- ImmutableArray formattableDocumentPaths,
+ ImmutableHashSet formattableDocumentPaths,
ILogger logger,
CancellationToken cancellationToken)
{
- var compilation = await project.GetCompilationAsync(cancellationToken);
+ var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
if (compilation is null)
{
return;
}
- var analyzerCompilation = compilation.WithAnalyzers(
- analyzers,
- options: project.AnalyzerOptions,
- cancellationToken);
- var diagnostics = await analyzerCompilation.GetAnalyzerDiagnosticsAsync(cancellationToken);
+ var analyzerOptions = new CompilationWithAnalyzersOptions(
+ project.AnalyzerOptions,
+ onAnalyzerException: null,
+ concurrentAnalysis: true,
+ logAnalyzerExecutionTime: false,
+ reportSuppressedDiagnostics: false);
+ var analyzerCompilation = compilation.WithAnalyzers(analyzers, analyzerOptions);
+ var diagnostics = await analyzerCompilation.GetAnalyzerDiagnosticsAsync(cancellationToken).ConfigureAwait(false);
+
// filter diagnostics
foreach (var diagnostic in diagnostics)
{
if (!diagnostic.IsSuppressed &&
diagnostic.Severity >= DiagnosticSeverity.Warning &&
diagnostic.Location.IsInSource &&
- formattableDocumentPaths.Contains(diagnostic.Location.SourceTree?.FilePath, StringComparer.OrdinalIgnoreCase))
+ diagnostic.Location.SourceTree != null &&
+ formattableDocumentPaths.Contains(diagnostic.Location.SourceTree.FilePath))
{
result.AddDiagnostic(project, diagnostic);
}
diff --git a/src/Analyzers/CodeAnalysisResult.cs b/src/Analyzers/CodeAnalysisResult.cs
index 5090f5a649..71a9100480 100644
--- a/src/Analyzers/CodeAnalysisResult.cs
+++ b/src/Analyzers/CodeAnalysisResult.cs
@@ -2,24 +2,23 @@
using System.Collections.Generic;
-using NonBlocking;
-
namespace Microsoft.CodeAnalysis.Tools.Analyzers
{
internal class CodeAnalysisResult
{
- private readonly ConcurrentDictionary> _dictionary
- = new ConcurrentDictionary>();
+ private readonly Dictionary> _dictionary
+ = new Dictionary>();
internal void AddDiagnostic(Project project, Diagnostic diagnostic)
{
- _ = _dictionary.AddOrUpdate(project,
- addValueFactory: (key) => new List() { diagnostic },
- updateValueFactory: (key, list) =>
- {
- list.Add(diagnostic);
- return list;
- });
+ if (!_dictionary.ContainsKey(project))
+ {
+ _dictionary.Add(project, new List() { diagnostic });
+ }
+ else
+ {
+ _dictionary[project].Add(diagnostic);
+ }
}
public IReadOnlyDictionary> Diagnostics
diff --git a/src/Analyzers/Extensions.cs b/src/Analyzers/Extensions.cs
index c7976c9597..57bf2f384b 100644
--- a/src/Analyzers/Extensions.cs
+++ b/src/Analyzers/Extensions.cs
@@ -1,25 +1,200 @@
// 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.Generic;
+using System.Collections;
+using System.Collections.Immutable;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
+using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.CodeAnalysis.Options;
namespace Microsoft.CodeAnalysis.Tools.Analyzers
{
public static class Extensions
{
- public static Task ForEachAsync(this IEnumerable enumerable,
- Func action,
- CancellationToken cancellationToken = default)
- => Task.WhenAll(enumerable
- .AsParallel()
- .WithDegreeOfParallelism(Environment.ProcessorCount)
- .WithCancellation(cancellationToken)
- .Select(x => action(x, cancellationToken)));
+ private static Assembly MicrosoftCodeAnalysisFeaturesAssembly { get; }
+ private static Type IDEDiagnosticIdToOptionMappingHelperType { get; }
+ private static MethodInfo TryGetMappedOptionsMethod { get; }
+
+ static Extensions()
+ {
+ MicrosoftCodeAnalysisFeaturesAssembly = Assembly.Load(new AssemblyName("Microsoft.CodeAnalysis.Features"));
+ IDEDiagnosticIdToOptionMappingHelperType = MicrosoftCodeAnalysisFeaturesAssembly.GetType("Microsoft.CodeAnalysis.Diagnostics.IDEDiagnosticIdToOptionMappingHelper");
+ TryGetMappedOptionsMethod = IDEDiagnosticIdToOptionMappingHelperType.GetMethod("TryGetMappedOptions", BindingFlags.Static | BindingFlags.Public);
+ }
public static bool Any(this SolutionChanges solutionChanges)
- => solutionChanges.GetProjectChanges().Any(x => x.GetChangedDocuments().Any());
+ => solutionChanges.GetProjectChanges().Any(x => x.GetChangedDocuments().Any());
+
+ public static bool TryCreateInstance(this Type type, [NotNullWhen(returnValue: true)] out T? instance) where T : class
+ {
+ try
+ {
+ var defaultCtor = type.GetConstructor(
+ BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance,
+ binder: null,
+ new Type[] { },
+ modifiers: null);
+
+ instance = defaultCtor != null
+ ? (T)Activator.CreateInstance(
+ type,
+ BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance,
+ binder: null,
+ args: null,
+ culture: null)
+ : null;
+
+ return instance != null;
+ }
+ catch (Exception ex)
+ {
+ throw new InvalidOperationException($"Failed to create instrance of {type.FullName} in {type.AssemblyQualifiedName}.", ex);
+ }
+ }
+
+ ///
+ /// Get the highest possible severity for any formattable document in the project.
+ ///
+ public static async Task GetSeverityAsync(
+ this DiagnosticAnalyzer analyzer,
+ Project project,
+ ImmutableHashSet formattablePaths,
+ CancellationToken cancellationToken)
+ {
+ var severity = DiagnosticSeverity.Hidden;
+ var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
+ if (compilation is null)
+ {
+ return severity;
+ }
+
+ foreach (var document in project.Documents)
+ {
+ // Is the document formattable?
+ if (document.FilePath is null || !formattablePaths.Contains(document.FilePath))
+ {
+ continue;
+ }
+
+ var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);
+
+ var documentSeverity = analyzer.GetSeverity(document, project.AnalyzerOptions, options, compilation);
+ if (documentSeverity > severity)
+ {
+ severity = documentSeverity;
+ }
+ }
+
+ return severity;
+ }
+
+ private static DiagnosticSeverity GetSeverity(
+ this DiagnosticAnalyzer analyzer,
+ Document document,
+ AnalyzerOptions? analyzerOptions,
+ OptionSet options,
+ Compilation compilation)
+ {
+ var severity = DiagnosticSeverity.Hidden;
+
+ if (!document.TryGetSyntaxTree(out var tree))
+ {
+ return severity;
+ }
+
+ foreach (var descriptor in analyzer.SupportedDiagnostics)
+ {
+ if (severity == DiagnosticSeverity.Error)
+ {
+ break;
+ }
+
+ if (analyzerOptions.TryGetSeverityFromBulkConfiguration(tree, compilation, descriptor, out var reportDiagnostic))
+ {
+ var configuredSeverity = ToSeverity(reportDiagnostic);
+ if (configuredSeverity > severity)
+ {
+ severity = configuredSeverity;
+ }
+ continue;
+ }
+
+ if (TryGetSeverityFromCodeStyleOption(descriptor, compilation, options, out var codeStyleSeverity))
+ {
+ if (codeStyleSeverity > severity)
+ {
+ severity = codeStyleSeverity;
+ }
+ continue;
+ }
+
+ if (descriptor.DefaultSeverity > severity)
+ {
+ severity = descriptor.DefaultSeverity;
+ }
+ }
+
+ return severity;
+
+ static DiagnosticSeverity ToSeverity(ReportDiagnostic reportDiagnostic)
+ {
+ return reportDiagnostic switch
+ {
+ ReportDiagnostic.Error => DiagnosticSeverity.Error,
+ ReportDiagnostic.Warn => DiagnosticSeverity.Warning,
+ ReportDiagnostic.Info => DiagnosticSeverity.Info,
+ _ => DiagnosticSeverity.Hidden
+ };
+ }
+
+ static bool TryGetSeverityFromCodeStyleOption(
+ DiagnosticDescriptor descriptor,
+ Compilation compilation,
+ OptionSet options,
+ out DiagnosticSeverity severity)
+ {
+ severity = DiagnosticSeverity.Hidden;
+
+ var parameters = new object?[] { descriptor.Id, compilation.Language, null };
+ var result = (bool)TryGetMappedOptionsMethod.Invoke(null, parameters);
+
+ if (!result)
+ {
+ return false;
+ }
+
+ var codeStyleOptions = (IEnumerable)parameters[2]!;
+ foreach (var codeStyleOptionObj in codeStyleOptions)
+ {
+ var codeStyleOption = (IOption)codeStyleOptionObj;
+ var option = options.GetOption(new OptionKey(codeStyleOption, codeStyleOption.IsPerLanguage ? compilation.Language : null));
+ if (option is null)
+ {
+ continue;
+ }
+
+ var notificationProperty = option.GetType().GetProperty("Notification");
+ if (notificationProperty is null)
+ {
+ continue;
+ }
+
+ var notification = notificationProperty.GetValue(option);
+ var reportDiagnostic = (ReportDiagnostic)notification.GetType().GetProperty("Severity").GetValue(notification);
+ var codeStyleSeverity = ToSeverity(reportDiagnostic);
+
+ if (codeStyleSeverity > severity)
+ {
+ severity = codeStyleSeverity;
+ }
+ }
+
+ return true;
+ }
+ }
}
}
diff --git a/src/Analyzers/Interfaces/IAnalyzerFinder.cs b/src/Analyzers/Interfaces/IAnalyzerFinder.cs
index 81e5835d95..fe6a7f3bc6 100644
--- a/src/Analyzers/Interfaces/IAnalyzerFinder.cs
+++ b/src/Analyzers/Interfaces/IAnalyzerFinder.cs
@@ -1,13 +1,27 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information.
+using System.Collections.Generic;
using System.Collections.Immutable;
+using System.Threading;
+using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.Extensions.Logging;
namespace Microsoft.CodeAnalysis.Tools.Analyzers
{
interface IAnalyzerFinder
{
- ImmutableArray<(DiagnosticAnalyzer Analyzer, CodeFixProvider? Fixer)> GetAnalyzersAndFixers();
+ ImmutableArray<(DiagnosticAnalyzer Analyzer, CodeFixProvider? Fixer)> GetAnalyzersAndFixers(
+ Solution solution,
+ FormatOptions formatOptions,
+ ILogger logger);
+
+ Task>> FilterBySeverityAsync(
+ IEnumerable projects,
+ ImmutableArray allAnalyzers,
+ ImmutableHashSet formattablePaths,
+ FormatOptions formatOptions,
+ CancellationToken cancellationToken);
}
}
diff --git a/src/Analyzers/Interfaces/IAnalyzerRunner.cs b/src/Analyzers/Interfaces/IAnalyzerRunner.cs
index 68cf23c402..2d264ac134 100644
--- a/src/Analyzers/Interfaces/IAnalyzerRunner.cs
+++ b/src/Analyzers/Interfaces/IAnalyzerRunner.cs
@@ -14,7 +14,7 @@ interface IAnalyzerRunner
CodeAnalysisResult result,
DiagnosticAnalyzer analyzers,
Project project,
- ImmutableArray formattableDocumentPaths,
+ ImmutableHashSet formattableDocumentPaths,
ILogger logger,
CancellationToken cancellationToken);
@@ -22,7 +22,7 @@ interface IAnalyzerRunner
CodeAnalysisResult result,
ImmutableArray analyzers,
Project project,
- ImmutableArray formattableDocumentPaths,
+ ImmutableHashSet formattableDocumentPaths,
ILogger logger,
CancellationToken cancellationToken);
}
diff --git a/src/Analyzers/RoslynCodeStyleAnalyzerFinder.cs b/src/Analyzers/RoslynCodeStyleAnalyzerFinder.cs
index 2ebf30efc0..fea651ba5f 100644
--- a/src/Analyzers/RoslynCodeStyleAnalyzerFinder.cs
+++ b/src/Analyzers/RoslynCodeStyleAnalyzerFinder.cs
@@ -1,59 +1,52 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information.
+using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using System.Reflection;
+using System.Threading;
+using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.Extensions.Logging;
namespace Microsoft.CodeAnalysis.Tools.Analyzers
{
internal class RoslynCodeStyleAnalyzerFinder : IAnalyzerFinder
{
- private readonly static string s_executingPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
+ private static readonly string s_executingPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
private readonly string _featuresCSharpPath = Path.Combine(s_executingPath, "Microsoft.CodeAnalysis.CSharp.Features.dll");
private readonly string _featuresVisualBasicPath = Path.Combine(s_executingPath, "Microsoft.CodeAnalysis.VisualBasic.Features.dll");
- public ImmutableArray<(DiagnosticAnalyzer Analyzer, CodeFixProvider? Fixer)> GetAnalyzersAndFixers()
+ public ImmutableArray<(DiagnosticAnalyzer Analyzer, CodeFixProvider? Fixer)> GetAnalyzersAndFixers(
+ Solution solution,
+ FormatOptions options,
+ ILogger logger)
{
- var analyzers = FindAllAnalyzers();
-
- // TODO: Match CodeFixes to the analyzers that produce the diagnostic ids they fix.
- return analyzers.Select(analyzer => (analyzer, (CodeFixProvider?)null)).ToImmutableArray();
- }
-
- private ImmutableArray FindAllAnalyzers()
- {
- var featuresCSharpReference = new AnalyzerFileReference(_featuresCSharpPath, AssemblyLoader.Instance);
- var csharpAnalyzers = featuresCSharpReference.GetAnalyzers(LanguageNames.CSharp);
-
- var featuresVisualBasicReference = new AnalyzerFileReference(_featuresVisualBasicPath, AssemblyLoader.Instance);
- var visualBasicAnalyzers = featuresVisualBasicReference.GetAnalyzers(LanguageNames.VisualBasic);
+ if (!options.FixCodeStyle)
+ {
+ return ImmutableArray<(DiagnosticAnalyzer Analyzer, CodeFixProvider? Fixer)>.Empty;
+ }
- var allAnalyzers = csharpAnalyzers.Concat(visualBasicAnalyzers).ToImmutableArray();
- return allAnalyzers;
- }
+ var assemblies = new[]
+ {
+ _featuresCSharpPath,
+ _featuresVisualBasicPath
+ }.Select(path => Assembly.LoadFrom(path));
- private ImmutableArray FindAllCodeFixesAsync()
- {
- // TODO: Discover CodeFixes
- return ImmutableArray.Empty;
+ return AnalyzerFinderHelpers.LoadAnalyzersAndFixers(assemblies, logger);
}
- internal class AssemblyLoader : IAnalyzerAssemblyLoader
+ public Task>> FilterBySeverityAsync(
+ IEnumerable projects,
+ ImmutableArray allAnalyzers,
+ ImmutableHashSet formattablePaths,
+ FormatOptions formatOptions,
+ CancellationToken cancellationToken)
{
- public static AssemblyLoader Instance = new AssemblyLoader();
-
- public void AddDependencyLocation(string fullPath)
- {
- }
-
- public Assembly LoadFromPath(string fullPath)
- {
- return Assembly.LoadFrom(fullPath);
- }
+ return AnalyzerFinderHelpers.FilterBySeverityAsync(projects, allAnalyzers, formattablePaths, formatOptions.CodeStyleSeverity, cancellationToken);
}
}
}
diff --git a/src/Analyzers/SolutionCodeFixApplier.cs b/src/Analyzers/SolutionCodeFixApplier.cs
index 55652d0685..f8a960cf4c 100644
--- a/src/Analyzers/SolutionCodeFixApplier.cs
+++ b/src/Analyzers/SolutionCodeFixApplier.cs
@@ -21,10 +21,13 @@ internal class SolutionCodeFixApplier : ICodeFixApplier
ILogger logger,
CancellationToken cancellationToken)
{
+ var diagnosticId = result.Diagnostics.FirstOrDefault().Value.FirstOrDefault()?.Id;
+
var fixAllProvider = codeFix.GetFixAllProvider();
- if (!fixAllProvider.GetSupportedFixAllScopes().Contains(FixAllScope.Solution))
+ if (fixAllProvider?.GetSupportedFixAllScopes()?.Contains(FixAllScope.Solution) != true)
{
- throw new InvalidOperationException($"Code fix {codeFix.GetType()} doesn't support Fix All in Solution");
+ logger.LogWarning($"Unable to fix {diagnosticId}. Code fix {codeFix.GetType().Name} doesn't support Fix All in Solution.");
+ return solution;
}
var project = solution.Projects.FirstOrDefault();
@@ -42,15 +45,25 @@ internal class SolutionCodeFixApplier : ICodeFixApplier
fixAllDiagnosticProvider: new DiagnosticProvider(result),
cancellationToken: cancellationToken);
- var action = await fixAllProvider.GetFixAsync(fixAllContext);
- var operations = await (action?.GetOperationsAsync(cancellationToken) ?? Task.FromResult(ImmutableArray.Empty));
- var applyChangesOperation = operations.OfType().SingleOrDefault();
- return applyChangesOperation?.ChangedSolution ?? solution;
+ try
+ {
+ var action = await fixAllProvider.GetFixAsync(fixAllContext).ConfigureAwait(false);
+ var operations = action != null
+ ? await action.GetOperationsAsync(cancellationToken).ConfigureAwait(false)
+ : ImmutableArray.Empty;
+ var applyChangesOperation = operations.OfType().SingleOrDefault();
+ return applyChangesOperation?.ChangedSolution ?? solution;
+ }
+ catch (Exception ex)
+ {
+ logger.LogWarning($"Failed to apply code fix {codeFix?.GetType().Name} for {diagnosticId}: {ex.Message}");
+ return solution;
+ }
}
private class DiagnosticProvider : FixAllContext.DiagnosticProvider
{
- private static readonly Task> EmptyDignosticResult = Task.FromResult(Enumerable.Empty());
+ private static Task> EmptyDignosticResult => Task.FromResult(Enumerable.Empty());
private readonly IReadOnlyDictionary> _diagnosticsByProject;
internal DiagnosticProvider(CodeAnalysisResult analysisResult)
diff --git a/src/CodeFormatter.cs b/src/CodeFormatter.cs
index a5308a0cb1..a186a8af53 100644
--- a/src/CodeFormatter.cs
+++ b/src/CodeFormatter.cs
@@ -29,27 +29,27 @@ internal static class CodeFormatter
new EndOfLineFormatter(),
new CharsetFormatter(),
new ImportsFormatter(),
- new AnalyzerFormatter(new RoslynCodeStyleAnalyzerFinder(), new AnalyzerRunner(), new SolutionCodeFixApplier()),
+ new AnalyzerFormatter("Code Style", new RoslynCodeStyleAnalyzerFinder(), new AnalyzerRunner(), new SolutionCodeFixApplier()),
+ new AnalyzerFormatter("Analyzer Reference", new AnalyzerReferenceAnalyzerFinder(), new AnalyzerRunner(), new SolutionCodeFixApplier()),
}.ToImmutableArray();
public static async Task FormatWorkspaceAsync(
- FormatOptions options,
+ FormatOptions formatOptions,
ILogger logger,
CancellationToken cancellationToken,
bool createBinaryLog = false)
{
- var (workspaceFilePath, workspaceType, logLevel, _, saveFormattedFiles, _, fileMatcher, reportPath, includeGeneratedFiles) = options;
- var logWorkspaceWarnings = logLevel == LogLevel.Trace;
+ var logWorkspaceWarnings = formatOptions.LogLevel == LogLevel.Trace;
- logger.LogInformation(string.Format(Resources.Formatting_code_files_in_workspace_0, workspaceFilePath));
+ logger.LogInformation(string.Format(Resources.Formatting_code_files_in_workspace_0, formatOptions.WorkspaceFilePath));
logger.LogTrace(Resources.Loading_workspace);
var workspaceStopwatch = Stopwatch.StartNew();
- using var workspace = workspaceType == WorkspaceType.Folder
- ? await OpenFolderWorkspaceAsync(workspaceFilePath, fileMatcher, cancellationToken).ConfigureAwait(false)
- : await OpenMSBuildWorkspaceAsync(workspaceFilePath, workspaceType, createBinaryLog, logWorkspaceWarnings, logger, cancellationToken).ConfigureAwait(false);
+ using var workspace = formatOptions.WorkspaceType == WorkspaceType.Folder
+ ? await OpenFolderWorkspaceAsync(formatOptions.WorkspaceFilePath, formatOptions.FileMatcher, cancellationToken).ConfigureAwait(false)
+ : await OpenMSBuildWorkspaceAsync(formatOptions.WorkspaceFilePath, formatOptions.WorkspaceType, createBinaryLog, logWorkspaceWarnings, logger, cancellationToken).ConfigureAwait(false);
if (workspace is null)
{
@@ -59,13 +59,13 @@ internal static class CodeFormatter
var loadWorkspaceMS = workspaceStopwatch.ElapsedMilliseconds;
logger.LogTrace(Resources.Complete_in_0_ms, workspaceStopwatch.ElapsedMilliseconds);
- var projectPath = workspaceType == WorkspaceType.Project ? workspaceFilePath : string.Empty;
+ var projectPath = formatOptions.WorkspaceType == WorkspaceType.Project ? formatOptions.WorkspaceFilePath : string.Empty;
var solution = workspace.CurrentSolution;
logger.LogTrace(Resources.Determining_formattable_files);
var (fileCount, formatableFiles) = await DetermineFormattableFilesAsync(
- solution, projectPath, fileMatcher, includeGeneratedFiles, logger, cancellationToken).ConfigureAwait(false);
+ solution, projectPath, formatOptions.FileMatcher, formatOptions.IncludeGeneratedFiles, logger, cancellationToken).ConfigureAwait(false);
var determineFilesMS = workspaceStopwatch.ElapsedMilliseconds - loadWorkspaceMS;
logger.LogTrace(Resources.Complete_in_0_ms, determineFilesMS);
@@ -74,7 +74,7 @@ internal static class CodeFormatter
var formattedFiles = new List();
var formattedSolution = await RunCodeFormattersAsync(
- solution, formatableFiles, options, logger, formattedFiles, cancellationToken).ConfigureAwait(false);
+ solution, formatableFiles, formatOptions, logger, formattedFiles, cancellationToken).ConfigureAwait(false);
var formatterRanMS = workspaceStopwatch.ElapsedMilliseconds - loadWorkspaceMS - determineFilesMS;
logger.LogTrace(Resources.Complete_in_0_ms, formatterRanMS);
@@ -88,7 +88,9 @@ internal static class CodeFormatter
{
var changedDocument = solution.GetDocument(changedDocumentId);
if (changedDocument?.FilePath is null)
+ {
continue;
+ }
logger.LogInformation(Resources.Formatted_code_file_0, changedDocument.FilePath);
filesFormatted++;
@@ -97,15 +99,15 @@ internal static class CodeFormatter
var exitCode = 0;
- if (saveFormattedFiles && !workspace.TryApplyChanges(formattedSolution))
+ if (formatOptions.SaveFormattedFiles && !workspace.TryApplyChanges(formattedSolution))
{
logger.LogError(Resources.Failed_to_save_formatting_changes);
exitCode = 1;
}
- if (exitCode == 0 && !string.IsNullOrWhiteSpace(reportPath))
+ if (exitCode == 0 && !string.IsNullOrWhiteSpace(formatOptions.ReportPath))
{
- var reportFilePath = GetReportFilePath(reportPath!); // IsNullOrEmpty is not annotated on .NET Core 2.1
+ var reportFilePath = GetReportFilePath(formatOptions.ReportPath!); // IsNullOrEmpty is not annotated on .NET Core 2.1
var reportFolderPath = Path.GetDirectoryName(reportFilePath);
if (!Directory.Exists(reportFolderPath))
@@ -236,7 +238,7 @@ static void LogWorkspaceDiagnostics(ILogger logger, bool logWorkspaceWarnings, I
private static async Task RunCodeFormattersAsync(
Solution solution,
ImmutableArray formattableDocuments,
- FormatOptions options,
+ FormatOptions formatOptions,
ILogger logger,
List formattedFiles,
CancellationToken cancellationToken)
@@ -245,12 +247,7 @@ static void LogWorkspaceDiagnostics(ILogger logger, bool logWorkspaceWarnings, I
foreach (var codeFormatter in s_codeFormatters)
{
- if (!options.FormatType.HasFlag(codeFormatter.FormatType))
- {
- continue;
- }
-
- formattedSolution = await codeFormatter.FormatAsync(formattedSolution, formattableDocuments, options, logger, formattedFiles, cancellationToken).ConfigureAwait(false);
+ formattedSolution = await codeFormatter.FormatAsync(formattedSolution, formattableDocuments, formatOptions, logger, formattedFiles, cancellationToken).ConfigureAwait(false);
}
return formattedSolution;
@@ -326,7 +323,7 @@ await GeneratedCodeUtilities.IsGeneratedCodeAsync(syntaxTree, cancellationToken)
// Track files covered by an editorconfig separately from those not covered.
var analyzerConfigOptions = document.Project.AnalyzerOptions.AnalyzerConfigOptionsProvider.GetOptions(syntaxTree);
- if (analyzerConfigOptions is object)
+ if (analyzerConfigOptions != null)
{
documentsCoveredByEditorConfig.Add(document.Id);
}
diff --git a/src/FileChange.cs b/src/FileChange.cs
index d149ee2240..6105b79116 100644
--- a/src/FileChange.cs
+++ b/src/FileChange.cs
@@ -1,4 +1,6 @@
-using Microsoft.CodeAnalysis.Text;
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information.
+
+using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.Tools
{
diff --git a/src/FixSeverity.cs b/src/FixSeverity.cs
new file mode 100644
index 0000000000..47b719bda0
--- /dev/null
+++ b/src/FixSeverity.cs
@@ -0,0 +1,11 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information.
+
+namespace Microsoft.CodeAnalysis.Tools
+{
+ public static class FixSeverity
+ {
+ public const string Error = "error";
+ public const string Warn = "warn";
+ public const string Info = "info";
+ }
+}
diff --git a/src/FormatCommand.cs b/src/FormatCommand.cs
index de44d51e7e..9ba8a9f0cd 100644
--- a/src/FormatCommand.cs
+++ b/src/FormatCommand.cs
@@ -29,7 +29,11 @@ internal static RootCommand CreateCommandLineOptions()
},
new Option(new[] { "--fix-style", "-fs" }, Resources.Run_code_style_analyzer_and_apply_fixes)
{
- Argument = new Argument()
+ Argument = new Argument("severity") { Arity = ArgumentArity.ZeroOrOne }
+ },
+ new Option(new[] { "--fix-analyzers", "-fa" }, Resources.Run_code_style_analyzer_and_apply_fixes)
+ {
+ Argument = new Argument("severity") { Arity = ArgumentArity.ZeroOrOne }
},
new Option(new[] { "--include", "--files" }, Resources.A_list_of_relative_file_or_folder_paths_to_include_in_formatting_All_files_are_formatted_if_empty)
{
diff --git a/src/FormatOptions.cs b/src/FormatOptions.cs
index 07a14db452..597fe4547b 100644
--- a/src/FormatOptions.cs
+++ b/src/FormatOptions.cs
@@ -10,7 +10,10 @@ internal class FormatOptions
public string WorkspaceFilePath { get; }
public WorkspaceType WorkspaceType { get; }
public LogLevel LogLevel { get; }
- public FormatType FormatType { get; }
+ public bool FixCodeStyle { get; }
+ public DiagnosticSeverity CodeStyleSeverity { get; }
+ public bool FixAnalyzers { get; }
+ public DiagnosticSeverity AnalyzerSeverity { get; }
public bool SaveFormattedFiles { get; }
public bool ChangesAreErrors { get; }
public Matcher FileMatcher { get; }
@@ -21,7 +24,10 @@ internal class FormatOptions
string workspaceFilePath,
WorkspaceType workspaceType,
LogLevel logLevel,
- FormatType formatType,
+ bool fixCodeStyle,
+ DiagnosticSeverity codeStyleSeverity,
+ bool fixAnalyzers,
+ DiagnosticSeverity analyerSeverity,
bool saveFormattedFiles,
bool changesAreErrors,
Matcher fileMatcher,
@@ -31,7 +37,10 @@ internal class FormatOptions
WorkspaceFilePath = workspaceFilePath;
WorkspaceType = workspaceType;
LogLevel = logLevel;
- FormatType = formatType;
+ FixCodeStyle = fixCodeStyle;
+ CodeStyleSeverity = codeStyleSeverity;
+ FixAnalyzers = fixAnalyzers;
+ AnalyzerSeverity = analyerSeverity;
SaveFormattedFiles = saveFormattedFiles;
ChangesAreErrors = changesAreErrors;
FileMatcher = fileMatcher;
@@ -43,7 +52,10 @@ internal class FormatOptions
out string workspaceFilePath,
out WorkspaceType workspaceType,
out LogLevel logLevel,
- out FormatType formatType,
+ out bool fixCodeStyle,
+ out DiagnosticSeverity codeStyleSeverity,
+ out bool fixAnalyzers,
+ out DiagnosticSeverity analyerSeverity,
out bool saveFormattedFiles,
out bool changesAreErrors,
out Matcher fileMatcher,
@@ -53,7 +65,10 @@ internal class FormatOptions
workspaceFilePath = WorkspaceFilePath;
workspaceType = WorkspaceType;
logLevel = LogLevel;
- formatType = FormatType;
+ fixCodeStyle = FixCodeStyle;
+ codeStyleSeverity = CodeStyleSeverity;
+ fixAnalyzers = FixAnalyzers;
+ analyerSeverity = AnalyzerSeverity;
saveFormattedFiles = SaveFormattedFiles;
changesAreErrors = ChangesAreErrors;
fileMatcher = FileMatcher;
diff --git a/src/FormatType.cs b/src/FormatType.cs
deleted file mode 100644
index b8638ab705..0000000000
--- a/src/FormatType.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information.
-
-using System;
-
-[Flags]
-public enum FormatType
-{
- None = 0,
- Whitespace = 1,
- CodeStyle = 2,
- All = Whitespace | CodeStyle
-}
diff --git a/src/Formatters/CharsetFormatter.cs b/src/Formatters/CharsetFormatter.cs
index 45eaad2574..c8f509e06e 100644
--- a/src/Formatters/CharsetFormatter.cs
+++ b/src/Formatters/CharsetFormatter.cs
@@ -15,7 +15,6 @@ namespace Microsoft.CodeAnalysis.Tools.Formatters
{
internal sealed class CharsetFormatter : DocumentFormatter
{
- public override FormatType FormatType => FormatType.Whitespace;
protected override string FormatWarningDescription => Resources.Fix_file_encoding;
private static Encoding Utf8 => new UTF8Encoding(encoderShouldEmitUTF8Identifier: false);
@@ -70,7 +69,7 @@ private static byte[] GetEncodedBytes(string text, Encoding encoding)
private static bool TryGetCharset(AnalyzerConfigOptions? analyzerConfigOptions, [NotNullWhen(true)] out Encoding? encoding)
{
- if (analyzerConfigOptions is object &&
+ if (analyzerConfigOptions != null &&
analyzerConfigOptions.TryGetValue("charset", out var charsetOption))
{
encoding = GetCharset(charsetOption);
diff --git a/src/Formatters/DocumentFormatter.cs b/src/Formatters/DocumentFormatter.cs
index a313056b22..ae32adbf42 100644
--- a/src/Formatters/DocumentFormatter.cs
+++ b/src/Formatters/DocumentFormatter.cs
@@ -18,7 +18,6 @@ namespace Microsoft.CodeAnalysis.Tools.Formatters
///
internal abstract class DocumentFormatter : ICodeFormatter
{
- public abstract FormatType FormatType { get; }
protected abstract string FormatWarningDescription { get; }
///
diff --git a/src/Formatters/EndOfLineFormatter.cs b/src/Formatters/EndOfLineFormatter.cs
index 69a1407e73..160077bce1 100644
--- a/src/Formatters/EndOfLineFormatter.cs
+++ b/src/Formatters/EndOfLineFormatter.cs
@@ -13,7 +13,6 @@ namespace Microsoft.CodeAnalysis.Tools.Formatters
{
internal sealed class EndOfLineFormatter : DocumentFormatter
{
- public override FormatType FormatType => FormatType.Whitespace;
protected override string FormatWarningDescription => Resources.Fix_end_of_line_marker;
internal override Task FormatFileAsync(
@@ -61,7 +60,7 @@ internal sealed class EndOfLineFormatter : DocumentFormatter
public static bool TryGetEndOfLine(AnalyzerConfigOptions? analyzerConfigOptions, [NotNullWhen(true)] out string? endOfLine)
{
- if (analyzerConfigOptions is object &&
+ if (analyzerConfigOptions != null &&
analyzerConfigOptions.TryGetValue("end_of_line", out var endOfLineOption))
{
endOfLine = GetEndOfLine(endOfLineOption);
diff --git a/src/Formatters/FinalNewlineFormatter.cs b/src/Formatters/FinalNewlineFormatter.cs
index 16ba76488a..10e8664e17 100644
--- a/src/Formatters/FinalNewlineFormatter.cs
+++ b/src/Formatters/FinalNewlineFormatter.cs
@@ -13,7 +13,6 @@ namespace Microsoft.CodeAnalysis.Tools.Formatters
{
internal sealed class FinalNewlineFormatter : DocumentFormatter
{
- public override FormatType FormatType => FormatType.Whitespace;
protected override string FormatWarningDescription => Resources.Fix_final_newline;
internal override async Task FormatFileAsync(
@@ -29,7 +28,7 @@ internal sealed class FinalNewlineFormatter : DocumentFormatter
!analyzerConfigOptions.TryGetValue("insert_final_newline", out var insertFinalNewlineValue) ||
!bool.TryParse(insertFinalNewlineValue, out var insertFinalNewline))
{
- return await document.GetTextAsync(cancellationToken);
+ return await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
}
if (!EndOfLineFormatter.TryGetEndOfLine(analyzerConfigOptions, out var endOfLine))
diff --git a/src/Formatters/ICodeFormatter.cs b/src/Formatters/ICodeFormatter.cs
index 06bc7beff5..fa0b67db69 100644
--- a/src/Formatters/ICodeFormatter.cs
+++ b/src/Formatters/ICodeFormatter.cs
@@ -10,8 +10,6 @@ namespace Microsoft.CodeAnalysis.Tools.Formatters
{
internal interface ICodeFormatter
{
- FormatType FormatType { get; }
-
///
/// Applies formatting and returns a formatted .
///
diff --git a/src/Formatters/ImportsFormatter.cs b/src/Formatters/ImportsFormatter.cs
index 149c61c9a3..76ab78af34 100644
--- a/src/Formatters/ImportsFormatter.cs
+++ b/src/Formatters/ImportsFormatter.cs
@@ -17,7 +17,6 @@ namespace Microsoft.CodeAnalysis.Tools.Formatters
///
internal sealed class ImportsFormatter : DocumentFormatter
{
- public override FormatType FormatType => FormatType.Whitespace;
protected override string FormatWarningDescription => Resources.Fix_imports_ordering;
private readonly DocumentFormatter _endOfLineFormatter = new EndOfLineFormatter();
@@ -32,7 +31,7 @@ internal sealed class ImportsFormatter : DocumentFormatter
{
try
{
- var organizedDocument = await Formatter.OrganizeImportsAsync(document, cancellationToken);
+ var organizedDocument = await Formatter.OrganizeImportsAsync(document, cancellationToken).ConfigureAwait(false);
var isSameVersion = await IsSameDocumentAndVersionAsync(document, organizedDocument, cancellationToken).ConfigureAwait(false);
if (isSameVersion)
@@ -42,8 +41,8 @@ internal sealed class ImportsFormatter : DocumentFormatter
// Because the Formatter does not abide the `end_of_line` option we have to fix up the ends of the organized lines.
// See https://github.com/dotnet/roslyn/issues/44136
- var organizedSourceText = await organizedDocument.GetTextAsync(cancellationToken);
- return await _endOfLineFormatter.FormatFileAsync(organizedDocument, organizedSourceText, optionSet, analyzerConfigOptions, formatOptions, logger, cancellationToken);
+ var organizedSourceText = await organizedDocument.GetTextAsync(cancellationToken).ConfigureAwait(false);
+ return await _endOfLineFormatter.FormatFileAsync(organizedDocument, organizedSourceText, optionSet, analyzerConfigOptions, formatOptions, logger, cancellationToken).ConfigureAwait(false);
}
catch (InsufficientExecutionStackException)
{
@@ -66,8 +65,8 @@ private static async Task IsSameDocumentAndVersionAsync(Document a, Docume
return false;
}
- var aVersion = await a.GetTextVersionAsync(cancellationToken);
- var bVersion = await b.GetTextVersionAsync(cancellationToken);
+ var aVersion = await a.GetTextVersionAsync(cancellationToken).ConfigureAwait(false);
+ var bVersion = await b.GetTextVersionAsync(cancellationToken).ConfigureAwait(false);
return aVersion == bVersion;
}
diff --git a/src/Formatters/WhitespaceFormatter.cs b/src/Formatters/WhitespaceFormatter.cs
index 7fe18550bd..382feb9615 100644
--- a/src/Formatters/WhitespaceFormatter.cs
+++ b/src/Formatters/WhitespaceFormatter.cs
@@ -15,7 +15,6 @@ namespace Microsoft.CodeAnalysis.Tools.Formatters
///
internal sealed class WhitespaceFormatter : DocumentFormatter
{
- public override FormatType FormatType => FormatType.Whitespace;
protected override string FormatWarningDescription => Resources.Fix_whitespace_formatting;
internal override async Task FormatFileAsync(
@@ -29,11 +28,11 @@ internal sealed class WhitespaceFormatter : DocumentFormatter
{
if (formatOptions.SaveFormattedFiles)
{
- return await GetFormattedDocument(document, optionSet, cancellationToken);
+ return await GetFormattedDocument(document, optionSet, cancellationToken).ConfigureAwait(false);
}
else
{
- return await GetFormattedDocumentWithDetailedChanges(document, sourceText, optionSet, cancellationToken);
+ return await GetFormattedDocumentWithDetailedChanges(document, sourceText, optionSet, cancellationToken).ConfigureAwait(false);
}
}
@@ -51,7 +50,7 @@ private static async Task GetFormattedDocument(Document document, Op
///
private static async Task GetFormattedDocumentWithDetailedChanges(Document document, SourceText sourceText, OptionSet optionSet, CancellationToken cancellationToken)
{
- var root = await document.GetSyntaxRootAsync(cancellationToken);
+ var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var formattingTextChanges = Formatter.GetFormattedTextChanges(root, document.Project.Solution.Workspace, optionSet, cancellationToken);
return sourceText.WithChanges(formattingTextChanges);
diff --git a/src/Program.cs b/src/Program.cs
index 8ed483caca..4c80898b5b 100644
--- a/src/Program.cs
+++ b/src/Program.cs
@@ -43,7 +43,8 @@ private static async Task Main(string[] args)
string? project,
string? folder,
string? workspace,
- bool fixStyle,
+ string? fixStyle,
+ string? fixAnalyzers,
string? verbosity,
bool check,
string[] include,
@@ -154,7 +155,10 @@ private static async Task Main(string[] args)
workspacePath,
workspaceType,
logLevel,
- fixStyle ? FormatType.All : FormatType.Whitespace,
+ fixCodeStyle: s_parseResult.WasOptionUsed("--fix-style", "-fs"),
+ codeStyleSeverity: GetSeverity(fixStyle ?? FixSeverity.Error),
+ fixAnalyzers: s_parseResult.WasOptionUsed("--fix-analyzers", "-fa"),
+ analyerSeverity: GetSeverity(fixAnalyzers ?? FixSeverity.Error),
saveFormattedFiles: !check,
changesAreErrors: check,
fileMatcher,
@@ -221,6 +225,17 @@ internal static LogLevel GetLogLevel(string? verbosity)
}
}
+ internal static DiagnosticSeverity GetSeverity(string? severity)
+ {
+ return severity?.ToLowerInvariant() switch
+ {
+ FixSeverity.Error => DiagnosticSeverity.Error,
+ FixSeverity.Warn => DiagnosticSeverity.Warning,
+ FixSeverity.Info => DiagnosticSeverity.Info,
+ _ => throw new ArgumentOutOfRangeException(nameof(severity)),
+ };
+ }
+
private static ILogger SetupLogging(IConsole console, LogLevel logLevel)
{
var serviceCollection = new ServiceCollection();
diff --git a/src/Utilities/EditorConfigFinder.cs b/src/Utilities/EditorConfigFinder.cs
index 04ee7f34bc..f7d5cea6e4 100644
--- a/src/Utilities/EditorConfigFinder.cs
+++ b/src/Utilities/EditorConfigFinder.cs
@@ -25,7 +25,7 @@ public static ImmutableArray GetEditorConfigPaths(string path)
.Select(file => file.FullName)
.ToList();
- while (directory.Parent is object)
+ while (directory.Parent != null)
{
directory = directory.Parent;
diff --git a/src/Workspaces/FolderWorkspace_FolderSolutionLoader.cs b/src/Workspaces/FolderWorkspace_FolderSolutionLoader.cs
index 3fa33eec82..72afbba340 100644
--- a/src/Workspaces/FolderWorkspace_FolderSolutionLoader.cs
+++ b/src/Workspaces/FolderWorkspace_FolderSolutionLoader.cs
@@ -26,7 +26,7 @@ public static async Task LoadSolutionInfoAsync(string folderPath,
// Create projects for each of the supported languages.
foreach (var loader in ProjectLoaders)
{
- var projectInfo = await loader.LoadProjectInfoAsync(folderPath, fileMatcher, cancellationToken);
+ var projectInfo = await loader.LoadProjectInfoAsync(folderPath, fileMatcher, cancellationToken).ConfigureAwait(false);
if (projectInfo is null)
{
continue;
diff --git a/src/Workspaces/FolderWorkspace_ProjectLoader.cs b/src/Workspaces/FolderWorkspace_ProjectLoader.cs
index 6b4567e5d4..f836196480 100644
--- a/src/Workspaces/FolderWorkspace_ProjectLoader.cs
+++ b/src/Workspaces/FolderWorkspace_ProjectLoader.cs
@@ -23,7 +23,7 @@ private abstract class ProjectLoader
{
var projectId = ProjectId.CreateNewId(debugName: folderPath);
- var documents = await LoadDocumentInfosAsync(projectId, folderPath, FileExtension, fileMatcher);
+ var documents = await LoadDocumentInfosAsync(projectId, folderPath, FileExtension, fileMatcher).ConfigureAwait(false);
if (documents.IsDefaultOrEmpty)
{
return null;
diff --git a/src/dotnet-format.csproj b/src/dotnet-format.csproj
index 77f4e14608..7d5d17d059 100644
--- a/src/dotnet-format.csproj
+++ b/src/dotnet-format.csproj
@@ -57,7 +57,6 @@
https://github.com/microsoft/MSBuildLocator/issues/88
-->
-
diff --git a/tests/CodeFormatterTests.cs b/tests/CodeFormatterTests.cs
index edf68ba37d..1d7ce5851c 100644
--- a/tests/CodeFormatterTests.cs
+++ b/tests/CodeFormatterTests.cs
@@ -394,7 +394,10 @@ public async Task TestFormatWorkspaceAsync(string workspaceFilePath, IEn
workspacePath,
workspaceType,
LogLevel.Trace,
- FormatType.Whitespace,
+ fixCodeStyle: false,
+ codeStyleSeverity: DiagnosticSeverity.Error,
+ fixAnalyzers: false,
+ analyerSeverity: DiagnosticSeverity.Error,
saveFormattedFiles: false,
changesAreErrors: false,
fileMatcher,
diff --git a/tests/Formatters/AbstractFormatterTests.cs b/tests/Formatters/AbstractFormatterTests.cs
index 69b7d8255e..7c5dd22805 100644
--- a/tests/Formatters/AbstractFormatterTests.cs
+++ b/tests/Formatters/AbstractFormatterTests.cs
@@ -116,7 +116,10 @@ private protected async Task TestAsync(string testCode, string expec
workspaceFilePath: project.FilePath,
workspaceType: WorkspaceType.Folder,
logLevel: LogLevel.Trace,
- formatType: FormatType.Whitespace,
+ fixCodeStyle: false,
+ codeStyleSeverity: DiagnosticSeverity.Error,
+ fixAnalyzers: false,
+ analyerSeverity: DiagnosticSeverity.Error,
saveFormattedFiles: false,
changesAreErrors: false,
fileMatcher,
diff --git a/tests/Formatters/FormattedFilesTests.cs b/tests/Formatters/FormattedFilesTests.cs
index e0b6349fd5..8732f12052 100644
--- a/tests/Formatters/FormattedFilesTests.cs
+++ b/tests/Formatters/FormattedFilesTests.cs
@@ -58,7 +58,10 @@ private async Task> TestFormattedFiles(string testCode)
workspaceFilePath: project.FilePath,
workspaceType: WorkspaceType.Folder,
logLevel: LogLevel.Trace,
- FormatType.All,
+ fixCodeStyle: false,
+ codeStyleSeverity: DiagnosticSeverity.Error,
+ fixAnalyzers: false,
+ analyerSeverity: DiagnosticSeverity.Error,
saveFormattedFiles: false,
changesAreErrors: false,
fileMatcher,
diff --git a/validate.rsp b/validate.rsp
index 0288aac783..cd0bd8bffa 100644
--- a/validate.rsp
+++ b/validate.rsp
@@ -1,5 +1,6 @@
---folder
-.
+./format.sln
+--fix-style
+--fix-analyzers
--exclude
./tests/projects/
--check