From d532a15f8aab1edb8710d2af116f16cb9f7dacea Mon Sep 17 00:00:00 2001 From: Stuart Turner Date: Mon, 25 Mar 2024 07:21:24 -0500 Subject: [PATCH] Add diagnostic if `Handle` method is not `private` (#52) --- .../AnalyzerReleases.Shipped.md | 1 + .../DiagnosticIds.cs | 1 + .../HandlerClassAnalyzer.cs | 26 ++++++++++++- .../AnalyzerTests/AnalyzerTestHelpers.cs | 7 +--- ...viorTypeDoesNotHaveTwoGenericParameters.cs | 3 +- ...orTypeDoesNotInheritFromGenericBehavior.cs | 3 +- ...ehaviorTypeDoesNotUseUnboundedReference.cs | 3 +- .../Tests.BehaviorTypeIsUsedMoreThanOnce.cs | 3 +- .../Tests.BehaviorTypeIsValid.cs | 3 +- .../Tests.HandleMethodDoesNotExist.cs | 3 +- .../Tests.HandleMethodDoesNotReturnTask.cs | 3 +- ...ests.HandleMethodIsCorrectWithIntReturn.cs | 3 +- ...sts.HandleMethodIsCorrectWithVoidReturn.cs | 3 +- .../Tests.HandleMethodIsNotPrivate.cs | 37 +++++++++++++++++++ .../Tests.HandleMethodIsNotStatic.cs | 3 +- .../Tests.HandleMethodIsNotUnique.cs | 3 +- .../Tests.HandlerClassNested.cs | 3 +- .../Tests.RenderModeCast.cs | 3 +- .../Tests.RenderModeIsNone.cs | 3 +- .../Tests.RenderModeIsNormal.cs | 3 +- 20 files changed, 80 insertions(+), 37 deletions(-) create mode 100644 tests/Immediate.Handlers.Tests/AnalyzerTests/HandlerClassAnalyzerTests/Tests.HandleMethodIsNotPrivate.cs diff --git a/src/Immediate.Handlers.Analyzers/AnalyzerReleases.Shipped.md b/src/Immediate.Handlers.Analyzers/AnalyzerReleases.Shipped.md index f23652b8..47e15d5b 100644 --- a/src/Immediate.Handlers.Analyzers/AnalyzerReleases.Shipped.md +++ b/src/Immediate.Handlers.Analyzers/AnalyzerReleases.Shipped.md @@ -13,3 +13,4 @@ IHR0007 | ImmediateHandler | Error | BehaviorsAnalyzer IHR0008 | ImmediateHandler | Error | BehaviorsAnalyzer IHR0009 | ImmediateHandler | Error | HandlerClassAnalyzer IHR0010 | ImmediateHandler | Error | HandlerClassAnalyzer +IHR0011 | ImmediateHandler | Error | HandlerClassAnalyzer diff --git a/src/Immediate.Handlers.Analyzers/DiagnosticIds.cs b/src/Immediate.Handlers.Analyzers/DiagnosticIds.cs index 4c259a02..a30f26eb 100644 --- a/src/Immediate.Handlers.Analyzers/DiagnosticIds.cs +++ b/src/Immediate.Handlers.Analyzers/DiagnosticIds.cs @@ -14,4 +14,5 @@ internal static class DiagnosticIds public const string IHR0008BehaviorsMustUseUnboundGenerics = "IHR0008"; public const string IHR0009HandlerMethodMustBeStatic = "IHR0009"; public const string IHR0010HandlerMethodMustBeUnique = "IHR0010"; + public const string IHR0011HandlerMethodMustBePrivate = "IHR0011"; } diff --git a/src/Immediate.Handlers.Analyzers/HandlerClassAnalyzer.cs b/src/Immediate.Handlers.Analyzers/HandlerClassAnalyzer.cs index 2125a099..11d03111 100644 --- a/src/Immediate.Handlers.Analyzers/HandlerClassAnalyzer.cs +++ b/src/Immediate.Handlers.Analyzers/HandlerClassAnalyzer.cs @@ -62,6 +62,17 @@ public sealed class HandlerClassAnalyzer : DiagnosticAnalyzer description: "Static handler method must be static." ); + private static readonly DiagnosticDescriptor HandlerMethodMustBePrivate = + new( + id: DiagnosticIds.IHR0011HandlerMethodMustBePrivate, + title: "Handler method must be private", + messageFormat: "Method '{0}' must not conflict with another static handler method", + category: "ImmediateHandler", + defaultSeverity: DiagnosticSeverity.Error, + isEnabledByDefault: true, + description: "Static handler method must be static." + ); + public override ImmutableArray SupportedDiagnostics { get; } = ImmutableArray.Create( [ @@ -70,6 +81,7 @@ public sealed class HandlerClassAnalyzer : DiagnosticAnalyzer HandlerMustNotBeNestedInAnotherClass, HandlerMethodMustBeStatic, HandlerMethodMustBeUnique, + HandlerMethodMustBePrivate, ]); public override void Initialize(AnalysisContext context) @@ -164,7 +176,19 @@ private static void AnalyzeSymbol(SymbolAnalysisContext context) Diagnostic.Create( HandlerMethodMustReturnTask, methodSymbol.Locations[0], - methodSymbol.Name) + methodSymbol.Name + ) + ); + } + + if (methodSymbol.DeclaredAccessibility is not Accessibility.Private) + { + context.ReportDiagnostic( + Diagnostic.Create( + HandlerMethodMustBePrivate, + methodSymbol.Locations[0], + methodSymbol.Name + ) ); } diff --git a/tests/Immediate.Handlers.Tests/AnalyzerTests/AnalyzerTestHelpers.cs b/tests/Immediate.Handlers.Tests/AnalyzerTests/AnalyzerTestHelpers.cs index 60b3c811..5b46f798 100644 --- a/tests/Immediate.Handlers.Tests/AnalyzerTests/AnalyzerTestHelpers.cs +++ b/tests/Immediate.Handlers.Tests/AnalyzerTests/AnalyzerTestHelpers.cs @@ -9,9 +9,7 @@ public static class AnalyzerTestHelpers { public static CSharpAnalyzerTest CreateAnalyzerTest( string inputSource, - DriverReferenceAssemblies assemblies, - IEnumerable expectedDiagnostics - ) + DriverReferenceAssemblies assemblies) where TAnalyzer : DiagnosticAnalyzer, new() { var csTest = new CSharpAnalyzerTest @@ -31,9 +29,6 @@ IEnumerable expectedDiagnostics csTest.TestState.AdditionalReferences .AddRange(assemblies.GetAdditionalReferences()); - csTest.TestState.ExpectedDiagnostics - .AddRange(expectedDiagnostics); - return csTest; } } diff --git a/tests/Immediate.Handlers.Tests/AnalyzerTests/BehaviorAnalyzerTests/Tests.BehaviorTypeDoesNotHaveTwoGenericParameters.cs b/tests/Immediate.Handlers.Tests/AnalyzerTests/BehaviorAnalyzerTests/Tests.BehaviorTypeDoesNotHaveTwoGenericParameters.cs index f6ac74c7..966bc995 100644 --- a/tests/Immediate.Handlers.Tests/AnalyzerTests/BehaviorAnalyzerTests/Tests.BehaviorTypeDoesNotHaveTwoGenericParameters.cs +++ b/tests/Immediate.Handlers.Tests/AnalyzerTests/BehaviorAnalyzerTests/Tests.BehaviorTypeDoesNotHaveTwoGenericParameters.cs @@ -72,7 +72,6 @@ private static ValueTask> HandleAsync( } } """, - DriverReferenceAssemblies.Normal, - [] + DriverReferenceAssemblies.Normal ).RunAsync(); } diff --git a/tests/Immediate.Handlers.Tests/AnalyzerTests/BehaviorAnalyzerTests/Tests.BehaviorTypeDoesNotInheritFromGenericBehavior.cs b/tests/Immediate.Handlers.Tests/AnalyzerTests/BehaviorAnalyzerTests/Tests.BehaviorTypeDoesNotInheritFromGenericBehavior.cs index 65720b98..692f72df 100644 --- a/tests/Immediate.Handlers.Tests/AnalyzerTests/BehaviorAnalyzerTests/Tests.BehaviorTypeDoesNotInheritFromGenericBehavior.cs +++ b/tests/Immediate.Handlers.Tests/AnalyzerTests/BehaviorAnalyzerTests/Tests.BehaviorTypeDoesNotInheritFromGenericBehavior.cs @@ -71,7 +71,6 @@ private static ValueTask> HandleAsync( } } """, - DriverReferenceAssemblies.Normal, - [] + DriverReferenceAssemblies.Normal ).RunAsync(); } diff --git a/tests/Immediate.Handlers.Tests/AnalyzerTests/BehaviorAnalyzerTests/Tests.BehaviorTypeDoesNotUseUnboundedReference.cs b/tests/Immediate.Handlers.Tests/AnalyzerTests/BehaviorAnalyzerTests/Tests.BehaviorTypeDoesNotUseUnboundedReference.cs index c0382784..c4cb13dd 100644 --- a/tests/Immediate.Handlers.Tests/AnalyzerTests/BehaviorAnalyzerTests/Tests.BehaviorTypeDoesNotUseUnboundedReference.cs +++ b/tests/Immediate.Handlers.Tests/AnalyzerTests/BehaviorAnalyzerTests/Tests.BehaviorTypeDoesNotUseUnboundedReference.cs @@ -68,7 +68,6 @@ private static ValueTask> HandleAsync( } } """, - DriverReferenceAssemblies.Normal, - [] + DriverReferenceAssemblies.Normal ).RunAsync(); } diff --git a/tests/Immediate.Handlers.Tests/AnalyzerTests/BehaviorAnalyzerTests/Tests.BehaviorTypeIsUsedMoreThanOnce.cs b/tests/Immediate.Handlers.Tests/AnalyzerTests/BehaviorAnalyzerTests/Tests.BehaviorTypeIsUsedMoreThanOnce.cs index 42b0b4f9..09e27a95 100644 --- a/tests/Immediate.Handlers.Tests/AnalyzerTests/BehaviorAnalyzerTests/Tests.BehaviorTypeIsUsedMoreThanOnce.cs +++ b/tests/Immediate.Handlers.Tests/AnalyzerTests/BehaviorAnalyzerTests/Tests.BehaviorTypeIsUsedMoreThanOnce.cs @@ -70,7 +70,6 @@ private static ValueTask> HandleAsync( } } """, - DriverReferenceAssemblies.Normal, - [] + DriverReferenceAssemblies.Normal ).RunAsync(); } diff --git a/tests/Immediate.Handlers.Tests/AnalyzerTests/BehaviorAnalyzerTests/Tests.BehaviorTypeIsValid.cs b/tests/Immediate.Handlers.Tests/AnalyzerTests/BehaviorAnalyzerTests/Tests.BehaviorTypeIsValid.cs index 0f6317a8..b264d65b 100644 --- a/tests/Immediate.Handlers.Tests/AnalyzerTests/BehaviorAnalyzerTests/Tests.BehaviorTypeIsValid.cs +++ b/tests/Immediate.Handlers.Tests/AnalyzerTests/BehaviorAnalyzerTests/Tests.BehaviorTypeIsValid.cs @@ -79,7 +79,6 @@ private static ValueTask> HandleAsync( } } """, - DriverReferenceAssemblies.Normal, - [] + DriverReferenceAssemblies.Normal ).RunAsync(); } diff --git a/tests/Immediate.Handlers.Tests/AnalyzerTests/HandlerClassAnalyzerTests/Tests.HandleMethodDoesNotExist.cs b/tests/Immediate.Handlers.Tests/AnalyzerTests/HandlerClassAnalyzerTests/Tests.HandleMethodDoesNotExist.cs index 57f313dd..9ccc141c 100644 --- a/tests/Immediate.Handlers.Tests/AnalyzerTests/HandlerClassAnalyzerTests/Tests.HandleMethodDoesNotExist.cs +++ b/tests/Immediate.Handlers.Tests/AnalyzerTests/HandlerClassAnalyzerTests/Tests.HandleMethodDoesNotExist.cs @@ -25,7 +25,6 @@ public static class {|IHR0001:GetUsersQuery|} public record Query; } """, - DriverReferenceAssemblies.Normal, - [] + DriverReferenceAssemblies.Normal ).RunAsync(); } diff --git a/tests/Immediate.Handlers.Tests/AnalyzerTests/HandlerClassAnalyzerTests/Tests.HandleMethodDoesNotReturnTask.cs b/tests/Immediate.Handlers.Tests/AnalyzerTests/HandlerClassAnalyzerTests/Tests.HandleMethodDoesNotReturnTask.cs index 7ea8dde8..422d5fa1 100644 --- a/tests/Immediate.Handlers.Tests/AnalyzerTests/HandlerClassAnalyzerTests/Tests.HandleMethodDoesNotReturnTask.cs +++ b/tests/Immediate.Handlers.Tests/AnalyzerTests/HandlerClassAnalyzerTests/Tests.HandleMethodDoesNotReturnTask.cs @@ -45,7 +45,6 @@ public ValueTask> GetUsers() public interface ILogger; """, - DriverReferenceAssemblies.Normal, - [] + DriverReferenceAssemblies.Normal ).RunAsync(); } diff --git a/tests/Immediate.Handlers.Tests/AnalyzerTests/HandlerClassAnalyzerTests/Tests.HandleMethodIsCorrectWithIntReturn.cs b/tests/Immediate.Handlers.Tests/AnalyzerTests/HandlerClassAnalyzerTests/Tests.HandleMethodIsCorrectWithIntReturn.cs index 6c10c530..f772ea69 100644 --- a/tests/Immediate.Handlers.Tests/AnalyzerTests/HandlerClassAnalyzerTests/Tests.HandleMethodIsCorrectWithIntReturn.cs +++ b/tests/Immediate.Handlers.Tests/AnalyzerTests/HandlerClassAnalyzerTests/Tests.HandleMethodIsCorrectWithIntReturn.cs @@ -39,7 +39,6 @@ private ValueTask Handle( } } """, - DriverReferenceAssemblies.Normal, - [] + DriverReferenceAssemblies.Normal ).RunAsync(); } diff --git a/tests/Immediate.Handlers.Tests/AnalyzerTests/HandlerClassAnalyzerTests/Tests.HandleMethodIsCorrectWithVoidReturn.cs b/tests/Immediate.Handlers.Tests/AnalyzerTests/HandlerClassAnalyzerTests/Tests.HandleMethodIsCorrectWithVoidReturn.cs index 13cfcbc0..d8f1f663 100644 --- a/tests/Immediate.Handlers.Tests/AnalyzerTests/HandlerClassAnalyzerTests/Tests.HandleMethodIsCorrectWithVoidReturn.cs +++ b/tests/Immediate.Handlers.Tests/AnalyzerTests/HandlerClassAnalyzerTests/Tests.HandleMethodIsCorrectWithVoidReturn.cs @@ -37,7 +37,6 @@ private async ValueTask Handle( } } """, - DriverReferenceAssemblies.Normal, - [] + DriverReferenceAssemblies.Normal ).RunAsync(); } diff --git a/tests/Immediate.Handlers.Tests/AnalyzerTests/HandlerClassAnalyzerTests/Tests.HandleMethodIsNotPrivate.cs b/tests/Immediate.Handlers.Tests/AnalyzerTests/HandlerClassAnalyzerTests/Tests.HandleMethodIsNotPrivate.cs new file mode 100644 index 00000000..64a9e535 --- /dev/null +++ b/tests/Immediate.Handlers.Tests/AnalyzerTests/HandlerClassAnalyzerTests/Tests.HandleMethodIsNotPrivate.cs @@ -0,0 +1,37 @@ +using Immediate.Handlers.Analyzers; +using Immediate.Handlers.Tests.Helpers; + +namespace Immediate.Handlers.Tests.AnalyzerTests.HandlerClassAnalyzerTests; + +[System.Diagnostics.CodeAnalysis.SuppressMessage("Naming", "CA1724:Type names should not match namespaces", Justification = "Not being consumed by other code")] +public partial class Tests +{ + [Fact] + public async Task HandleMethodIsNotPrivate_AlertDiagnostic() => + await AnalyzerTestHelpers.CreateAnalyzerTest( + """ + using System; + using System.Collections.Generic; + using System.IO; + using System.Linq; + using System.Net.Http; + using System.Threading; + using System.Threading.Tasks; + using Immediate.Handlers.Shared; + + [Handler] + public class GetUsersQuery + { + public record Query; + + public static ValueTask {|IHR0011:HandleAsync|}( + Query _, + CancellationToken token) + { + return ValueTask.FromResult(0); + } + } + """, + DriverReferenceAssemblies.Normal + ).RunAsync(); +} diff --git a/tests/Immediate.Handlers.Tests/AnalyzerTests/HandlerClassAnalyzerTests/Tests.HandleMethodIsNotStatic.cs b/tests/Immediate.Handlers.Tests/AnalyzerTests/HandlerClassAnalyzerTests/Tests.HandleMethodIsNotStatic.cs index 600acf49..17ae8467 100644 --- a/tests/Immediate.Handlers.Tests/AnalyzerTests/HandlerClassAnalyzerTests/Tests.HandleMethodIsNotStatic.cs +++ b/tests/Immediate.Handlers.Tests/AnalyzerTests/HandlerClassAnalyzerTests/Tests.HandleMethodIsNotStatic.cs @@ -53,7 +53,6 @@ public ValueTask> GetUsers() public interface ILogger; """, - DriverReferenceAssemblies.Normal, - [] + DriverReferenceAssemblies.Normal ).RunAsync(); } diff --git a/tests/Immediate.Handlers.Tests/AnalyzerTests/HandlerClassAnalyzerTests/Tests.HandleMethodIsNotUnique.cs b/tests/Immediate.Handlers.Tests/AnalyzerTests/HandlerClassAnalyzerTests/Tests.HandleMethodIsNotUnique.cs index c44c508c..52767f34 100644 --- a/tests/Immediate.Handlers.Tests/AnalyzerTests/HandlerClassAnalyzerTests/Tests.HandleMethodIsNotUnique.cs +++ b/tests/Immediate.Handlers.Tests/AnalyzerTests/HandlerClassAnalyzerTests/Tests.HandleMethodIsNotUnique.cs @@ -39,7 +39,6 @@ public record Query; } } """, - DriverReferenceAssemblies.Normal, - [] + DriverReferenceAssemblies.Normal ).RunAsync(); } diff --git a/tests/Immediate.Handlers.Tests/AnalyzerTests/HandlerClassAnalyzerTests/Tests.HandlerClassNested.cs b/tests/Immediate.Handlers.Tests/AnalyzerTests/HandlerClassAnalyzerTests/Tests.HandlerClassNested.cs index 57ecd2fc..995510d5 100644 --- a/tests/Immediate.Handlers.Tests/AnalyzerTests/HandlerClassAnalyzerTests/Tests.HandlerClassNested.cs +++ b/tests/Immediate.Handlers.Tests/AnalyzerTests/HandlerClassAnalyzerTests/Tests.HandlerClassNested.cs @@ -33,7 +33,6 @@ private static ValueTask HandleAsync( } } """, - DriverReferenceAssemblies.Normal, - [] + DriverReferenceAssemblies.Normal ).RunAsync(); } diff --git a/tests/Immediate.Handlers.Tests/AnalyzerTests/RenderModeAnalyzerTests/Tests.RenderModeCast.cs b/tests/Immediate.Handlers.Tests/AnalyzerTests/RenderModeAnalyzerTests/Tests.RenderModeCast.cs index 8de498ac..c2b3a63b 100644 --- a/tests/Immediate.Handlers.Tests/AnalyzerTests/RenderModeAnalyzerTests/Tests.RenderModeCast.cs +++ b/tests/Immediate.Handlers.Tests/AnalyzerTests/RenderModeAnalyzerTests/Tests.RenderModeCast.cs @@ -35,7 +35,6 @@ private static ValueTask HandleAsync( } } """, - DriverReferenceAssemblies.Normal, - [] + DriverReferenceAssemblies.Normal ).RunAsync(); } diff --git a/tests/Immediate.Handlers.Tests/AnalyzerTests/RenderModeAnalyzerTests/Tests.RenderModeIsNone.cs b/tests/Immediate.Handlers.Tests/AnalyzerTests/RenderModeAnalyzerTests/Tests.RenderModeIsNone.cs index cb8d118f..fbf8e5bc 100644 --- a/tests/Immediate.Handlers.Tests/AnalyzerTests/RenderModeAnalyzerTests/Tests.RenderModeIsNone.cs +++ b/tests/Immediate.Handlers.Tests/AnalyzerTests/RenderModeAnalyzerTests/Tests.RenderModeIsNone.cs @@ -35,7 +35,6 @@ private static ValueTask HandleAsync( } } """, - DriverReferenceAssemblies.Normal, - [] + DriverReferenceAssemblies.Normal ).RunAsync(); } diff --git a/tests/Immediate.Handlers.Tests/AnalyzerTests/RenderModeAnalyzerTests/Tests.RenderModeIsNormal.cs b/tests/Immediate.Handlers.Tests/AnalyzerTests/RenderModeAnalyzerTests/Tests.RenderModeIsNormal.cs index 6e3fe6c3..6872759b 100644 --- a/tests/Immediate.Handlers.Tests/AnalyzerTests/RenderModeAnalyzerTests/Tests.RenderModeIsNormal.cs +++ b/tests/Immediate.Handlers.Tests/AnalyzerTests/RenderModeAnalyzerTests/Tests.RenderModeIsNormal.cs @@ -35,7 +35,6 @@ private static ValueTask HandleAsync( } } """, - DriverReferenceAssemblies.Normal, - [] + DriverReferenceAssemblies.Normal ).RunAsync(); }