Skip to content

Commit a30bae3

Browse files
committed
Add diagnostic for missing mapping method name
1 parent a00b3a5 commit a30bae3

File tree

1 file changed

+53
-2
lines changed

1 file changed

+53
-2
lines changed

src/Linqraft.SourceGenerator/SelectExprGenerator.cs

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,16 @@ public partial class SelectExprGenerator : IIncrementalGenerator
1919
// Fully qualified metadata name for the LinqraftMappingGenerateAttribute
2020
private const string LinqraftMappingGenerateAttributeFullName =
2121
"Linqraft.LinqraftMappingGenerateAttribute";
22+
private const string MappingGenerateMethodNameMissingDiagnosticId = "LINQRAFT001";
23+
private static readonly DiagnosticDescriptor MappingGenerateMethodNameMissingDescriptor =
24+
new(
25+
MappingGenerateMethodNameMissingDiagnosticId,
26+
"LinqraftMappingGenerate requires a method name",
27+
"Method '{0}' must specify a mapping method name. Use [LinqraftMappingGenerate(\"MethodName\")] on methods.",
28+
"Linqraft",
29+
DiagnosticSeverity.Error,
30+
isEnabledByDefault: true
31+
);
2232

2333
/// <summary>
2434
/// Initialize the generator
@@ -55,6 +65,14 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
5565
)
5666
.Where(static info => info is not null)
5767
.Collect();
68+
var mappingMethodDiagnostics = context
69+
.SyntaxProvider.ForAttributeWithMetadataName(
70+
fullyQualifiedMetadataName: LinqraftMappingGenerateAttributeFullName,
71+
predicate: static (node, _) => node is MethodDeclarationSyntax,
72+
transform: static (ctx, _) => GetMappingMethodDiagnostic(ctx)
73+
)
74+
.Where(static diag => diag is not null)
75+
.Collect();
5876

5977
// Provider to detect classes that inherit from LinqraftMappingDeclare<T>
6078
// Using ForAttributeWithMetadataName for performance - now requires [LinqraftMappingGenerate] attribute
@@ -71,18 +89,25 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
7189
var invocationsWithConfig = invocations.Combine(configurationProvider);
7290
var mappingMethodsWithConfig = mappingMethods.Combine(configurationProvider);
7391
var mappingDeclareClassesWithConfig = mappingDeclareClasses.Combine(configurationProvider);
92+
var mappingMethodDiagnosticsWithConfig = mappingMethodDiagnostics.Combine(
93+
configurationProvider
94+
);
7495

7596
// Combine all providers
7697
var combinedData = invocationsWithConfig
7798
.Combine(mappingMethodsWithConfig)
78-
.Combine(mappingDeclareClassesWithConfig);
99+
.Combine(mappingDeclareClassesWithConfig)
100+
.Combine(mappingMethodDiagnosticsWithConfig);
79101

80102
// Code generation
81103
context.RegisterSourceOutput(
82104
combinedData,
83105
(spc, data) =>
84106
{
85-
var (((infos, config), (mappingInfos, _)), (mappingDeclareInfos, _)) = data;
107+
var (
108+
(((infos, config), (mappingInfos, _)), (mappingDeclareInfos, _)),
109+
(mappingDiagnostics, _)
110+
) = data;
86111
var infoWithoutNulls = infos.Where(info => info is not null).Select(info => info!);
87112
var mappingInfoWithoutNulls = mappingInfos
88113
.Where(info => info is not null)
@@ -112,6 +137,12 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
112137
}
113138
}
114139

140+
// Report diagnostics for invalid mapping methods
141+
foreach (var diagnostic in mappingDiagnostics.Where(diag => diag is not null))
142+
{
143+
spc.ReportDiagnostic(diagnostic!);
144+
}
145+
115146
// Combine regular SelectExpr infos with mapping-generated ones
116147
var allInfos = infoWithoutNulls.Concat(mappingSelectExprInfos);
117148

@@ -559,6 +590,26 @@ GeneratorAttributeSyntaxContext context
559590
};
560591
}
561592

593+
private static Diagnostic? GetMappingMethodDiagnostic(GeneratorAttributeSyntaxContext context)
594+
{
595+
if (context.TargetNode is not MethodDeclarationSyntax method)
596+
return null;
597+
598+
var attributeData = context.Attributes.FirstOrDefault();
599+
if (attributeData is null)
600+
return null;
601+
602+
var targetMethodName = attributeData.ConstructorArguments.FirstOrDefault().Value as string;
603+
if (!string.IsNullOrWhiteSpace(targetMethodName))
604+
return null;
605+
606+
return Diagnostic.Create(
607+
MappingGenerateMethodNameMissingDescriptor,
608+
method.Identifier.GetLocation(),
609+
method.Identifier.Text
610+
);
611+
}
612+
562613
/// <summary>
563614
/// Gets mapping declare info from ForAttributeWithMetadataName context.
564615
/// This is more efficient than CreateSyntaxProvider because ForAttributeWithMetadataName

0 commit comments

Comments
 (0)