Summary
A C function whose body braces are split across #ifdef/#else branches is silently dropped from the code knowledge graph — no Function node is emitted for it, even though its callers remain and reference it as an unresolved name.
Root cause
The extractor parses raw source with tree-sitter without running the preprocessor, so both #ifdef branches are present at once. When a construct like this opens a brace in each branch but shares one close brace:
#ifdef _WIN32
if (a() && b()) { // open brace (branch 1)
...
#else
if (c() && d()) { // a different open brace (branch 2)
#endif
...shared body...
} // single shared close brace
tree-sitter sees two if { opens and one } close → unbalanced braces → an ERROR node spanning the function body → no Function node is created. Recovery is localized (neighbouring functions extract fine), so the symptom is one function silently absent.
Reproduction (reproduce-first)
Found via a graph-vs-grep audit: cbm_path_within_root in src/mcp/mcp.c was absent from the graph while its 6 callers were present. Refactoring that specific function to a single unconditional control flow (#960) made it index. The general pattern remains unhandled.
Suggested RED reproduction for the bug-repro suite: a fixture C function with the #ifdef-splits-brace shape, asserting a Function node is produced for it. It should fail on the current extractor and pass once the extractor handles the pattern.
Impact
Low frequency but real: any function using this (uncommon) preprocessor pattern is invisible to search_graph/trace_path/callers, and dead-code / impact analysis will misjudge it. Also a latent correctness gap for graph-based audits.
Possible directions (extractor-side, harder than the per-function workaround)
- Detect the
ERROR-node-spanning-a-definition case and attempt a light preprocessor pass (pick one #ifdef branch) before re-parsing that region.
- Or a targeted brace-rebalancing heuristic for
#ifdef/#else/#endif regions inside a definition.
Not urgent; filing so the limitation is tracked rather than rediscovered.
Summary
A C function whose body braces are split across
#ifdef/#elsebranches is silently dropped from the code knowledge graph — noFunctionnode is emitted for it, even though its callers remain and reference it as an unresolved name.Root cause
The extractor parses raw source with tree-sitter without running the preprocessor, so both
#ifdefbranches are present at once. When a construct like this opens a brace in each branch but shares one close brace:tree-sitter sees two
if {opens and one}close → unbalanced braces → anERRORnode spanning the function body → noFunctionnode is created. Recovery is localized (neighbouring functions extract fine), so the symptom is one function silently absent.Reproduction (reproduce-first)
Found via a graph-vs-grep audit:
cbm_path_within_rootinsrc/mcp/mcp.cwas absent from the graph while its 6 callers were present. Refactoring that specific function to a single unconditional control flow (#960) made it index. The general pattern remains unhandled.Suggested RED reproduction for the bug-repro suite: a fixture C function with the
#ifdef-splits-brace shape, asserting aFunctionnode is produced for it. It should fail on the current extractor and pass once the extractor handles the pattern.Impact
Low frequency but real: any function using this (uncommon) preprocessor pattern is invisible to
search_graph/trace_path/callers, and dead-code / impact analysis will misjudge it. Also a latent correctness gap for graph-based audits.Possible directions (extractor-side, harder than the per-function workaround)
ERROR-node-spanning-a-definition case and attempt a light preprocessor pass (pick one#ifdefbranch) before re-parsing that region.#ifdef/#else/#endifregions inside a definition.Not urgent; filing so the limitation is tracked rather than rediscovered.