未验证 提交 98ec28ef 编写于 作者: M Manish Vasani 提交者: GitHub

Merge pull request #38792 from mavasani/AnalyzerDriverFix

Allow disabled by default analyzers to be enabled with editorconfig e…
......@@ -11467,6 +11467,71 @@ public void AnalyzerWarnAsErrorDoesNotEmit(bool warnAsError)
string binaryPath = Path.Combine(dir.Path, "temp.dll");
Assert.True(File.Exists(binaryPath) == !warnAsError);
}
// Currently, configuring no location diagnostics through editorconfig is not supported.
[Theory(Skip = "https://github.com/dotnet/roslyn/issues/38042")]
[CombinatorialData]
public void AnalyzerConfigRespectedForNoLocationDiagnostic(ReportDiagnostic reportDiagnostic, bool isEnabledByDefault, bool noWarn)
{
var analyzer = new AnalyzerWithNoLocationDiagnostics(isEnabledByDefault);
TestAnalyzerConfigRespectedCore(analyzer, analyzer.Descriptor, reportDiagnostic, noWarn);
}
[WorkItem(37876, "https://github.com/dotnet/roslyn/issues/37876")]
[Theory]
[CombinatorialData]
public void AnalyzerConfigRespectedForDisabledByDefaultDiagnostic(ReportDiagnostic analyzerConfigSeverity, bool isEnabledByDefault, bool noWarn)
{
var analyzer = new NamedTypeAnalyzerWithConfigurableEnabledByDefault(isEnabledByDefault);
TestAnalyzerConfigRespectedCore(analyzer, analyzer.Descriptor, analyzerConfigSeverity, noWarn);
}
private void TestAnalyzerConfigRespectedCore(DiagnosticAnalyzer analyzer, DiagnosticDescriptor descriptor, ReportDiagnostic analyzerConfigSeverity, bool noWarn)
{
if (analyzerConfigSeverity == ReportDiagnostic.Default)
{
// "dotnet_diagnostic.ID.severity = default" is not supported.
return;
}
var dir = Temp.CreateDirectory();
var src = dir.CreateFile("test.cs").WriteAllText(@"class C { }");
var analyzerConfig = dir.CreateFile(".editorconfig").WriteAllText($@"
[*.cs]
dotnet_diagnostic.{descriptor.Id}.severity = {analyzerConfigSeverity.ToAnalyzerConfigString()}");
var arguments = new[] {
"/nologo",
"/t:library",
"/preferreduilang:en",
"/analyzerconfig:" + analyzerConfig.Path,
src.Path };
if (noWarn)
{
arguments = arguments.Append($"/nowarn:{descriptor.Id}");
}
var cmd = CreateCSharpCompiler(null, dir.Path, arguments,
analyzers: ImmutableArray.Create<DiagnosticAnalyzer>(analyzer));
Assert.Equal(analyzerConfig.Path, Assert.Single(cmd.Arguments.AnalyzerConfigPaths));
var outWriter = new StringWriter(CultureInfo.InvariantCulture);
var exitCode = cmd.Run(outWriter);
var expectedErrorCode = analyzerConfigSeverity == ReportDiagnostic.Error ? 1 : 0;
Assert.Equal(expectedErrorCode, exitCode);
if (analyzerConfigSeverity == ReportDiagnostic.Error || analyzerConfigSeverity == ReportDiagnostic.Warn || analyzerConfigSeverity == ReportDiagnostic.Info)
{
var prefix = analyzerConfigSeverity == ReportDiagnostic.Error ? "error" : analyzerConfigSeverity == ReportDiagnostic.Warn ? "warning" : "info";
Assert.Contains($"{prefix} {descriptor.Id}: {descriptor.MessageFormat}", outWriter.ToString());
}
else
{
Assert.DoesNotContain(descriptor.Id.ToString(), outWriter.ToString());
}
}
}
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
......
......@@ -23,6 +23,9 @@
<ItemGroup>
<EmbeddedResource Include="..\..\csc\csc.rsp" LogicalName="csc.rsp" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Xunit.Combinatorial" Version="$(XunitCombinatorialVersion)" />
</ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
......
......@@ -308,12 +308,19 @@ internal bool IsSupportedDiagnostic(DiagnosticAnalyzer analyzer, Diagnostic diag
// Is this diagnostic suppressed by default (as written by the rule author)
var isSuppressed = !diag.IsEnabledByDefault;
// If the user said something about it, that overrides the author.
// Compilation wide user settings from ruleset/nowarn/warnaserror overrides the analyzer author.
if (diagnosticOptions.TryGetValue(diag.Id, out var severity))
{
isSuppressed = severity == ReportDiagnostic.Suppress;
}
// Editorconfig user settings override compilation wide settings.
if (isSuppressed &&
isEnabledWithAnalyzerConfigOptions(diag.Id, analyzerExecutor.Compilation))
{
isSuppressed = false;
}
if (!isSuppressed)
{
return false;
......@@ -332,6 +339,23 @@ internal bool IsSupportedDiagnostic(DiagnosticAnalyzer analyzer, Diagnostic diag
}
return true;
static bool isEnabledWithAnalyzerConfigOptions(string diagnosticId, Compilation compilation)
{
if (compilation != null)
{
foreach (var tree in compilation.SyntaxTrees)
{
if (tree.DiagnosticOptions.TryGetValue(diagnosticId, out var configuredValue) &&
configuredValue != ReportDiagnostic.Suppress)
{
return true;
}
}
}
return false;
}
}
internal static bool HasNotConfigurableTag(IEnumerable<string> customTags)
......
......@@ -1923,5 +1923,54 @@ public override void ReportSuppressions(SuppressionAnalysisContext context)
context.ReportSuppression(Suppression.Create(_descriptor2, nonReportedDiagnostic));
}
}
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
public sealed class AnalyzerWithNoLocationDiagnostics : DiagnosticAnalyzer
{
public AnalyzerWithNoLocationDiagnostics(bool isEnabledByDefault)
{
Descriptor = new DiagnosticDescriptor(
"ID0001",
"Title1",
"Message1",
"Category1",
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault);
}
public DiagnosticDescriptor Descriptor { get; }
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Descriptor);
public override void Initialize(AnalysisContext context)
{
context.RegisterCompilationAction(compilationContext =>
compilationContext.ReportDiagnostic(Diagnostic.Create(Descriptor, Location.None)));
}
}
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
public sealed class NamedTypeAnalyzerWithConfigurableEnabledByDefault : DiagnosticAnalyzer
{
public NamedTypeAnalyzerWithConfigurableEnabledByDefault(bool isEnabledByDefault)
{
Descriptor = new DiagnosticDescriptor(
"ID0001",
"Title1",
"Message1",
"Category1",
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault);
}
public DiagnosticDescriptor Descriptor { get; }
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])),
SymbolKind.NamedType);
}
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis
{
internal static class ReportDiagnosticExtensions
{
public static string ToAnalyzerConfigString(this ReportDiagnostic reportDiagnostic)
{
return reportDiagnostic switch
{
ReportDiagnostic.Error => "error",
ReportDiagnostic.Warn => "warning",
ReportDiagnostic.Info => "suggestion",
ReportDiagnostic.Hidden => "silent",
ReportDiagnostic.Suppress => "none",
_ => throw ExceptionUtilities.Unreachable,
};
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册