Version Used: .NET 8.0
Steps to Reproduce:
For regulatory and compliance reasons, we have an analyzer that adds a diagnostic to uses of #pragma warning disable ....
using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
namespace Example.Analyzers;
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public sealed class PragmaWarningAnalyzer : DiagnosticAnalyzer
{
internal static DiagnosticDescriptor Rule = new(
id: "EX0001",
title: "Do not use pragma statements to suppress analyzers",
messageFormat: "Diagnostic(s) '{0}' are suppressed using a pragma statement. Use a global suppression instead.",
category: "Reliability",
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true
);
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => [Rule];
public override void Initialize(AnalysisContext context)
{
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
context.EnableConcurrentExecution();
context.RegisterSyntaxNodeAction(AnalyzeSyntaxNode, SyntaxKind.PragmaWarningDirectiveTrivia);
}
private static void AnalyzeSyntaxNode(SyntaxNodeAnalysisContext context)
{
var pragmaWarningDirective = (PragmaWarningDirectiveTriviaSyntax)context.Node;
if (!pragmaWarningDirective.DisableOrRestoreKeyword.IsKind(SyntaxKind.DisableKeyword))
{
return;
}
foreach (var errorCode in pragmaWarningDirective.ErrorCodes)
{
var diagnostic = Diagnostic.Create(Rule, errorCode.GetLocation(), errorCode.ToString());
context.ReportDiagnostic(diagnostic);
}
}
}
I wrote a CSharp Analyzer Verifier test case.
using Verify = Microsoft.CodeAnalysis.CSharp.Testing.CSharpAnalyzerVerifier<Example.Analyzers.PragmaWarningAnalyzer, Microsoft.CodeAnalysis.Testing.DefaultVerifier>;
namespace Example.Analyzers.Tests;
public class PragmaWarningAnalyzerTests
{
[Fact]
public async Task ITPIE0001()
{
const string source = """
#pragma warning disable CS0168
class C
{
void M()
{
int unused;
}
}
#pragma warning restore CS0168
""";
await Verify.VerifyAnalyzerAsync(source);
}
}
It correctly identifies the location of an unexpected diagnostic.
System.InvalidOperationException : Mismatch between number of diagnostics returned, expected "0" actual "1"
Diagnostics:
// /0/Test0.cs(1,25): warning EX0001: Diagnostic(s) 'CS0168' are suppressed using a pragma statement. Use a global suppression instead.
VerifyCS.Diagnostic().WithSpan(1, 25, 1, 31).WithArguments("CS0168"),
Expected Behavior:
I expected to add the expected diagnostic:
// /0/Test0.cs(1,25): warning EX0001: Diagnostic(s) 'CS0168' are suppressed using a pragma statement. Use a global suppression instead.
var expected = Verify.Diagnostic("EX0001").WithSpan(1, 25, 1, 31).WithArguments("CS0168");
await Verify.VerifyAnalyzerAsync(source, expected);
Or to use one of the marker syntaxes:
const string source = """
#pragma warning disable [|CS0168|]
...
""";
const string source = """
#pragma warning disable {|EX0001:CS0168|}
...
""";
Actual Behavior:
No matter how I provided or marked the diagnostic, I got an exception where MY diagnostic ID is now switched into the place of the argument!
System.InvalidOperationException : Context: Verifying exclusions in '#pragma warning disable' code
Mismatch between number of diagnostics returned, expected "0" actual "1"
Diagnostics:
// /0/Test0.cs(1,25): warning EX0001: Diagnostic(s) 'EX0001' are suppressed using a pragma statement. Use a global suppression instead.
VerifyCS.Diagnostic().WithSpan(1, 25, 1, 34).WithArguments("EX0001"),
I think something is amiss with a parser somewhere.
Version Used: .NET 8.0
Steps to Reproduce:
For regulatory and compliance reasons, we have an analyzer that adds a diagnostic to uses of
#pragma warning disable ....I wrote a CSharp Analyzer Verifier test case.
It correctly identifies the location of an unexpected diagnostic.
Expected Behavior:
I expected to add the expected diagnostic:
Or to use one of the marker syntaxes:
Actual Behavior:
No matter how I provided or marked the diagnostic, I got an exception where MY diagnostic ID is now switched into the place of the argument!
I think something is amiss with a parser somewhere.