未验证 提交 4ce9f2d5 编写于 作者: M Manish Vasani 提交者: GitHub

Merge pull request #43546 from mavasani/SkipAnalyzersOnBuild

Skip execution of analyzers reporting info and hidden diagnostics dur…
......@@ -3473,11 +3473,11 @@ static Symbol getExplicitAccessibilitySymbol(Symbol symbol)
}
}
internal override AnalyzerDriver AnalyzerForLanguage(ImmutableArray<DiagnosticAnalyzer> analyzers, AnalyzerManager analyzerManager)
internal override AnalyzerDriver CreateAnalyzerDriver(ImmutableArray<DiagnosticAnalyzer> analyzers, AnalyzerManager analyzerManager, SeverityFilter severityFilter)
{
Func<SyntaxNode, SyntaxKind> getKind = node => node.Kind();
Func<SyntaxTrivia, bool> isComment = trivia => trivia.Kind() == SyntaxKind.SingleLineCommentTrivia || trivia.Kind() == SyntaxKind.MultiLineCommentTrivia;
return new AnalyzerDriver<SyntaxKind>(analyzers, getKind, analyzerManager, isComment);
return new AnalyzerDriver<SyntaxKind>(analyzers, getKind, analyzerManager, severityFilter, isComment);
}
internal void SymbolDeclaredEvent(Symbol symbol)
......
......@@ -925,9 +925,16 @@ private int RunCore(TextWriter consoleOutput, ErrorLogger errorLogger, Cancellat
additionalFileAnalyzerOptions);
}
Diagnostics.AnalyzerOptions analyzerOptions = CreateAnalyzerOptions(
AnalyzerOptions analyzerOptions = CreateAnalyzerOptions(
additionalTextFiles, analyzerConfigProvider);
// PERF: Avoid executing analyzers that report only Hidden and/or Info diagnostics, which don't appear in the build output.
// 1. Always filter out 'Hidden' analyzer diagnostics in build.
// 2. Filter out 'Info' analyzer diagnostics if they are not required to be logged in errorlog.
var severityFilter = SeverityFilter.Hidden;
if (Arguments.ErrorLogPath == null)
severityFilter |= SeverityFilter.Info;
analyzerDriver = AnalyzerDriver.CreateAndAttachToCompilation(
compilation,
analyzers,
......@@ -935,6 +942,7 @@ private int RunCore(TextWriter consoleOutput, ErrorLogger errorLogger, Cancellat
new AnalyzerManager(analyzers),
analyzerExceptionDiagnostics.Add,
Arguments.ReportAnalyzer,
severityFilter,
out compilation,
analyzerCts.Token);
reportAnalyzer = Arguments.ReportAnalyzer && !analyzers.IsEmpty;
......
......@@ -114,7 +114,7 @@ public abstract partial class Compilation
return set;
}
internal abstract AnalyzerDriver AnalyzerForLanguage(ImmutableArray<DiagnosticAnalyzer> analyzers, AnalyzerManager analyzerManager);
internal abstract AnalyzerDriver CreateAnalyzerDriver(ImmutableArray<DiagnosticAnalyzer> analyzers, AnalyzerManager analyzerManager, SeverityFilter severityFilter);
/// <summary>
/// Gets the source language ("C#" or "Visual Basic").
......
// 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.
#nullable enable
using System;
namespace Microsoft.CodeAnalysis.Diagnostics
{
/// <summary>
/// Represents a set of filtered diagnostic severities.
/// Currently, we only support filtering out Hidden and Info severities during build.
/// </summary>
[Flags]
internal enum SeverityFilter
{
None = 0x00,
Hidden = 0x01,
Info = 0x10
}
internal static class SeverityFilterExtensions
{
internal static bool Contains(this SeverityFilter severityFilter, ReportDiagnostic severity)
{
return severity switch
{
ReportDiagnostic.Hidden => (severityFilter & SeverityFilter.Hidden) != 0,
ReportDiagnostic.Info => (severityFilter & SeverityFilter.Info) != 0,
_ => false
};
}
}
}
// 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.
namespace Microsoft.CodeAnalysis.Diagnostics
{
internal partial class AnalyzerDriver
{
private static class AnalyzerConfigOptionNames
{
private const string DotnetAnalyzerDiagnosticPrefix = "dotnet_analyzer_diagnostic";
private const string CategoryPrefix = "category";
private const string SeveritySuffix = "severity";
public const string DotnetAnalyzerDiagnosticSeverityKey = DotnetAnalyzerDiagnosticPrefix + "." + SeveritySuffix;
public static string GetCategoryBasedDotnetAnalyzerDiagnosticSeverityKey(string category)
=> $"{DotnetAnalyzerDiagnosticPrefix}.{CategoryPrefix}-{category}.{SeveritySuffix}";
}
}
}
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
......@@ -185,7 +187,7 @@ public async ValueTask<AnalyzerActions> GetPerSymbolAnalyzerActionsAsync(ISymbol
ImmutableArray<SymbolStartAnalyzerAction> getFilteredActionsByKind(ImmutableArray<SymbolStartAnalyzerAction> symbolStartActions)
{
ArrayBuilder<SymbolStartAnalyzerAction> filteredActionsBuilderOpt = null;
ArrayBuilder<SymbolStartAnalyzerAction>? filteredActionsBuilderOpt = null;
for (int i = 0; i < symbolStartActions.Length; i++)
{
var symbolStartAction = symbolStartActions[i];
......@@ -286,7 +288,8 @@ internal bool IsSupportedDiagnostic(DiagnosticAnalyzer analyzer, Diagnostic diag
DiagnosticAnalyzer analyzer,
CompilationOptions options,
Func<DiagnosticAnalyzer, bool> isCompilerAnalyzer,
AnalyzerExecutor analyzerExecutor)
AnalyzerExecutor analyzerExecutor,
SeverityFilter severityFilter)
{
if (isCompilerAnalyzer(analyzer))
{
......@@ -321,10 +324,20 @@ internal bool IsSupportedDiagnostic(DiagnosticAnalyzer analyzer, Diagnostic diag
{
isSuppressed = severity == ReportDiagnostic.Suppress;
}
else
{
severity = isSuppressed ? ReportDiagnostic.Suppress : DiagnosticDescriptor.MapSeverityToReport(diag.DefaultSeverity);
}
// Is this diagnostic suppressed due to its severity
if (severityFilter.Contains(severity))
{
isSuppressed = true;
}
// Editorconfig user settings override compilation wide settings.
if (isSuppressed &&
isEnabledWithAnalyzerConfigOptions(diag.Id, analyzerExecutor.Compilation))
isEnabledWithAnalyzerConfigOptions(diag, severityFilter, analyzerExecutor.Compilation, analyzerExecutor.AnalyzerOptions))
{
isSuppressed = false;
}
......@@ -348,16 +361,24 @@ internal bool IsSupportedDiagnostic(DiagnosticAnalyzer analyzer, Diagnostic diag
return true;
static bool isEnabledWithAnalyzerConfigOptions(string diagnosticId, Compilation compilation)
static bool isEnabledWithAnalyzerConfigOptions(
DiagnosticDescriptor descriptor,
SeverityFilter severityFilter,
Compilation? compilation,
AnalyzerOptions? analyzerOptions)
{
if (compilation != null)
{
foreach (var tree in compilation.SyntaxTrees)
{
if (tree.DiagnosticOptions.TryGetValue(diagnosticId, out var configuredValue) &&
configuredValue != ReportDiagnostic.Suppress)
// Check if diagnostic is enabled by SyntaxTree.DiagnosticOptions or Bulk configuration from AnalyzerConfigOptions.
if (tree.DiagnosticOptions.TryGetValue(descriptor.Id, out var configuredValue) ||
analyzerOptions.TryGetSeverityFromBulkConfiguration(tree, compilation, descriptor, out configuredValue))
{
return true;
if (configuredValue != ReportDiagnostic.Suppress && !severityFilter.Contains(configuredValue))
{
return true;
}
}
}
}
......
// 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.
#nullable enable
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using Roslyn.Utilities;
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}";
/// <summary>
/// Tries to get configured severity for the given <paramref name="descriptor"/>
/// for the given <paramref name="tree"/> from bulk configuration analyzer config options, i.e.
/// 'dotnet_analyzer_diagnostic.category-%RuleCategory%.severity = %severity%'
/// or
/// 'dotnet_analyzer_diagnostic.severity = %severity%'
/// </summary>
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.Contains(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) &&
AnalyzerConfigSet.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) &&
AnalyzerConfigSet.TryParseSeverity(value, out severity))
{
return true;
}
severity = default;
return false;
}
}
}
......@@ -138,7 +138,7 @@ private CompilationWithAnalyzers(Compilation compilation, ImmutableArray<Diagnos
_analysisState = new AnalysisState(analyzers, _compilationData, _compilation.Options);
_analysisResultBuilder = new AnalysisResultBuilder(analysisOptions.LogAnalyzerExecutionTime, analyzers);
_analyzerManager = new AnalyzerManager(analyzers);
_driverPool = new ObjectPool<AnalyzerDriver>(() => _compilation.AnalyzerForLanguage(analyzers, _analyzerManager));
_driverPool = new ObjectPool<AnalyzerDriver>(() => _compilation.CreateAnalyzerDriver(analyzers, _analyzerManager, severityFilter: SeverityFilter.None));
_executingConcurrentTreeTasksOpt = analysisOptions.ConcurrentAnalysis ? new Dictionary<SyntaxTree, Tuple<Task, CancellationTokenSource>>() : null;
_concurrentTreeTaskTokensOpt = analysisOptions.ConcurrentAnalysis ? new Dictionary<Task, int>() : null;
_executingCompilationOrNonConcurrentTreeTask = null;
......@@ -389,7 +389,7 @@ private async Task ComputeAnalyzerDiagnosticsWithoutStateTrackingAsync(Cancellat
// Create and attach the driver to compilation.
var categorizeDiagnostics = true;
driver = compilation.AnalyzerForLanguage(analyzers, _analyzerManager);
driver = compilation.CreateAnalyzerDriver(analyzers, _analyzerManager, severityFilter: SeverityFilter.None);
driver.Initialize(compilation, _analysisOptions, compilationData, categorizeDiagnostics, cancellationToken);
var analysisScope = new AnalysisScope(compilation, analyzers, concurrentAnalysis: _analysisOptions.ConcurrentAnalysis, categorizeDiagnostics: categorizeDiagnostics);
driver.AttachQueueAndStartProcessingEvents(compilation.EventQueue, analysisScope, cancellationToken);
......@@ -429,7 +429,7 @@ private async Task<ImmutableArray<Diagnostic>> GetAllDiagnosticsWithoutStateTrac
// Create and attach the driver to compilation.
var categorizeDiagnostics = false;
driver = compilation.AnalyzerForLanguage(analyzers, _analyzerManager);
driver = compilation.CreateAnalyzerDriver(analyzers, _analyzerManager, severityFilter: SeverityFilter.None);
driver.Initialize(compilation, _analysisOptions, compilationData, categorizeDiagnostics, cancellationToken);
var analysisScope = new AnalysisScope(compilation, analyzers, concurrentAnalysis: _analysisOptions.ConcurrentAnalysis, categorizeDiagnostics: categorizeDiagnostics);
driver.AttachQueueAndStartProcessingEvents(compilation.EventQueue, analysisScope, cancellationToken);
......@@ -1194,7 +1194,7 @@ SemanticModel getSemanticModel(Compilation compilation, SyntaxTree tree)
var analyzerManager = new AnalyzerManager(analyzer);
var analyzerExecutor = AnalyzerExecutor.CreateForSupportedDiagnostics(onAnalyzerException, analyzerManager);
return AnalyzerDriver.IsDiagnosticAnalyzerSuppressed(analyzer, options, analyzerManager, analyzerExecutor);
return AnalyzerDriver.IsDiagnosticAnalyzerSuppressed(analyzer, options, analyzerManager, analyzerExecutor, severityFilter: SeverityFilter.None);
}
/// <summary>
......
......@@ -2165,10 +2165,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
End If
End Sub
Friend Overrides Function AnalyzerForLanguage(analyzers As ImmutableArray(Of DiagnosticAnalyzer), analyzerManager As AnalyzerManager) As AnalyzerDriver
Friend Overrides Function CreateAnalyzerDriver(analyzers As ImmutableArray(Of DiagnosticAnalyzer), analyzerManager As AnalyzerManager, severityFilter As SeverityFilter) As AnalyzerDriver
Dim getKind As Func(Of SyntaxNode, SyntaxKind) = Function(node As SyntaxNode) node.Kind
Dim isComment As Func(Of SyntaxTrivia, Boolean) = Function(trivia As SyntaxTrivia) trivia.Kind() = SyntaxKind.CommentTrivia
Return New AnalyzerDriver(Of SyntaxKind)(analyzers, getKind, analyzerManager, isComment)
Return New AnalyzerDriver(Of SyntaxKind)(analyzers, getKind, analyzerManager, severityFilter, isComment)
End Function
#End Region
......
......@@ -2089,15 +2089,17 @@ public override void Initialize(AnalysisContext context)
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
public sealed class NamedTypeAnalyzerWithConfigurableEnabledByDefault : DiagnosticAnalyzer
{
public NamedTypeAnalyzerWithConfigurableEnabledByDefault(bool isEnabledByDefault)
private readonly bool _throwOnAllNamedTypes;
public NamedTypeAnalyzerWithConfigurableEnabledByDefault(bool isEnabledByDefault, DiagnosticSeverity defaultSeverity, bool throwOnAllNamedTypes = false)
{
Descriptor = new DiagnosticDescriptor(
"ID0001",
"Title1",
"Message1",
"Category1",
defaultSeverity: DiagnosticSeverity.Warning,
defaultSeverity,
isEnabledByDefault);
_throwOnAllNamedTypes = throwOnAllNamedTypes;
}
public DiagnosticDescriptor Descriptor { get; }
......@@ -2105,8 +2107,15 @@ public NamedTypeAnalyzerWithConfigurableEnabledByDefault(bool isEnabledByDefault
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Descriptor);
public override void Initialize(AnalysisContext context)
{
context.RegisterSymbolAction(
context => context.ReportDiagnostic(Diagnostic.Create(Descriptor, context.Symbol.Locations[0])),
context.RegisterSymbolAction(context =>
{
if (_throwOnAllNamedTypes)
{
throw new NotImplementedException();
}
context.ReportDiagnostic(Diagnostic.Create(Descriptor, context.Symbol.Locations[0]));
},
SymbolKind.NamedType);
}
}
......
......@@ -288,7 +288,8 @@ public static TCompilation VerifyDiagnostics<TCompilation>(this TCompilation c,
}
var analyzerManager = new AnalyzerManager(analyzersArray);
var driver = AnalyzerDriver.CreateAndAttachToCompilation(c, analyzersArray, options, analyzerManager, onAnalyzerException, null, false, out var newCompilation, cancellationToken);
var driver = AnalyzerDriver.CreateAndAttachToCompilation(c, analyzersArray, options, analyzerManager, onAnalyzerException,
analyzerExceptionFilter: null, reportAnalyzer: false, severityFilter: SeverityFilter.None, out var newCompilation, cancellationToken);
var compilerDiagnostics = newCompilation.GetDiagnostics(cancellationToken);
var analyzerDiagnostics = driver.GetDiagnosticsAsync(newCompilation).Result;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册