You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
GeneratorBase.Diagnostics must be overridden but is never read, so a null or wrong-prefix catalogue is silently accepted #58
GeneratorBase declares protected abstract DiagnosticCatalog Diagnostics { get; } (SourceGeneratorToolkit/GeneratorBase.cs:36-39) and documents it as "the catalogue this generator's diagnostics are allocated from". Every consumer has to override it, and the README examples (README.md:119, :164) and the seam example in CLAUDE.md (:102) all do.
Nothing in SourceGeneratorToolkit or SourceGeneratorToolkit.Testing ever reads it. The declaration is the only reference. Initialize reports the MetadataFileMissing descriptor directly, GeneratorBase<T>.Generate reports MetadataParseFailed directly, and neither descriptor is checked against the catalogue.
staticclassOld{publicstaticDiagnosticCatalogC=new("OLD","old");/* M = C.Warning(1,..), P = C.Error(2,..) */}staticclassMine{publicstaticDiagnosticCatalogC=new("MYG","mine");}sealedclassNullCatalogGen():GeneratorBase<Meta>("things.json"){protectedoverrideDiagnosticCatalogDiagnostics=>null!;protectedoverrideDiagnosticDescriptorMetadataFileMissing=>Old.M;protectedoverrideDiagnosticDescriptorMetadataParseFailed=>Old.P;...}sealedclassMismatchGen():GeneratorBase<Meta>("things.json"){protectedoverrideDiagnosticCatalogDiagnostics=>Mine.C;// MYGprotectedoverrideDiagnosticDescriptorMetadataFileMissing=>Old.M;// OLD001protectedoverrideDiagnosticDescriptorMetadataParseFailed=>Old.P;// OLD002 ... }
Each was run through GeneratorHarness with { not json:
Diagnostics => null! : exception=none diags=OLD002
Diagnostics => MYG catalogue, descriptors from OLD : exception=none diags=OLD002
Why it matters
The catalogue exists to prevent identifier drift. The DiagnosticCatalog remarks name this exact failure as the typical one: "a base class reporting parse failures under its own prefix while everything derived from it uses another". The base class asks every consumer for the information it would need to catch that drift, then never uses it. A required member looks enforced. In practice a generator can report its two built-in diagnostics under a prefix that differs from the one its tests enumerate for AnalyzerReleases.Unshipped.md, and nothing notices.
Suggested fix / acceptance criteria
Pick one:
(a) Use it. In Initialize, check that MetadataFileMissing and MetadataParseFailed are both in Diagnostics.Descriptors (by reference or ID). If either is missing, fail loudly with a message naming the descriptor and the catalogue prefix. Add a test with a mismatched catalogue that asserts the failure, and one with a null catalogue.
(b) Remove it. Drop the abstract member ([major]) and update the README and CLAUDE.md examples.
Either way, a consumer can no longer supply a catalogue that has no effect.
Priority: Low. No output is wrong today. The catalogue is a required member that has no effect, so it gives a false sense of enforcement against prefix drift.
Recommendation: Option (a), using the catalogue, is non-breaking and makes the member meaningful. Option (b) needs a [major] release, so prefer (a) unless a major release is already planned.
Activity
matt-edmondson commentedon Nov 1, 2026
Triage
SourceGeneratorToolkit/GeneratorBase.cs(Diagnostics,Initialize,Generate)[major]release, so prefer (a) unless a major release is already planned.Generated by Claude Code