Dedup partial service-class declarations in the generator#4560
Dedup partial service-class declarations in the generator#4560pepone wants to merge 1 commit intoicerpc:mainfrom
Conversation
ForAttributeWithMetadataName emits one ClassDeclarationSyntax per attribute application. If a user puts [Service] on more than one partial part of the same class, the parser previously processed every syntax node and the generator called AddSource twice with the same hint name, which Roslyn rejects with an opaque generator-threw ArgumentException at build time. Track classes by their resolved INamedTypeSymbol and skip ones we've already processed. The user's intent is unambiguous (the parts together are one class), so silent dedup is the natural behavior; no diagnostic is needed.
There was a problem hiding this comment.
Pull request overview
This PR fixes an edge case in IceRpc.ServiceGenerator where applying [Service] to multiple parts of the same partial class caused the generator to emit duplicate sources with the same hint name, triggering a Roslyn ArgumentException during build.
Changes:
- Deduplicate service class processing by tracking seen
INamedTypeSymbols withSymbolEqualityComparer.Default. - Skip subsequent partial declarations of the same class symbol to avoid duplicate
AddSourcehint names. - Add an explanatory comment documenting why the deduplication exists.
| @@ -53,7 +57,7 @@ internal IReadOnlyList<ServiceClass> GetServiceDefinitions(IEnumerable<ClassDecl | |||
|
|
|||
| SemanticModel semanticModel = _compilation.GetSemanticModel(classDeclaration.SyntaxTree); | |||
| INamedTypeSymbol? classSymbol = semanticModel.GetDeclaredSymbol(classDeclaration, _cancellationToken); | |||
| if (classSymbol is null) | |||
| if (classSymbol is null || !seenClassSymbols.Add(classSymbol)) | |||
|
Closing as not applicable. The audit's premise relies on the user being able to apply [Service] on multiple partial parts of the same class. ServiceAttribute is declared as |
Summary
ForAttributeWithMetadataNameemits oneClassDeclarationSyntaxper attribute application. If a user writes[Service]on more than one part of a partial class, the parser previously processed every syntax node and the generator calledcontext.AddSourcetwice with the same hint name, which Roslyn rejects with an opaque generator-threwArgumentExceptionat build time.INamedTypeSymbol(usingSymbolEqualityComparer.Default) and skip ones we've already processed. The parts together are one class — silent dedup is the natural behavior.Fixes #4458