From c75546b7f48e22ddd06df655f1ade5d146bfab3e Mon Sep 17 00:00:00 2001 From: Manish Vasani Date: Fri, 11 Nov 2016 16:00:44 -0800 Subject: [PATCH] Ensure that we don't execute Initialize and compilation start actions for analyzers with no enabled rules Fixes #15184 --- .../CompilationWithAnalyzersTests.cs | 19 +++++++++++++++++++ .../DiagnosticAnalyzer/AnalysisState.cs | 6 ++++-- .../DiagnosticAnalyzer/AnalyzerDriver.cs | 7 ++++++- .../CompilationWithAnalyzers.cs | 4 ++-- .../Desktop/CommonDiagnosticAnalyzers.cs | 18 ++++++++++++++++++ 5 files changed, 49 insertions(+), 5 deletions(-) diff --git a/src/Compilers/Core/CodeAnalysisTest/Diagnostics/CompilationWithAnalyzersTests.cs b/src/Compilers/Core/CodeAnalysisTest/Diagnostics/CompilationWithAnalyzersTests.cs index c89a4925ec0..dcdef4057db 100644 --- a/src/Compilers/Core/CodeAnalysisTest/Diagnostics/CompilationWithAnalyzersTests.cs +++ b/src/Compilers/Core/CodeAnalysisTest/Diagnostics/CompilationWithAnalyzersTests.cs @@ -4,11 +4,13 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; +using System.Threading; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Diagnostics; using Roslyn.Test.Utilities; using Roslyn.Utilities; using Xunit; +using static Microsoft.CodeAnalysis.CommonDiagnosticAnalyzers; namespace Microsoft.CodeAnalysis.UnitTests.Diagnostics { @@ -45,5 +47,22 @@ public void GetEffectiveDiagnostics() AssertEx.Equal(new[] { d1 }, filtered); } + + [Fact] + public void GetAnalyzerTelemetry() + { + var compilation = CSharpCompilation.Create("c", options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); + DiagnosticAnalyzer analyzer = new AnalyzerWithDisabledRules(); + var analyzers = ImmutableArray.Create(analyzer); + var analyzerOptions = new AnalyzerOptions(ImmutableArray.Empty); + var compWithAnalyzers = new CompilationWithAnalyzers(compilation, analyzers, analyzerOptions, CancellationToken.None); + + var analysisResult = compWithAnalyzers.GetAnalysisResultAsync(CancellationToken.None).Result; + Assert.Empty(analysisResult.CompilationDiagnostics); + + // Even though the analyzer registers a symbol action, it should never be invoked because all of its rules are disabled. + var analyzerTelemetry = compWithAnalyzers.GetAnalyzerTelemetryInfoAsync(analyzer, CancellationToken.None).Result; + Assert.Equal(0, analyzerTelemetry.SymbolActionsCount); + } } } diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalysisState.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalysisState.cs index 6ba672dcbf7..daae9320e2c 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalysisState.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalysisState.cs @@ -51,6 +51,7 @@ internal partial class AnalysisState private readonly HashSet _treesWithGeneratedSourceEvents; private readonly HashSet _partialSymbolsWithGeneratedSourceEvents; private readonly CompilationData _compilationData; + private readonly CompilationOptions _compilationOptions; private bool _compilationStartGenerated; private bool _compilationEndGenerated; @@ -63,11 +64,12 @@ internal partial class AnalysisState private readonly ObjectPool> _compilationEventsPool; private readonly HashSet _pooledEventsWithAnyActionsSet; - public AnalysisState(ImmutableArray analyzers, CompilationData compilationData) + public AnalysisState(ImmutableArray analyzers, CompilationData compilationData, CompilationOptions compilationOptions) { _gate = new object(); _analyzerStateMap = CreateAnalyzerStateMap(analyzers, out _analyzerStates); _compilationData = compilationData; + _compilationOptions = compilationOptions; _pendingSourceEvents = new Dictionary>(); _pendingNonSourceEvents = new HashSet(); _lazyAnalyzerActionCountsMap = null; @@ -402,7 +404,7 @@ private async Task EnsureAnalyzerActionCountsInitializedAsync(AnalyzerDriver dri var builder = ImmutableDictionary.CreateBuilder(); foreach (var analyzer in _analyzerStateMap.Keys) { - var actionCounts = await driver.GetAnalyzerActionCountsAsync(analyzer, cancellationToken).ConfigureAwait(false); + var actionCounts = await driver.GetAnalyzerActionCountsAsync(analyzer, _compilationOptions, cancellationToken).ConfigureAwait(false); builder.Add(analyzer, actionCounts); } diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerDriver.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerDriver.cs index c89caed3d1c..232e2456c82 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerDriver.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerDriver.cs @@ -1298,9 +1298,14 @@ protected bool IsGeneratedCode(SyntaxTree tree) protected bool DoNotAnalyzeGeneratedCode => _doNotAnalyzeGeneratedCode; - internal async Task GetAnalyzerActionCountsAsync(DiagnosticAnalyzer analyzer, CancellationToken cancellationToken) + internal async Task GetAnalyzerActionCountsAsync(DiagnosticAnalyzer analyzer, CompilationOptions compilationOptions, CancellationToken cancellationToken) { var executor = analyzerExecutor.WithCancellationToken(cancellationToken); + if (IsDiagnosticAnalyzerSuppressed(analyzer, compilationOptions, analyzerManager, executor)) + { + return new AnalyzerActionCounts(null); + } + var analyzerActions = await analyzerManager.GetAnalyzerActionsAsync(analyzer, executor).ConfigureAwait(false); return new AnalyzerActionCounts(analyzerActions); } diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/CompilationWithAnalyzers.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/CompilationWithAnalyzers.cs index fc1f3c03f9b..a442abecc28 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/CompilationWithAnalyzers.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/CompilationWithAnalyzers.cs @@ -129,7 +129,7 @@ private CompilationWithAnalyzers(Compilation compilation, ImmutableArray(() => _compilation.AnalyzerForLanguage(analyzers, AnalyzerManager.Instance)); _executingConcurrentTreeTasksOpt = analysisOptions.ConcurrentAnalysis ? new Dictionary>() : null; @@ -412,7 +412,7 @@ private async Task ComputeAnalyzerDiagnosticsWithoutStateTrackingAsync(Cancellat var analyzerActionCounts = new Dictionary(analyzers.Length); foreach (var analyzer in analyzers) { - var actionCounts = await driver.GetAnalyzerActionCountsAsync(analyzer, cancellationToken).ConfigureAwait(false); + var actionCounts = await driver.GetAnalyzerActionCountsAsync(analyzer, compilation.Options, cancellationToken).ConfigureAwait(false); analyzerActionCounts.Add(analyzer, actionCounts); } Func getAnalyzerActionCounts = analyzer => analyzerActionCounts[analyzer]; diff --git a/src/Test/Utilities/Desktop/CommonDiagnosticAnalyzers.cs b/src/Test/Utilities/Desktop/CommonDiagnosticAnalyzers.cs index 744523bf3f4..98d6ac34de4 100644 --- a/src/Test/Utilities/Desktop/CommonDiagnosticAnalyzers.cs +++ b/src/Test/Utilities/Desktop/CommonDiagnosticAnalyzers.cs @@ -384,6 +384,24 @@ public sealed class AnalyzerWithNoActions : DiagnosticAnalyzer public override void Initialize(AnalysisContext context) { } } + [DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)] + public sealed class AnalyzerWithDisabledRules : DiagnosticAnalyzer + { + public static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor( + "ID1", + "Title1", + "Message1", + "Category1", + defaultSeverity: DiagnosticSeverity.Warning, + isEnabledByDefault: false); + + public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule); + public override void Initialize(AnalysisContext context) + { + context.RegisterSymbolAction(_ => { }, SymbolKind.NamedType); + } + } + [DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)] public sealed class EnsureNoMergedNamespaceSymbolAnalyzer : DiagnosticAnalyzer { -- GitLab