diff --git a/src/DataverseAnalyzer/PragmaWarningDisableMA0051Analyzer.cs b/src/DataverseAnalyzer/PragmaWarningDisableMA0051Analyzer.cs new file mode 100644 index 0000000..6ecd054 --- /dev/null +++ b/src/DataverseAnalyzer/PragmaWarningDisableMA0051Analyzer.cs @@ -0,0 +1,53 @@ +using System.Collections.Immutable; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; + +namespace DataverseAnalyzer; + +[DiagnosticAnalyzer(LanguageNames.CSharp)] +public sealed class PragmaWarningDisableMA0051Analyzer : DiagnosticAnalyzer +{ + private static readonly Lazy LazyRule = new(() => new DiagnosticDescriptor( + "CT0011", + Resources.CT0011_Title, + Resources.CT0011_MessageFormat, + "Usage", + DiagnosticSeverity.Warning, + isEnabledByDefault: true, + description: Resources.CT0011_Description)); + + public static DiagnosticDescriptor Rule => LazyRule.Value; + + public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule); + + public override void Initialize(AnalysisContext context) + { + if (context is null) + throw new ArgumentNullException(nameof(context)); + + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); + context.EnableConcurrentExecution(); + + context.RegisterSyntaxNodeAction(AnalyzePragmaWarning, SyntaxKind.PragmaWarningDirectiveTrivia); + } + + private static void AnalyzePragmaWarning(SyntaxNodeAnalysisContext context) + { + var pragma = (PragmaWarningDirectiveTriviaSyntax)context.Node; + + if (!pragma.DisableOrRestoreKeyword.IsKind(SyntaxKind.DisableKeyword)) + return; + + foreach (var errorCode in pragma.ErrorCodes) + { + if (errorCode is IdentifierNameSyntax identifier && + identifier.Identifier.ValueText == "MA0051") + { + context.ReportDiagnostic(Diagnostic.Create(Rule, pragma.GetLocation())); + return; + } + } + } +} \ No newline at end of file diff --git a/src/DataverseAnalyzer/Resources.Designer.cs b/src/DataverseAnalyzer/Resources.Designer.cs index de143f2..86d999d 100644 --- a/src/DataverseAnalyzer/Resources.Designer.cs +++ b/src/DataverseAnalyzer/Resources.Designer.cs @@ -71,5 +71,11 @@ internal static class Resources internal static string CT0010_Description => GetString(nameof(CT0010_Description)); + internal static string CT0011_Title => GetString(nameof(CT0011_Title)); + + internal static string CT0011_MessageFormat => GetString(nameof(CT0011_MessageFormat)); + + internal static string CT0011_Description => GetString(nameof(CT0011_Description)); + private static string GetString(string name) => ResourceManager.GetString(name, CultureInfo.InvariantCulture) ?? name; } \ No newline at end of file diff --git a/src/DataverseAnalyzer/Resources.resx b/src/DataverseAnalyzer/Resources.resx index aaa2fec..597530a 100644 --- a/src/DataverseAnalyzer/Resources.resx +++ b/src/DataverseAnalyzer/Resources.resx @@ -154,4 +154,13 @@ 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. + + Do not suppress MA0051 (method too long) + + + Do not suppress MA0051. Split the method into smaller helper methods instead. + + + Suppressing MA0051 hides methods that are too long. Instead, split the method into smaller, focused helper methods to improve readability and maintainability. + \ No newline at end of file diff --git a/tests/DataverseAnalyzer.Tests/PragmaWarningDisableMA0051AnalyzerTests.cs b/tests/DataverseAnalyzer.Tests/PragmaWarningDisableMA0051AnalyzerTests.cs new file mode 100644 index 0000000..b8c3a84 --- /dev/null +++ b/tests/DataverseAnalyzer.Tests/PragmaWarningDisableMA0051AnalyzerTests.cs @@ -0,0 +1,115 @@ +using System.Collections.Immutable; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Diagnostics; + +namespace DataverseAnalyzer.Tests; + +public sealed class PragmaWarningDisableMA0051AnalyzerTests +{ + [Fact] + public async Task PragmaDisableMA0051ShouldTrigger() + { + var source = """ + class TestClass + { + #pragma warning disable MA0051 + public void TestMethod() { } + #pragma warning restore MA0051 + } + """; + + var diagnostics = await GetDiagnosticsAsync(source); + Assert.Single(diagnostics); + Assert.Equal("CT0011", diagnostics[0].Id); + } + + [Fact] + public async Task PragmaDisableMA0051WithOtherWarningsShouldTrigger() + { + var source = """ + class TestClass + { + #pragma warning disable MA0051, CS0168 + public void TestMethod() { } + #pragma warning restore MA0051, CS0168 + } + """; + + var diagnostics = await GetDiagnosticsAsync(source); + Assert.Single(diagnostics); + Assert.Equal("CT0011", diagnostics[0].Id); + } + + [Fact] + public async Task PragmaRestoreMA0051ShouldNotTrigger() + { + var source = """ + class TestClass + { + #pragma warning restore MA0051 + public void TestMethod() { } + } + """; + + var diagnostics = await GetDiagnosticsAsync(source); + Assert.Empty(diagnostics); + } + + [Fact] + public async Task PragmaDisableOtherWarningShouldNotTrigger() + { + var source = """ + class TestClass + { + #pragma warning disable CS0168 + public void TestMethod() { } + #pragma warning restore CS0168 + } + """; + + var diagnostics = await GetDiagnosticsAsync(source); + Assert.Empty(diagnostics); + } + + [Fact] + public async Task MultiplePragmaDisableMA0051ShouldTriggerMultipleTimes() + { + var source = """ + class TestClass + { + #pragma warning disable MA0051 + public void TestMethodA() { } + #pragma warning restore MA0051 + #pragma warning disable MA0051 + public void TestMethodB() { } + #pragma warning restore MA0051 + } + """; + + var diagnostics = await GetDiagnosticsAsync(source); + Assert.Equal(2, diagnostics.Length); + Assert.All(diagnostics, d => Assert.Equal("CT0011", d.Id)); + } + + private static async Task GetDiagnosticsAsync(string source) + { + var syntaxTree = CSharpSyntaxTree.ParseText(source, new CSharpParseOptions(LanguageVersion.Latest)); + var references = new List + { + MetadataReference.CreateFromFile(typeof(object).Assembly.Location), + }; + + var compilation = CSharpCompilation.Create( + "TestAssembly", + new[] { syntaxTree }, + references, + new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); + + var analyzer = new PragmaWarningDisableMA0051Analyzer(); + var compilationWithAnalyzers = compilation.WithAnalyzers(ImmutableArray.Create(analyzer)); + + var diagnostics = await compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync(); + return diagnostics.Where(d => d.Id == "CT0011").ToArray(); + } +} \ No newline at end of file