Skip to content

Commit

Permalink
Merge pull request #725 from JoeRobich/filter-analyzers-by-language
Browse files Browse the repository at this point in the history
Filter analyzers by project language before running
  • Loading branch information
JoeRobich committed Jul 6, 2020
2 parents ddcce23 + 47e446c commit 12b27cc
Showing 1 changed file with 27 additions and 5 deletions.
32 changes: 27 additions & 5 deletions src/Analyzers/AnalyzerFormatter.cs
Expand Up @@ -16,6 +16,8 @@ namespace Microsoft.CodeAnalysis.Tools.Analyzers
{
internal class AnalyzerFormatter : ICodeFormatter
{
private static readonly ImmutableArray<string> _supportedLanguages = ImmutableArray.Create(LanguageNames.CSharp, LanguageNames.VisualBasic);

private readonly string _name;
private readonly IAnalyzerInformationProvider _informationProvider;
private readonly IAnalyzerRunner _runner;
Expand All @@ -42,6 +44,10 @@ internal class AnalyzerFormatter : ICodeFormatter
CancellationToken cancellationToken)
{
var (analyzers, fixers) = _informationProvider.GetAnalyzersAndFixers(solution, formatOptions, logger);
if (analyzers.IsEmpty && fixers.IsEmpty)
{
return solution;
}

var analysisStopwatch = Stopwatch.StartNew();
logger.LogTrace(Resources.Running_0_analysis, _name);
Expand Down Expand Up @@ -148,13 +154,13 @@ static void LogDiagnosticLocations(Solution solution, IEnumerable<Diagnostic> di
}

// Build maps between diagnostic id and the associated analyzers and codefixes
var analyzersById = CreateAnalyzerMap(reportedDiagnostics, allAnalyzers);
var analyzersByIdAndLanguage = CreateAnalyzerMap(reportedDiagnostics, allAnalyzers);
var fixersById = CreateFixerMap(reportedDiagnostics, allCodefixes);

// We need to run each codefix iteratively so ensure that all diagnostics are found and fixed.
foreach (var diagnosticId in reportedDiagnostics)
{
var analyzers = analyzersById[diagnosticId];
var analyzersByLanguage = analyzersByIdAndLanguage[diagnosticId];
var codefixes = fixersById[diagnosticId];

// If there is no codefix, there is no reason to run analysis again.
Expand All @@ -173,6 +179,7 @@ static void LogDiagnosticLocations(Solution solution, IEnumerable<Diagnostic> di
continue;
}

var analyzers = analyzersByLanguage[project.Language];
await _runner.RunCodeAnalysisAsync(result, analyzers, project, formattablePaths, severity, logger, cancellationToken).ConfigureAwait(false);
}

Expand All @@ -193,13 +200,18 @@ static void LogDiagnosticLocations(Solution solution, IEnumerable<Diagnostic> di

return solution;

static ImmutableDictionary<string, ImmutableArray<DiagnosticAnalyzer>> CreateAnalyzerMap(
static ImmutableDictionary<string, ImmutableDictionary<string, ImmutableArray<DiagnosticAnalyzer>>> CreateAnalyzerMap(
ImmutableArray<string> diagnosticIds,
ImmutableArray<DiagnosticAnalyzer> analyzers)
{
return diagnosticIds.ToImmutableDictionary(
id => id,
id => analyzers.Where(analyzer => analyzer.SupportedDiagnostics.Any(diagnostic => diagnostic.Id == id)).ToImmutableArray());
id => _supportedLanguages.ToImmutableDictionary(
language => language,
language => analyzers
.Where(analyzer => DoesAnalyzerSupportLanguage(analyzer, language))
.Where(analyzer => analyzer.SupportedDiagnostics.Any(diagnostic => diagnostic.Id == id))
.ToImmutableArray()));
}

static ImmutableDictionary<string, ImmutableArray<CodeFixProvider>> CreateFixerMap(
Expand All @@ -226,7 +238,9 @@ static void LogDiagnosticLocations(Solution solution, IEnumerable<Diagnostic> di
{
var analyzers = ImmutableArray.CreateBuilder<DiagnosticAnalyzer>();

foreach (var analyzer in allAnalyzers)
// Filter analyzers by project's language
var filteredAnalyzer = allAnalyzers.Where(analyzer => DoesAnalyzerSupportLanguage(analyzer, project.Language));
foreach (var analyzer in filteredAnalyzer)
{
// Always run naming style analyzers because we cannot determine potential severity.
// The reported diagnostics will be filtered by severity when they are run.
Expand All @@ -248,5 +262,13 @@ static void LogDiagnosticLocations(Solution solution, IEnumerable<Diagnostic> di

return projectAnalyzers.ToImmutableDictionary();
}

private static bool DoesAnalyzerSupportLanguage(DiagnosticAnalyzer analyzer, string language)
{
return analyzer.GetType()
.GetCustomAttributes(typeof(DiagnosticAnalyzerAttribute), true)
.OfType<DiagnosticAnalyzerAttribute>()
.Any(attribute => attribute.Languages.Contains(language));
}
}
}

0 comments on commit 12b27cc

Please sign in to comment.