Skip to content

Commit

Permalink
Run diagnostics in parallel if in dry-run
Browse files Browse the repository at this point in the history
  • Loading branch information
jmarolf authored and JoeRobich committed Jun 3, 2020
1 parent e3f4aaf commit 07ac26d
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 14 deletions.
30 changes: 20 additions & 10 deletions src/Analyzers/AnalyzerFormatter.cs
Expand Up @@ -44,18 +44,32 @@ internal class AnalyzerFormatter : ICodeFormatter
.OfType<string>().ToImmutableArray();

var pairs = _finder.GetAnalyzersAndFixers();
foreach (var (analyzer, codefix) in pairs)

if (!options.SaveFormattedFiles)
{
// 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) =>
{
await _runner.RunCodeAnalysisAsync(result, analyzer, project, paths, logger, token);
await _runner.RunCodeAnalysisAsync(result, analyzers, project, paths, logger, token);
}, cancellationToken);

var hasDiagnostics = result.Diagnostics.Any(kvp => kvp.Value.Length > 0);
if (hasDiagnostics)
LogDiagnosticLocations(result.Diagnostics.SelectMany(kvp => kvp.Value), options.WorkspaceFilePath, options.ChangesAreErrors, logger);
}
else
{
// we need to run each codefix iteratively so ensure that all diagnostics are found and fixed
foreach (var (analyzer, codefix) in pairs)
{
if (options.SaveFormattedFiles)
var result = new CodeAnalysisResult();
await solution.Projects.ForEachAsync(async (project, token) =>
{
await _runner.RunCodeAnalysisAsync(result, analyzer, project, paths, logger, token);
}, cancellationToken);

var hasDiagnostics = result.Diagnostics.Any(kvp => kvp.Value.Length > 0);
if (hasDiagnostics && codefix is object)
{
logger.LogTrace($"Applying fixes for {codefix.GetType().Name}");
solution = await _applier.ApplyCodeFixesAsync(solution, result, codefix, logger, cancellationToken);
Expand All @@ -65,10 +79,6 @@ internal class AnalyzerFormatter : ICodeFormatter
solution = changedSolution;
}
}
else
{
LogDiagnosticLocations(result.Diagnostics.SelectMany(kvp => kvp.Value), options.WorkspaceFilePath, options.ChangesAreErrors, logger);
}
}
}

Expand All @@ -84,7 +94,7 @@ private void LogDiagnosticLocations(IEnumerable<Diagnostic> diagnostics, string
foreach (var diagnostic in diagnostics)
{
var message = diagnostic.GetMessage();
var filePath = diagnostic.Location.SourceTree.FilePath;
var filePath = diagnostic.Location.SourceTree?.FilePath;

var mappedLineSpan = diagnostic.Location.GetMappedLineSpan();
var changePosition = mappedLineSpan.StartLinePosition;
Expand Down
13 changes: 11 additions & 2 deletions src/Analyzers/AnalyzerRunner.cs
Expand Up @@ -12,13 +12,22 @@ namespace Microsoft.CodeAnalysis.Tools.Analyzers
{
internal partial class AnalyzerRunner : IAnalyzerRunner
{
public async Task RunCodeAnalysisAsync(
public Task RunCodeAnalysisAsync(
CodeAnalysisResult result,
DiagnosticAnalyzer analyzers,
Project project,
ImmutableArray<string> formattableDocumentPaths,
ILogger logger,
CancellationToken cancellationToken)
=> RunCodeAnalysisAsync(result, ImmutableArray.Create(analyzers), project, formattableDocumentPaths, logger, cancellationToken);

public async Task RunCodeAnalysisAsync(
CodeAnalysisResult result,
ImmutableArray<DiagnosticAnalyzer> analyzers,
Project project,
ImmutableArray<string> formattableDocumentPaths,
ILogger logger,
CancellationToken cancellationToken)
{
var compilation = await project.GetCompilationAsync(cancellationToken);
if (compilation is null)
Expand All @@ -27,7 +36,7 @@ internal partial class AnalyzerRunner : IAnalyzerRunner
}

var analyzerCompilation = compilation.WithAnalyzers(
ImmutableArray.Create(analyzers),
analyzers,
options: project.AnalyzerOptions,
cancellationToken);
var diagnostics = await analyzerCompilation.GetAnalyzerDiagnosticsAsync(cancellationToken);
Expand Down
8 changes: 8 additions & 0 deletions src/Analyzers/Interfaces/IAnalyzerRunner.cs
Expand Up @@ -17,5 +17,13 @@ interface IAnalyzerRunner
ImmutableArray<string> formattableDocumentPaths,
ILogger logger,
CancellationToken cancellationToken);

Task RunCodeAnalysisAsync(
CodeAnalysisResult result,
ImmutableArray<DiagnosticAnalyzer> analyzers,
Project project,
ImmutableArray<string> formattableDocumentPaths,
ILogger logger,
CancellationToken cancellationToken);
}
}
7 changes: 5 additions & 2 deletions src/Analyzers/SolutionCodeFixApplier.cs
Expand Up @@ -50,6 +50,7 @@ internal class SolutionCodeFixApplier : ICodeFixApplier

private class DiagnosticProvider : FixAllContext.DiagnosticProvider
{
private static readonly Task<IEnumerable<Diagnostic>> EmptyDignosticResult = Task.FromResult(Enumerable.Empty<Diagnostic>());
private readonly IReadOnlyDictionary<Project, ImmutableArray<Diagnostic>> _diagnosticsByProject;

internal DiagnosticProvider(CodeAnalysisResult analysisResult)
Expand All @@ -59,7 +60,7 @@ internal DiagnosticProvider(CodeAnalysisResult analysisResult)

public override Task<IEnumerable<Diagnostic>> GetAllDiagnosticsAsync(Project project, CancellationToken cancellationToken)
{
return Task.FromResult<IEnumerable<Diagnostic>>(_diagnosticsByProject[project]);
return GetProjectDiagnosticsAsync(project, cancellationToken);
}

public override Task<IEnumerable<Diagnostic>> GetDocumentDiagnosticsAsync(Document document, CancellationToken cancellationToken)
Expand All @@ -69,7 +70,9 @@ public override Task<IEnumerable<Diagnostic>> GetDocumentDiagnosticsAsync(Docume

public override Task<IEnumerable<Diagnostic>> GetProjectDiagnosticsAsync(Project project, CancellationToken cancellationToken)
{
return Task.FromResult<IEnumerable<Diagnostic>>(_diagnosticsByProject[project]);
return _diagnosticsByProject.ContainsKey(project)
? Task.FromResult<IEnumerable<Diagnostic>>(_diagnosticsByProject[project])
: EmptyDignosticResult;
}
}
}
Expand Down

0 comments on commit 07ac26d

Please sign in to comment.