From fc7a9d69e31644ee3dfba76ee6ce5f3145df2f4b Mon Sep 17 00:00:00 2001 From: Duke Date: Mon, 8 Jan 2024 16:46:45 +0100 Subject: [PATCH] Fix codefix test --- .../HandlerClassCodeFixProvider.cs | 79 ++++++++++++++++++- .../CodeFixTests/CodeFixTestHelper.cs | 7 +- .../Tests.HandleMethodDoesNotExist.cs} | 31 +++++--- 3 files changed, 101 insertions(+), 16 deletions(-) rename tests/Immediate.Handlers.Tests/CodeFixTests/{HandlerClassCodeFixTests.cs => HandlerClassCodeFixTests/Tests.HandleMethodDoesNotExist.cs} (61%) diff --git a/src/Immediate.Handlers.CodeFixes/HandlerClassCodeFixProvider.cs b/src/Immediate.Handlers.CodeFixes/HandlerClassCodeFixProvider.cs index f689e6b9..95ccf0d3 100644 --- a/src/Immediate.Handlers.CodeFixes/HandlerClassCodeFixProvider.cs +++ b/src/Immediate.Handlers.CodeFixes/HandlerClassCodeFixProvider.cs @@ -1,5 +1,11 @@ using System.Collections.Immutable; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Formatting; +using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; +using SyntaxKind = Microsoft.CodeAnalysis.CSharp.SyntaxKind; namespace Immediate.Handlers.CodeFixes; @@ -9,8 +15,77 @@ public class HandlerClassCodeFixProvider : CodeFixProvider public override FixAllProvider? GetFixAllProvider() => null; - public override Task RegisterCodeFixesAsync(CodeFixContext context) + public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { - throw new NotImplementedException(); + // We link only one diagnostic and assume there is only one diagnostic in the context. + var diagnostic = context.Diagnostics.Single(); + + // 'SourceSpan' of 'Location' is the highlighted area. We're going to use this area to find the 'SyntaxNode' to rename. + var diagnosticSpan = diagnostic.Location.SourceSpan; + + var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); + + if (root?.FindNode(diagnosticSpan) is ClassDeclarationSyntax classDeclarationSyntax) + { + context.RegisterCodeFix( + CodeAction.Create( + title: "Add HandleAsync method", + createChangedDocument: _ => AddHandleAsyncMethodAsync(context.Document, root, classDeclarationSyntax), + equivalenceKey: nameof(HandlerClassCodeFixProvider) + ), + diagnostic); + } + } + + private static Task AddHandleAsyncMethodAsync(Document document, + SyntaxNode root, + ClassDeclarationSyntax classDeclarationSyntax) + { + var methodDeclaration = MethodDeclaration( + GenericName( + Identifier("Task")) + .WithTypeArgumentList( + TypeArgumentList( + SingletonSeparatedList( + PredefinedType( + Token(SyntaxKind.IntKeyword))))), + Identifier("HandleAsync")) + .WithModifiers( + TokenList( + [ + Token(SyntaxKind.PrivateKeyword), + Token(SyntaxKind.StaticKeyword), + ])) + .WithParameterList( + ParameterList( + SeparatedList( + new SyntaxNodeOrToken[] + { + Parameter( + Identifier( + TriviaList(), + SyntaxKind.UnderscoreToken, + "_", + "_", + TriviaList())) + .WithType( + IdentifierName("Query")), + Token(SyntaxKind.CommaToken), + Parameter( + Identifier("token")) + .WithType( + IdentifierName("CancellationToken")), + }))) + .WithBody( + Block( + SingletonList( + ReturnStatement( + LiteralExpression( + SyntaxKind.NullLiteralExpression))))) + .WithAdditionalAnnotations(Formatter.Annotation); + + var newClassDecl = classDeclarationSyntax.AddMembers(methodDeclaration); + + return Task.FromResult(document.WithSyntaxRoot(root.ReplaceNode(classDeclarationSyntax, newClassDecl))); } } diff --git a/tests/Immediate.Handlers.Tests/CodeFixTests/CodeFixTestHelper.cs b/tests/Immediate.Handlers.Tests/CodeFixTests/CodeFixTestHelper.cs index 72512f57..2f3f8c18 100644 --- a/tests/Immediate.Handlers.Tests/CodeFixTests/CodeFixTestHelper.cs +++ b/tests/Immediate.Handlers.Tests/CodeFixTests/CodeFixTestHelper.cs @@ -12,8 +12,8 @@ public static CSharpCodeFixTest CreateCode string inputSource, string fixedSource, DriverReferenceAssemblies assemblies, - IEnumerable expectedDiagnostics - ) + IEnumerable expectedDiagnostics, + IEnumerable expectedFixedDiagnostics) where TAnalyzer : DiagnosticAnalyzer, new() where TCodeFix : CodeFixProvider, new() { @@ -35,6 +35,9 @@ IEnumerable expectedDiagnostics csTest.TestState.ExpectedDiagnostics .AddRange(expectedDiagnostics); + csTest.FixedState.ExpectedDiagnostics + .AddRange(expectedFixedDiagnostics); + return csTest; } diff --git a/tests/Immediate.Handlers.Tests/CodeFixTests/HandlerClassCodeFixTests.cs b/tests/Immediate.Handlers.Tests/CodeFixTests/HandlerClassCodeFixTests/Tests.HandleMethodDoesNotExist.cs similarity index 61% rename from tests/Immediate.Handlers.Tests/CodeFixTests/HandlerClassCodeFixTests.cs rename to tests/Immediate.Handlers.Tests/CodeFixTests/HandlerClassCodeFixTests/Tests.HandleMethodDoesNotExist.cs index 63a06783..5c051d62 100644 --- a/tests/Immediate.Handlers.Tests/CodeFixTests/HandlerClassCodeFixTests.cs +++ b/tests/Immediate.Handlers.Tests/CodeFixTests/HandlerClassCodeFixTests/Tests.HandleMethodDoesNotExist.cs @@ -5,12 +5,13 @@ Immediate.Handlers.Analyzers.HandlerClassAnalyzer, Immediate.Handlers.CodeFixes.HandlerClassCodeFixProvider>; -namespace Immediate.Handlers.Tests.CodeFixTests; +namespace Immediate.Handlers.Tests.CodeFixTests.HandlerClassCodeFixTests; -public class HandlerClassCodeFixTests +[System.Diagnostics.CodeAnalysis.SuppressMessage("Naming", "CA1724:Type names should not match namespaces", Justification = "Not being consumed by other code")] +public class Tests { [Fact] - public async Task CodeFixTest() + public async Task HandleMethodDoesNotExist() { var input = @" using System; @@ -21,6 +22,7 @@ public async Task CodeFixTest() using System.Threading; using System.Threading.Tasks; using Immediate.Handlers.Shared; + [Handler] public static class GetUsersQuery { @@ -35,20 +37,25 @@ public record Query; using System.Threading; using System.Threading.Tasks; using Immediate.Handlers.Shared; + [Handler] public static class GetUsersQuery { public record Query; - private static Task HandleAsync( - Query _, - CancellationToken token) - { - return null; - } -} -"; - var test = CodeFixTestHelper.CreateCodeFixTest(input, fixedSource, DriverReferenceAssemblies.Normal, [Verifier.Diagnostic("IH0001")]); + private static Task HandleAsync(Query _, CancellationToken token) + { + return null; + } +}"; + + var expected = Verifier.Diagnostic("IH0001") + .WithLocation(12, 21) + .WithArguments("GetUsersQuery"); + + //var expectedFixed = DiagnosticResult.CompilerError("CS7003").WithSpan(15, 17, 15, 23); + + var test = CodeFixTestHelper.CreateCodeFixTest(input, fixedSource, DriverReferenceAssemblies.Normal, [expected], []); await test.RunAsync(); }