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
C: a macro call with designated-initializer arguments and a trailing comma runs the enclosing function to end of file, nesting or dropping every function after it #1729
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.
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:
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.
Cause: tree-sitter-c has no rule for designated-initializer call args (.x = …). Error recovery extends the enclosing function_definition to EOF — later functions drop or nest as outer::inner.
Fix:blankCDesignatedMacroArgs in preParseCSource blanks those statement-level macro arg lists to spaces (newlines kept) before parse. Runs before the kernel route point, so both wasm and kernel C arms get the same bytes; no kernel change required.
Verified on Linux: issue fixture fail→pass (f 1–16 / g missing / h as f::h → f 1–7, g, h top-level). Related #1733 (fork) closed as superseded; #1736 (#if brace damage) left separate.
Activity
fix(extraction): blank a C macro call's designated-initializer argume…
fix(extraction): blank C designated-initializer macro args before par…
colbymchenry commentedon Sep 8, 2026
Fixed in #1755 (landed on
main).Cause: tree-sitter-c has no rule for designated-initializer call args (
.x = …). Error recovery extends the enclosingfunction_definitionto EOF — later functions drop or nest asouter::inner.Fix:
blankCDesignatedMacroArgsinpreParseCSourceblanks those statement-level macro arg lists to spaces (newlines kept) before parse. Runs before the kernel route point, so both wasm and kernel C arms get the same bytes; no kernel change required.Verified on Linux: issue fixture fail→pass (
f1–16 /gmissing /hasf::h→f1–7,g,htop-level). Related #1733 (fork) closed as superseded; #1736 (#ifbrace damage) left separate.fix(extraction): collapse a damaged C `#if` group to its first branch…
fix(extraction): collapse a damaged C `#if` group to its first branch…
fix(extraction): collapse a damaged C `#if` group to its first branch…
fix(extraction): collapse a damaged C `#if` group to its first branch…
fix(extraction): collapse a damaged C `#if` group to its first branch…
fix(extraction): collapse a damaged C `#if` group to its first branch…
fix(extraction): collapse a damaged C `#if` group to its first branch…
fix(extraction): collapse a damaged C `#if` group to its first branch…
fix(extraction): collapse a damaged C `#if` group to its first branch…
fix(extraction): collapse a damaged C `#if` group to its first branch…
fix(extraction): collapse a damaged C `#if` group to its first branch…
fix(extraction): collapse a damaged C `#if` group to its first branch…
fix(extraction): collapse a damaged C `#if` group to its first branch…
fix(extraction): collapse a damaged C `#if` group to its first branch…