fix(extraction): C# record-struct kind fidelity + bodiless positional records (#831 follow-up) (#838)

The shipped grammar parses every record form as record_declaration (no
record_struct_declaration node), so 'record struct' mis-kinded as class.
classifyClassNode now distinguishes the value-type form by its struct
keyword child, and extractStruct accepts bodiless positional records
(the no-body gate is for C/C++ forward declarations) instead of
crashing mid-file on them.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Colby Mchenry
2026-06-12 13:17:25 -05:00
committed by GitHub
co-authored by Claude Opus 4.8
parent ed117ef90b
commit 2c7bbd5387
4 changed files with 62 additions and 11 deletions
+14 -3
View File
@@ -56,13 +56,24 @@ export const csharpExtractor: LanguageExtractor = {
preParse: blankCsharpPreprocessorDirectives,
functionTypes: [],
// Records are first-class type declarations in modern C# (DTOs, value objects,
// MediatR/CQRS messages). `record` / `record class` parse as record_declaration
// (reference type → class); `record struct` as record_struct_declaration (value
// type → struct). Without these, references to a record never resolve (#237).
// MediatR/CQRS messages). Without these, references to a record never resolve
// (#237). The shipped grammar parses EVERY record form as record_declaration
// `record struct` / `readonly record struct` included (it has no
// record_struct_declaration node; that structTypes entry is forward-compat
// only) — so classifyClassNode tells the value-type form apart by its
// `struct` keyword child. (#831 follow-up)
classTypes: ['class_declaration', 'record_declaration'],
methodTypes: ['method_declaration', 'constructor_declaration'],
interfaceTypes: ['interface_declaration'],
structTypes: ['struct_declaration', 'record_struct_declaration'],
classifyClassNode: (node) => {
if (node.type === 'record_declaration') {
for (let i = 0; i < node.childCount; i++) {
if (node.child(i)?.type === 'struct') return 'struct';
}
}
return 'class';
},
enumTypes: ['enum_declaration'],
enumMemberTypes: ['enum_member_declaration'],
typeAliasTypes: [],