Skip to content

Commit cd06055

Browse files
authored
Allow multiple CustomHandler attributes on the same method (#29)
1 parent 9fbaff4 commit cd06055

File tree

3 files changed

+113
-10
lines changed

3 files changed

+113
-10
lines changed

ServiceScan.SourceGenerator.Tests/CustomHandlerTests.cs

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,109 @@ public static partial IServiceCollection ProcessServices(this IServiceCollection
217217
Assert.Equal(expected, results.GeneratedTrees[1].ToString());
218218
}
219219

220+
[Fact]
221+
public void AddMultipleCustomHandlerAttributesWithDifferentCustomHandler()
222+
{
223+
var source = $$"""
224+
using ServiceScan.SourceGenerator;
225+
226+
namespace GeneratorTests;
227+
228+
public static partial class ServicesExtensions
229+
{
230+
[GenerateServiceRegistrations(AssignableTo = typeof(IFirstService), CustomHandler = nameof(HandleFirstType))]
231+
[GenerateServiceRegistrations(AssignableTo = typeof(ISecondService), CustomHandler = nameof(HandleSecondType))]
232+
public static partial void ProcessServices();
233+
234+
private static void HandleFirstType<T>() => System.Console.WriteLine("First:" + typeof(T).Name);
235+
private static void HandleSecondType<T>() => System.Console.WriteLine("Second:" + typeof(T).Name);
236+
}
237+
""";
238+
239+
var services =
240+
"""
241+
namespace GeneratorTests;
242+
243+
public interface IFirstService { }
244+
public interface ISecondService { }
245+
public class MyService1 : IFirstService { }
246+
public class MyService2 : ISecondService { }
247+
""";
248+
249+
var compilation = CreateCompilation(source, services);
250+
251+
var results = CSharpGeneratorDriver
252+
.Create(_generator)
253+
.RunGenerators(compilation)
254+
.GetRunResult();
255+
256+
var expected = $$"""
257+
namespace GeneratorTests;
258+
259+
public static partial class ServicesExtensions
260+
{
261+
public static partial void ProcessServices()
262+
{
263+
HandleFirstType<global::GeneratorTests.MyService1>();
264+
HandleSecondType<global::GeneratorTests.MyService2>();
265+
}
266+
}
267+
""";
268+
Assert.Equal(expected, results.GeneratedTrees[1].ToString());
269+
}
270+
271+
272+
[Fact]
273+
public void AddMultipleCustomHandlerAttributesWithSameCustomHandler()
274+
{
275+
var source = $$"""
276+
using ServiceScan.SourceGenerator;
277+
278+
namespace GeneratorTests;
279+
280+
public static partial class ServicesExtensions
281+
{
282+
[GenerateServiceRegistrations(AssignableTo = typeof(IFirstService), CustomHandler = nameof(HandleType))]
283+
[GenerateServiceRegistrations(AssignableTo = typeof(ISecondService), CustomHandler = nameof(HandleType))]
284+
public static partial void ProcessServices();
285+
286+
private static void HandleType<T>() => System.Console.WriteLine(typeof(T).Name);
287+
}
288+
""";
289+
290+
var services =
291+
"""
292+
namespace GeneratorTests;
293+
294+
public interface IFirstService { }
295+
public interface ISecondService { }
296+
public class MyService1 : IFirstService { }
297+
public class MyService2 : ISecondService { }
298+
""";
299+
300+
var compilation = CreateCompilation(source, services);
301+
302+
var results = CSharpGeneratorDriver
303+
.Create(_generator)
304+
.RunGenerators(compilation)
305+
.GetRunResult();
306+
307+
var expected = $$"""
308+
namespace GeneratorTests;
309+
310+
public static partial class ServicesExtensions
311+
{
312+
public static partial void ProcessServices()
313+
{
314+
HandleType<global::GeneratorTests.MyService1>();
315+
HandleType<global::GeneratorTests.MyService2>();
316+
}
317+
}
318+
""";
319+
Assert.Equal(expected, results.GeneratedTrees[1].ToString());
320+
}
321+
322+
220323
private static Compilation CreateCompilation(params string[] source)
221324
{
222325
var path = Path.GetDirectoryName(typeof(object).Assembly.Location)!;

ServiceScan.SourceGenerator/DependencyInjectionGenerator.ParseMethodModel.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@ public partial class DependencyInjectionGenerator
1616
if (!method.IsPartialDefinition)
1717
return Diagnostic.Create(NotPartialDefinition, method.Locations[0]);
1818

19-
var hasCustomHandler = false;
20-
var attributeData = new AttributeModel[context.Attributes.Length];
19+
var attributeData = context.Attributes.Select(a => AttributeModel.Create(a, method)).ToArray();
20+
var hasCustomHandlers = attributeData.Any(a => a.CustomHandler != null);
21+
2122
for (var i = 0; i < context.Attributes.Length; i++)
2223
{
2324
var attribute = AttributeModel.Create(context.Attributes[i], method);
@@ -26,9 +27,8 @@ public partial class DependencyInjectionGenerator
2627
if (!attribute.HasSearchCriteria)
2728
return Diagnostic.Create(MissingSearchCriteria, attribute.Location);
2829

29-
hasCustomHandler |= attribute.CustomHandler != null;
30-
if (hasCustomHandler && context.Attributes.Length != 1)
31-
return Diagnostic.Create(OnlyOneCustomHandlerAllowed, attribute.Location);
30+
if (hasCustomHandlers && attribute.CustomHandler == null)
31+
return Diagnostic.Create(CantMixRegularAndCustomHandlerRegistrations, attribute.Location);
3232

3333
if (attribute.KeySelector != null)
3434
{
@@ -72,7 +72,7 @@ public partial class DependencyInjectionGenerator
7272
return null;
7373
}
7474

75-
if (!hasCustomHandler)
75+
if (!hasCustomHandlers)
7676
{
7777
var serviceCollectionType = context.SemanticModel.Compilation.GetTypeByMetadataName("Microsoft.Extensions.DependencyInjection.IServiceCollection");
7878

ServiceScan.SourceGenerator/DiagnosticDescriptors.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,9 @@ public static class DiagnosticDescriptors
4646
DiagnosticSeverity.Error,
4747
true);
4848

49-
public static readonly DiagnosticDescriptor OnlyOneCustomHandlerAllowed = new("DI0008",
50-
"Only one GenerateServiceRegistrations attribute is allowed when CustomHandler used",
51-
"Only one GenerateServiceRegistrations attribute is allowed when CustomHandler used",
49+
public static readonly DiagnosticDescriptor CantMixRegularAndCustomHandlerRegistrations = new("DI0008",
50+
"It's not allowed to mix GenerateServiceRegistrations attributes with and without CustomHandler on the same method",
51+
"It's not allowed to mix GenerateServiceRegistrations attributes with and without CustomHandler on the same method",
5252
"Usage",
5353
DiagnosticSeverity.Error,
5454
true);
@@ -69,7 +69,7 @@ public static class DiagnosticDescriptors
6969

7070
public static readonly DiagnosticDescriptor CustomHandlerMethodHasIncorrectSignature = new("DI0011",
7171
"Provided CustomHandler method has incorrect signature",
72-
"CustomHandler method must be generic, and must have the same parameters as the method with an attribute",
72+
"CustomHandler method must be generic, and must have the same parameters as the method with the attribute",
7373
"Usage",
7474
DiagnosticSeverity.Error,
7575
true);

0 commit comments

Comments
 (0)