In CodeGraph's C, C++, Objective-C, and Rust extractors, a union declaration
produces no symbol at all. The type is absent from the graph, and so is
everything attached to it.
union_specifier (C/C++/ObjC) and union_item (Rust) appear nowhere in the
extraction layer — no <x>Types list on the TS side, no dispatch branch in
either kernel walker:
$ grep -rn 'union_specifier\|union_item' src/ codegraph-kernel/src/
(no output)
Structs and enums beside them extract normally. The grammars parse unions fine,
so this is in symbol extraction, not the grammar.
Environment
- codegraph: 1.5.0 (npm), reproduced again on
main @ d6d1728
- Backend: node:sqlite (WAL)
- Platform: Linux x64
- C, C++, and Rust reproduce on both extraction paths: the native kernel and
the wasm/TS walker (CODEGRAPH_KERNEL=0). Objective-C continues to use its
existing wasm/TS extraction path.
Repro
src/lib.rs:
pub union Reg { pub raw: u32, pub bits: [u8; 4] }
pub struct Ctl { pub n: u32 }
pub trait Describe { fn describe(&self) -> String; }
impl Describe for Reg { fn describe(&self) -> String { "reg".into() } }
impl Describe for Ctl { fn describe(&self) -> String { "ctl".into() } }
pub fn dump(r: &Reg) -> String { r.describe() }
src/mem.c:
union Word { int i; char b[4]; };
struct Ctl { int x; };
codegraph init .
sqlite3 .codegraph/codegraph.db "SELECT kind, name FROM nodes WHERE kind='struct';"
Expected
Reg, Ctl, Word, Ctl — and two implements edges.
Actual
The two unions are missing, and with them Reg's realization of Describe:
struct Ctl (lib.rs)
struct Ctl (mem.c)
implements: Ctl -> Describe # Reg -> Describe never forms
Impact
Three separate losses, and the second is the one that hurts.
1. The type is gone. It cannot be searched for, does not appear in
codegraph_explore, and any function taking union Reg * has no type to point
at.
2. Its methods become orphans that point at a type which does not exist.
This is worse than a plain omission, because the graph ends up internally
inconsistent rather than merely incomplete:
Describe::describe <- contains from trait:Describe ✅
Ctl::describe <- contains from file:lib.rs + struct:Ctl ✅
Reg::describe <- contains from file:lib.rs ❌ its qualifiedName says "Reg"
Asking what Reg::describe belongs to gets the file. The Reg in its own
qualified name resolves to nothing.
3. Trait-dispatch synthesis silently under-reports. The synthesized
(provenance='heuristic') fan-out is Describe::describe -> Ctl::describe and
nothing else. A union implementor is not a candidate, because it is not a node —
so "who implements this trait" is quietly wrong rather than visibly incomplete.
In C the loss splits by form:
| form |
today |
union U { … }; |
no node at all |
typedef union { … } U; |
survives as type_alias:U — name kept, kind wrong, no members |
Unions are load-bearing in C: tagged variants, register overlays, protocol
frames, and — relevant to this repo — function-pointer dispatch tables, which
c-fnptr-synthesizer.ts finds by scanning nodes with kind === 'struct'. A
union-shaped dispatch table is invisible to it.
Cause
extractStruct is only reached for node types registered in a language's
structTypes, and no language lists its union node type. Same in both kernel
walkers, where the dispatch is a hardcoded kind == "struct_specifier" /
kind == "struct_item" branch.
I have a fix ready and will open a PR referencing this issue.
In CodeGraph's C, C++, Objective-C, and Rust extractors, a
uniondeclarationproduces no symbol at all. The type is absent from the graph, and so is
everything attached to it.
union_specifier(C/C++/ObjC) andunion_item(Rust) appear nowhere in theextraction layer — no
<x>Typeslist on the TS side, no dispatch branch ineither kernel walker:
Structs and enums beside them extract normally. The grammars parse unions fine,
so this is in symbol extraction, not the grammar.
Environment
main@d6d1728the wasm/TS walker (
CODEGRAPH_KERNEL=0). Objective-C continues to use itsexisting wasm/TS extraction path.
Repro
src/lib.rs:src/mem.c:Expected
Reg,Ctl,Word,Ctl— and twoimplementsedges.Actual
The two unions are missing, and with them
Reg's realization ofDescribe:Impact
Three separate losses, and the second is the one that hurts.
1. The type is gone. It cannot be searched for, does not appear in
codegraph_explore, and any function takingunion Reg *has no type to pointat.
2. Its methods become orphans that point at a type which does not exist.
This is worse than a plain omission, because the graph ends up internally
inconsistent rather than merely incomplete:
Asking what
Reg::describebelongs to gets the file. TheRegin its ownqualified name resolves to nothing.
3. Trait-dispatch synthesis silently under-reports. The synthesized
(
provenance='heuristic') fan-out isDescribe::describe -> Ctl::describeandnothing else. A union implementor is not a candidate, because it is not a node —
so "who implements this trait" is quietly wrong rather than visibly incomplete.
In C the loss splits by form:
union U { … };typedef union { … } U;type_alias:U— name kept, kind wrong, no membersUnions are load-bearing in C: tagged variants, register overlays, protocol
frames, and — relevant to this repo — function-pointer dispatch tables, which
c-fnptr-synthesizer.tsfinds by scanning nodes withkind === 'struct'. Aunion-shaped dispatch table is invisible to it.
Cause
extractStructis only reached for node types registered in a language'sstructTypes, and no language lists its union node type. Same in both kernelwalkers, where the dispatch is a hardcoded
kind == "struct_specifier"/kind == "struct_item"branch.I have a fix ready and will open a PR referencing this issue.