Skip to content

Commit 56b3ffb

Browse files
Fix Missing HandleAsync() Codefix When sealed
1 parent 6c4fe29 commit 56b3ffb

3 files changed

Lines changed: 94 additions & 27 deletions

File tree

src/Immediate.Handlers.CodeFixes/HandlerMethodMustExistCodeFixProvider.cs

Lines changed: 48 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -48,53 +48,77 @@ private static Task<Document> AddHandleAsyncMethodAsync(Document document,
4848
.OfType<RecordDeclarationSyntax>()
4949
.FirstOrDefault(x =>
5050
x.Identifier.Text.EndsWith("Query", StringComparison.Ordinal)
51-
|| x.Identifier.Text.EndsWith("Command", StringComparison.Ordinal));
51+
|| x.Identifier.Text.EndsWith("Command", StringComparison.Ordinal)
52+
);
5253

53-
var methodDeclaration = MethodDeclaration(
54+
var responseType = classDeclarationSyntax.Members
55+
.OfType<RecordDeclarationSyntax>()
56+
.FirstOrDefault(x => x.Identifier.Text.EndsWith("Response", StringComparison.Ordinal));
57+
58+
var methodDeclaration =
59+
MethodDeclaration(
5460
GenericName(
55-
Identifier("ValueTask"))
61+
Identifier("ValueTask")
62+
)
5663
.WithTypeArgumentList(
5764
TypeArgumentList(
5865
SingletonSeparatedList<TypeSyntax>(
59-
PredefinedType(
60-
Token(SyntaxKind.IntKeyword))))),
61-
Identifier("HandleAsync"))
66+
responseType is { }
67+
? IdentifierName(responseType.Identifier.Text)
68+
: PredefinedType(Token(SyntaxKind.IntKeyword))
69+
)
70+
)
71+
),
72+
Identifier("HandleAsync")
73+
)
6274
.WithModifiers(
6375
TokenList(
64-
[
65-
Token(SyntaxKind.PrivateKeyword),
66-
Token(SyntaxKind.StaticKeyword),
67-
]))
76+
classDeclarationSyntax.Modifiers.Any(m => m.IsKind(SyntaxKind.StaticKeyword))
77+
? [Token(SyntaxKind.PrivateKeyword), Token(SyntaxKind.StaticKeyword)]
78+
: [Token(SyntaxKind.PrivateKeyword)]
79+
)
80+
)
6881
.WithParameterList(
6982
ParameterList(
7083
SeparatedList<ParameterSyntax>(
7184
new SyntaxNodeOrToken[]
7285
{
73-
Parameter(
74-
Identifier(
75-
TriviaList(),
76-
SyntaxKind.UnderscoreToken,
77-
"_",
78-
"_",
79-
TriviaList()))
86+
Parameter(Identifier(requestType?.Identifier.Text.ToCamelCase() ?? "_"))
8087
.WithType(
81-
IdentifierName(requestType?.Identifier.Text ?? "object")),
88+
requestType is { }
89+
? IdentifierName(requestType.Identifier.Text)
90+
: PredefinedType(Token(SyntaxKind.ObjectKeyword))
91+
),
92+
8293
Token(SyntaxKind.CommaToken),
83-
Parameter(
84-
Identifier("token"))
94+
95+
Parameter(Identifier("token"))
8596
.WithType(
86-
IdentifierName("CancellationToken")),
87-
})))
97+
IdentifierName("CancellationToken")
98+
),
99+
}
100+
)
101+
)
102+
)
88103
.WithBody(
89104
Block(
90105
SingletonList<StatementSyntax>(
91106
ReturnStatement(
92-
LiteralExpression(
93-
SyntaxKind.DefaultLiteralExpression)))))
107+
LiteralExpression(SyntaxKind.DefaultLiteralExpression)
108+
)
109+
)
110+
)
111+
)
94112
.WithAdditionalAnnotations(Formatter.Annotation);
95113

96114
var newClassDecl = classDeclarationSyntax.AddMembers(methodDeclaration);
97115

98116
return Task.FromResult(document.WithSyntaxRoot(root.ReplaceNode(classDeclarationSyntax, newClassDecl)));
99117
}
100118
}
119+
120+
file static class Extensions
121+
{
122+
public static string ToCamelCase(this string s) =>
123+
char.ToLowerInvariant(s[0]) + s[1..];
124+
}

tests/Immediate.Handlers.Tests/AnalyzerTests/HandlerClassAnalyzerTests/Tests.HandleMethodIsCorrectWithIntReturn.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public static partial class {|IHR0019:GetUsersQuery|}
2424
{
2525
public record Query;
2626
27-
private static ValueTask<int> {|IHR0019:HandleAsync|}(
27+
private static ValueTask<int> HandleAsync(
2828
Query _,
2929
CancellationToken token)
3030
{

tests/Immediate.Handlers.Tests/CodeFixTests/HandlerMethodMustExistCodeFixProviderTests.cs

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ namespace Immediate.Handlers.Tests.CodeFixTests;
88
public sealed partial class HandlerMethodMustExistCodeFixProviderTests
99
{
1010
[Fact]
11-
public async Task HandleMethodDoesNotExist() =>
11+
public async Task HandleMethodDoesNotExistOnStaticClass() =>
1212
await CodeFixTestHelper.CreateCodeFixTest<HandlerClassAnalyzer, HandlerMethodMustExistCodeFixProvider>(
1313
"""
1414
using System;
@@ -41,7 +41,50 @@ public static class {|IHR0019:GetUsersQuery|}
4141
{
4242
public record Query;
4343
44-
private static ValueTask<int> {|IHR0019:HandleAsync|}(Query _, CancellationToken token)
44+
private static ValueTask<int> HandleAsync(Query query, CancellationToken token)
45+
{
46+
return default;
47+
}
48+
}
49+
""",
50+
DriverReferenceAssemblies.Normal
51+
).RunAsync(TestContext.Current.CancellationToken);
52+
53+
[Fact]
54+
public async Task HandleMethodDoesNotExistOnSealedClass() =>
55+
await CodeFixTestHelper.CreateCodeFixTest<HandlerClassAnalyzer, HandlerMethodMustExistCodeFixProvider>(
56+
"""
57+
using System;
58+
using System.Collections.Generic;
59+
using System.IO;
60+
using System.Linq;
61+
using System.Net.Http;
62+
using System.Threading;
63+
using System.Threading.Tasks;
64+
using Immediate.Handlers.Shared;
65+
66+
[Handler]
67+
public sealed class {|IHR0001:GetUsersQuery|}
68+
{
69+
public record Response;
70+
}
71+
""",
72+
"""
73+
using System;
74+
using System.Collections.Generic;
75+
using System.IO;
76+
using System.Linq;
77+
using System.Net.Http;
78+
using System.Threading;
79+
using System.Threading.Tasks;
80+
using Immediate.Handlers.Shared;
81+
82+
[Handler]
83+
public sealed class GetUsersQuery
84+
{
85+
public record Response;
86+
87+
private ValueTask<Response> HandleAsync(object _, CancellationToken token)
4588
{
4689
return default;
4790
}

0 commit comments

Comments
 (0)