From 4de0329a4eae525a78202c4d1ce98ce66804ab47 Mon Sep 17 00:00:00 2001 From: Samuel Meenzen Date: Mon, 12 Jun 2023 20:56:26 +0200 Subject: [PATCH 1/5] feat: create Stl.Analyzers project --- Stl.Fusion.sln | 7 +++++++ src/Directory.Build.props | 2 +- src/Stl.Analyzers/Stl.Analyzers.csproj | 16 ++++++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 src/Stl.Analyzers/Stl.Analyzers.csproj diff --git a/Stl.Fusion.sln b/Stl.Fusion.sln index 1151d75a1..b308b3265 100644 --- a/Stl.Fusion.sln +++ b/Stl.Fusion.sln @@ -105,6 +105,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Stl.Rpc.Server", "src\Stl.R EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Stl.Rpc.Server.NetFx", "src\Stl.Rpc.Server.NetFx\Stl.Rpc.Server.NetFx.csproj", "{5EA29C97-FB87-4001-BD8E-D12917D3C21A}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Stl.Analyzers", "src\Stl.Analyzers\Stl.Analyzers.csproj", "{A36C2D5F-65EA-4170-ABE4-7CD9A15B381E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -241,6 +243,10 @@ Global {5EA29C97-FB87-4001-BD8E-D12917D3C21A}.Debug|Any CPU.Build.0 = Debug|Any CPU {5EA29C97-FB87-4001-BD8E-D12917D3C21A}.Release|Any CPU.ActiveCfg = Release|Any CPU {5EA29C97-FB87-4001-BD8E-D12917D3C21A}.Release|Any CPU.Build.0 = Release|Any CPU + {A36C2D5F-65EA-4170-ABE4-7CD9A15B381E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A36C2D5F-65EA-4170-ABE4-7CD9A15B381E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A36C2D5F-65EA-4170-ABE4-7CD9A15B381E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A36C2D5F-65EA-4170-ABE4-7CD9A15B381E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -280,6 +286,7 @@ Global {68AEF45C-5DE6-41F0-8D97-1DF5FC27F1D3} = {A50B98CF-9AA1-4622-B2AD-5E17610115A7} {5BBF576B-FE92-4821-9617-79003001A9E1} = {A50B98CF-9AA1-4622-B2AD-5E17610115A7} {5EA29C97-FB87-4001-BD8E-D12917D3C21A} = {A50B98CF-9AA1-4622-B2AD-5E17610115A7} + {A36C2D5F-65EA-4170-ABE4-7CD9A15B381E} = {A50B98CF-9AA1-4622-B2AD-5E17610115A7} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {B50610D6-2B28-4258-98A2-A0B486FD5907} diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 400fa24e9..a3b19d322 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -49,7 +49,7 @@ - + diff --git a/src/Stl.Analyzers/Stl.Analyzers.csproj b/src/Stl.Analyzers/Stl.Analyzers.csproj new file mode 100644 index 000000000..af298d400 --- /dev/null +++ b/src/Stl.Analyzers/Stl.Analyzers.csproj @@ -0,0 +1,16 @@ + + + + netstandard2.0;net7.0 + enable + enable + true + Stl.Analyzers - Roslyn analyzers for common issues. + + + + + + + + From 4a9a11aa53c35ee61e07b29df23ad89f5a9ce2af Mon Sep 17 00:00:00 2001 From: Samuel Meenzen Date: Mon, 12 Jun 2023 20:57:23 +0200 Subject: [PATCH 2/5] feat: add analyzer for direct command handler calls --- src/Stl.Analyzers/CommandHandlerAnalyzer.cs | 81 +++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 src/Stl.Analyzers/CommandHandlerAnalyzer.cs diff --git a/src/Stl.Analyzers/CommandHandlerAnalyzer.cs b/src/Stl.Analyzers/CommandHandlerAnalyzer.cs new file mode 100644 index 000000000..8bcf14243 --- /dev/null +++ b/src/Stl.Analyzers/CommandHandlerAnalyzer.cs @@ -0,0 +1,81 @@ +using System.Collections.Immutable; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; + +namespace Stl.Analyzers; + +[DiagnosticAnalyzer(LanguageNames.CSharp)] +public class CommandHandlerAnalyzer : DiagnosticAnalyzer +{ + private static readonly DiagnosticDescriptor DirectCallDiagnostic = + new( + "STL0001", + "Invalid command handler call", + "Direct command handler calls on command service proxies are not allowed", + "Test", + DiagnosticSeverity.Error, + isEnabledByDefault: true + ); + + public override ImmutableArray SupportedDiagnostics { get; } = + ImmutableArray.Create(DirectCallDiagnostic); + + public override void Initialize(AnalysisContext context) + { + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); + context.EnableConcurrentExecution(); + + context.RegisterSyntaxNodeAction(CheckCommandHandler, SyntaxKind.InvocationExpression); + } + + private void CheckCommandHandler(SyntaxNodeAnalysisContext context) + { + // check if the called method has the CommandHandler attribute + + if (context.Node is not InvocationExpressionSyntax invocation) + { + return; + } + + var methodSymbol = context.SemanticModel.GetSymbolInfo(invocation).Symbol as IMethodSymbol; + + if (methodSymbol == null) + { + return; + } + + var syntaxReference = methodSymbol.DeclaringSyntaxReferences.FirstOrDefault(); + + if (syntaxReference == null) + { + return; + } + + SyntaxNode declaration = syntaxReference.GetSyntax(context.CancellationToken); + + if (declaration is not MethodDeclarationSyntax method) + { + return; + } + + bool isCommandHandler = method.AttributeLists + .SelectMany(x => x.Attributes) + .Any( + attribute => + string.Equals( + attribute.Name.ToString(), + "CommandHandler", + StringComparison.Ordinal + ) + ); + + if (!isCommandHandler) + return; + + var diagnostic = Diagnostic.Create(DirectCallDiagnostic, context.Node.GetLocation()); + + context.ReportDiagnostic(diagnostic); + } +} From e82c92def440627791fe13391f12c3bd1c4ef464 Mon Sep 17 00:00:00 2001 From: Samuel Meenzen Date: Wed, 14 Jun 2023 10:35:46 +0200 Subject: [PATCH 3/5] chore: minor code style adjustments --- src/Stl.Analyzers/CommandHandlerAnalyzer.cs | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/src/Stl.Analyzers/CommandHandlerAnalyzer.cs b/src/Stl.Analyzers/CommandHandlerAnalyzer.cs index 8bcf14243..f62dc203b 100644 --- a/src/Stl.Analyzers/CommandHandlerAnalyzer.cs +++ b/src/Stl.Analyzers/CommandHandlerAnalyzer.cs @@ -15,7 +15,7 @@ public class CommandHandlerAnalyzer : DiagnosticAnalyzer "Invalid command handler call", "Direct command handler calls on command service proxies are not allowed", "Test", - DiagnosticSeverity.Error, + DiagnosticSeverity.Warning, isEnabledByDefault: true ); @@ -32,34 +32,24 @@ public override void Initialize(AnalysisContext context) private void CheckCommandHandler(SyntaxNodeAnalysisContext context) { - // check if the called method has the CommandHandler attribute - if (context.Node is not InvocationExpressionSyntax invocation) - { return; - } - var methodSymbol = context.SemanticModel.GetSymbolInfo(invocation).Symbol as IMethodSymbol; - - if (methodSymbol == null) - { + if (context.SemanticModel.GetSymbolInfo(invocation, cancellationToken: context.CancellationToken).Symbol is not IMethodSymbol methodSymbol) return; - } var syntaxReference = methodSymbol.DeclaringSyntaxReferences.FirstOrDefault(); - if (syntaxReference == null) - { + if (syntaxReference is null) return; - } SyntaxNode declaration = syntaxReference.GetSyntax(context.CancellationToken); if (declaration is not MethodDeclarationSyntax method) - { return; - } + // check if the called method has the CommandHandler attribute + // this is a very naive implementation, the namespace should be checked as well bool isCommandHandler = method.AttributeLists .SelectMany(x => x.Attributes) .Any( From c4f0128c288ec73b366968f831af4a5e79a5661b Mon Sep 17 00:00:00 2001 From: Samuel Meenzen Date: Fri, 18 Aug 2023 15:06:08 +0200 Subject: [PATCH 4/5] feat: use STLC prefix for analyzer --- src/Stl.Analyzers/CommandHandlerAnalyzer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Stl.Analyzers/CommandHandlerAnalyzer.cs b/src/Stl.Analyzers/CommandHandlerAnalyzer.cs index f62dc203b..a50af0287 100644 --- a/src/Stl.Analyzers/CommandHandlerAnalyzer.cs +++ b/src/Stl.Analyzers/CommandHandlerAnalyzer.cs @@ -11,7 +11,7 @@ public class CommandHandlerAnalyzer : DiagnosticAnalyzer { private static readonly DiagnosticDescriptor DirectCallDiagnostic = new( - "STL0001", + "STLC0001", "Invalid command handler call", "Direct command handler calls on command service proxies are not allowed", "Test", From 94baa6b14343048523054ee87d3231071ff03e2e Mon Sep 17 00:00:00 2001 From: Samuel Meenzen Date: Fri, 18 Aug 2023 15:07:30 +0200 Subject: [PATCH 5/5] feat: enable analyzer for generated code --- src/Stl.Analyzers/CommandHandlerAnalyzer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Stl.Analyzers/CommandHandlerAnalyzer.cs b/src/Stl.Analyzers/CommandHandlerAnalyzer.cs index a50af0287..065a1a6d9 100644 --- a/src/Stl.Analyzers/CommandHandlerAnalyzer.cs +++ b/src/Stl.Analyzers/CommandHandlerAnalyzer.cs @@ -24,7 +24,7 @@ public class CommandHandlerAnalyzer : DiagnosticAnalyzer public override void Initialize(AnalysisContext context) { - context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); context.EnableConcurrentExecution(); context.RegisterSyntaxNodeAction(CheckCommandHandler, SyntaxKind.InvocationExpression);