Skip to content

Commit 189a32e

Browse files
Copilotmagesoe
andcommitted
Add CT0011 analyzer to prevent suppressing MA0051 (method too long)
Co-authored-by: magesoe <8904582+magesoe@users.noreply.github.com>
1 parent 6d40739 commit 189a32e

File tree

4 files changed

+183
-0
lines changed

4 files changed

+183
-0
lines changed
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
using System.Collections.Immutable;
2+
using Microsoft.CodeAnalysis;
3+
using Microsoft.CodeAnalysis.CSharp;
4+
using Microsoft.CodeAnalysis.CSharp.Syntax;
5+
using Microsoft.CodeAnalysis.Diagnostics;
6+
7+
namespace DataverseAnalyzer;
8+
9+
[DiagnosticAnalyzer(LanguageNames.CSharp)]
10+
public sealed class PragmaWarningDisableMA0051Analyzer : DiagnosticAnalyzer
11+
{
12+
private static readonly Lazy<DiagnosticDescriptor> LazyRule = new(() => new DiagnosticDescriptor(
13+
"CT0011",
14+
Resources.CT0011_Title,
15+
Resources.CT0011_MessageFormat,
16+
"Usage",
17+
DiagnosticSeverity.Warning,
18+
isEnabledByDefault: true,
19+
description: Resources.CT0011_Description));
20+
21+
public static DiagnosticDescriptor Rule => LazyRule.Value;
22+
23+
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule);
24+
25+
public override void Initialize(AnalysisContext context)
26+
{
27+
if (context is null)
28+
throw new ArgumentNullException(nameof(context));
29+
30+
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
31+
context.EnableConcurrentExecution();
32+
33+
context.RegisterSyntaxNodeAction(AnalyzePragmaWarning, SyntaxKind.PragmaWarningDirectiveTrivia);
34+
}
35+
36+
private static void AnalyzePragmaWarning(SyntaxNodeAnalysisContext context)
37+
{
38+
var pragma = (PragmaWarningDirectiveTriviaSyntax)context.Node;
39+
40+
if (!pragma.DisableOrRestoreKeyword.IsKind(SyntaxKind.DisableKeyword))
41+
return;
42+
43+
foreach (var errorCode in pragma.ErrorCodes)
44+
{
45+
if (errorCode is IdentifierNameSyntax identifier &&
46+
identifier.Identifier.ValueText == "MA0051")
47+
{
48+
context.ReportDiagnostic(Diagnostic.Create(Rule, pragma.GetLocation()));
49+
return;
50+
}
51+
}
52+
}
53+
}

src/DataverseAnalyzer/Resources.Designer.cs

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/DataverseAnalyzer/Resources.resx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,4 +154,13 @@
154154
<data name="CT0010_Description" xml:space="preserve">
155155
<value>Delete operations cannot have post-images because the record no longer exists after the delete operation. ImageType.Both is also invalid as it includes PostImage.</value>
156156
</data>
157+
<data name="CT0011_Title" xml:space="preserve">
158+
<value>Do not suppress MA0051 (method too long)</value>
159+
</data>
160+
<data name="CT0011_MessageFormat" xml:space="preserve">
161+
<value>Do not suppress MA0051. Split the method into smaller helper methods instead.</value>
162+
</data>
163+
<data name="CT0011_Description" xml:space="preserve">
164+
<value>Suppressing MA0051 hides methods that are too long. Instead, split the method into smaller, focused helper methods to improve readability and maintainability.</value>
165+
</data>
157166
</root>
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
using System.Collections.Immutable;
2+
using Microsoft.CodeAnalysis;
3+
using Microsoft.CodeAnalysis.CSharp;
4+
using Microsoft.CodeAnalysis.Diagnostics;
5+
6+
namespace DataverseAnalyzer.Tests;
7+
8+
public sealed class PragmaWarningDisableMA0051AnalyzerTests
9+
{
10+
[Fact]
11+
public async Task PragmaDisableMA0051ShouldTrigger()
12+
{
13+
var source = """
14+
class TestClass
15+
{
16+
#pragma warning disable MA0051
17+
public void TestMethod() { }
18+
#pragma warning restore MA0051
19+
}
20+
""";
21+
22+
var diagnostics = await GetDiagnosticsAsync(source);
23+
Assert.Single(diagnostics);
24+
Assert.Equal("CT0011", diagnostics[0].Id);
25+
}
26+
27+
[Fact]
28+
public async Task PragmaDisableMA0051WithOtherWarningsShouldTrigger()
29+
{
30+
var source = """
31+
class TestClass
32+
{
33+
#pragma warning disable MA0051, CS0168
34+
public void TestMethod() { }
35+
#pragma warning restore MA0051, CS0168
36+
}
37+
""";
38+
39+
var diagnostics = await GetDiagnosticsAsync(source);
40+
Assert.Single(diagnostics);
41+
Assert.Equal("CT0011", diagnostics[0].Id);
42+
}
43+
44+
[Fact]
45+
public async Task PragmaRestoreMA0051ShouldNotTrigger()
46+
{
47+
var source = """
48+
class TestClass
49+
{
50+
#pragma warning restore MA0051
51+
public void TestMethod() { }
52+
}
53+
""";
54+
55+
var diagnostics = await GetDiagnosticsAsync(source);
56+
Assert.Empty(diagnostics);
57+
}
58+
59+
[Fact]
60+
public async Task PragmaDisableOtherWarningShouldNotTrigger()
61+
{
62+
var source = """
63+
class TestClass
64+
{
65+
#pragma warning disable CS0168
66+
public void TestMethod() { }
67+
#pragma warning restore CS0168
68+
}
69+
""";
70+
71+
var diagnostics = await GetDiagnosticsAsync(source);
72+
Assert.Empty(diagnostics);
73+
}
74+
75+
[Fact]
76+
public async Task MultiplePragmaDisableMA0051ShouldTriggerMultipleTimes()
77+
{
78+
var source = """
79+
class TestClass
80+
{
81+
#pragma warning disable MA0051
82+
public void TestMethodA() { }
83+
#pragma warning restore MA0051
84+
#pragma warning disable MA0051
85+
public void TestMethodB() { }
86+
#pragma warning restore MA0051
87+
}
88+
""";
89+
90+
var diagnostics = await GetDiagnosticsAsync(source);
91+
Assert.Equal(2, diagnostics.Length);
92+
Assert.All(diagnostics, d => Assert.Equal("CT0011", d.Id));
93+
}
94+
95+
private static async Task<Diagnostic[]> GetDiagnosticsAsync(string source)
96+
{
97+
var syntaxTree = CSharpSyntaxTree.ParseText(source, new CSharpParseOptions(LanguageVersion.Latest));
98+
var references = new List<MetadataReference>
99+
{
100+
MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
101+
};
102+
103+
var compilation = CSharpCompilation.Create(
104+
"TestAssembly",
105+
new[] { syntaxTree },
106+
references,
107+
new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
108+
109+
var analyzer = new PragmaWarningDisableMA0051Analyzer();
110+
var compilationWithAnalyzers = compilation.WithAnalyzers(ImmutableArray.Create<DiagnosticAnalyzer>(analyzer));
111+
112+
var diagnostics = await compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync();
113+
return diagnostics.Where(d => d.Id == "CT0011").ToArray();
114+
}
115+
}

0 commit comments

Comments
 (0)