A C function whose body contains a macro call with designated-initializer arguments and a trailing comma is recorded with an extent that runs to the end of the file. Every function defined after it is either dropped from the graph or nested under it as outer::inner, and from there the resolver treats it as a closure it cannot reach.
Reproduction
pid.c:
void f(void)
{
M(a, b,
.x = 1,
.y = { 1, 2 },
);
}
void g(void)
{
}
int h(void)
{
return 1;
}
codegraph init and query nodes:
| name |
qualified_name |
lines |
f |
f |
1–16 (source: 1–7) |
g |
— |
missing |
h |
f::h |
13–16 |
Remove the comma after { 1, 2 } and all three come out right (f 1–7, g 9–11, h 13–16). tree-sitter-c does not accept the shape — a call_expression whose arguments are .x = … items ending in a comma — and its error recovery closes the function_definition at the end of the file. This is what the shipped tree-sitter-c.wasm returns; the extractor records the extent it is given.
The shape is not exotic. betaflight resets every config struct through it:
void resetPidProfile(pidProfile_t *pidProfile)
{
RESET_CONFIG(pidProfile_t, pidProfile,
.pid = { [PID_ROLL] = PID_ROLL_DEFAULT, … },
…
.adrc_sigma_decay_sched = 0,
);
}
On a 2,109-file betaflight tree the graph shows resetPidProfile at lines 168–1667 (source: 168–309) with the 45 functions after it as its children, and 310 C functions in 73 files nested inside another function this way — STM32 HAL sources (stm32h7xx_ll_utils.c, …_ll_tim.c, …_ll_usart.c) have the same shape. (That betaflight variant is one where the trailing comma alone does not explain it; the tiny case above is the reproducible core.)
Effect on resolution
isLexicallyReachable (#1230) reads the nesting as a scope: exact-match declines those 310 functions for every caller in another file, and on main the fuzzy fallback then picks them up at confidence 0.5 — 117 real calls into pid.c resolve that way instead of at 0.9. With #1718 the fuzzy fallback checks reachability too, so the 117 vanished; #1718 now gates C/C++ out of the nesting check (5eb5750), which is a resolver-side patch over this extraction defect, not a fix for it. Callers/callees of the dropped g-shaped functions have no node at all.
Where a fix could go
Either handle the recovered tree in the C extractor — when a function_definition contains an ERROR node, close it at the brace that balances its opening one and re-scan the remainder for top-level definitions — or pre-process the trailing-comma shape before parsing. I have not attempted either; the kernel arm (codegraph-kernel/src/c.rs) would need the same treatment, since the grammar is the same.
A C function whose body contains a macro call with designated-initializer arguments and a trailing comma is recorded with an extent that runs to the end of the file. Every function defined after it is either dropped from the graph or nested under it as
outer::inner, and from there the resolver treats it as a closure it cannot reach.Reproduction
pid.c:codegraph initand querynodes:ffghf::hRemove the comma after
{ 1, 2 }and all three come out right (f1–7,g9–11,h13–16). tree-sitter-c does not accept the shape — acall_expressionwhose arguments are.x = …items ending in a comma — and its error recovery closes thefunction_definitionat the end of the file. This is what the shippedtree-sitter-c.wasmreturns; the extractor records the extent it is given.The shape is not exotic. betaflight resets every config struct through it:
On a 2,109-file betaflight tree the graph shows
resetPidProfileat lines 168–1667 (source: 168–309) with the 45 functions after it as its children, and 310 C functions in 73 files nested inside another function this way — STM32 HAL sources (stm32h7xx_ll_utils.c,…_ll_tim.c,…_ll_usart.c) have the same shape. (That betaflight variant is one where the trailing comma alone does not explain it; the tiny case above is the reproducible core.)Effect on resolution
isLexicallyReachable(#1230) reads the nesting as a scope: exact-match declines those 310 functions for every caller in another file, and onmainthe fuzzy fallback then picks them up at confidence 0.5 — 117 realcallsintopid.cresolve that way instead of at 0.9. With #1718 the fuzzy fallback checks reachability too, so the 117 vanished; #1718 now gates C/C++ out of the nesting check (5eb5750), which is a resolver-side patch over this extraction defect, not a fix for it. Callers/callees of the droppedg-shaped functions have no node at all.Where a fix could go
Either handle the recovered tree in the C extractor — when a
function_definitioncontains anERRORnode, close it at the brace that balances its opening one and re-scan the remainder for top-level definitions — or pre-process the trailing-comma shape before parsing. I have not attempted either; the kernel arm (codegraph-kernel/src/c.rs) would need the same treatment, since the grammar is the same.