Recover parenthesized object declarations only when their apparent parameters resolve to earlier visible value bindings. Respect recovered scope, alias hiding and prototype shadowing instead of manufacturing receiver types.
Preserve heuristic confidence and source provenance. Add positive and negative regressions plus a three-repeat labeled initialization fixture to the quality gate.
Validation: cargo fmt --check and ./scripts/quality-gate.sh passed.
`.c` files were parsed with tree-sitter-cpp, so valid C that uses C++
keywords as identifiers (`int delete = 0; int new = 1;`, a parameter
named `class`) produced grammar-error diagnostics and lost symbols.
`.c` files now parse with tree-sitter-c (pinned =0.24.2, backend
`c:0.24.2`) while staying on the shared C/C++ extraction path, so C
sources and the headers they include still share one include/declaration
index. Headers (`.h`) keep the C++ grammar, which parses the C subset.
Test: cpp_xtu::c_sources_parse_with_the_c_grammar fails before this
change (grammar errors in util.c).
Every preprocessor branch was indexed as live. In yams,
InternalEventBus.h guards spdlog with
`#if __has_include(<spdlog/spdlog.h>) ... #else namespace spdlog { stubs }`,
so 1,243 spdlog::warn/info/error call sites resolved to the fallback
stubs, which became the 4th and 5th highest fan-in nodes.
Brick does not evaluate conditions, so only the first branch is treated
as live: declarations and prototypes inside `#elif`/`#else` stay in the
graph (marked `source.preprocessor-branch: alternative`) but are not
definitions, declarations or classes for call resolution. Branches are
tracked textually from the directive lines, because conditions like
`__has_include(<x>)` leave tree-sitter-cpp with an error-recovered tree
that has no `preproc_else` node to find. Include-guard (`#ifndef`) code
is a first branch and still resolves.
Test: cpp_xtu::preprocessor_alternative_branches_are_not_call_targets
fails before this change (spdlog::info resolves into the #elif stub).
With `using namespace a; using namespace b;` and both `a::run` and
`b::run` declared, a call to `run` resolved to whichever directive came
first in file order and was labelled `using-directive`. In C++ that
call is ambiguous (or an overload choice Brick does not model).
Directives are now grouped: each `using N::x;` and `using namespace N;`
nominates at most one declaration (its innermost resolving scope), and
the call resolves only when exactly one distinct declaration is
nominated; otherwise it stays external as `ambiguous`.
Test: cpp_xtu::two_using_directives_naming_the_same_function_are_ambiguous
fails before this change; its single-directive case still resolves.
C++ calls now resolve through the include closure: header prototypes pair
with definitions in other translation units, lookup walks class (including
in-repository bases), namespace, and `using` scopes outward, and static or
anonymous-namespace definitions stay file-local. Member calls resolve only
through explicitly declared receiver types (parameters, locals, fields,
this, smart pointers, aliases); template parameters stay unknown. Calls
hidden by the most vexing parse are recovered, casts are no longer calls,
reference-returning and conversion-operator declarations are named
correctly, and benign `= {}` default-argument recoveries no longer drop
prototypes or flag files.
Rust method calls resolve through a crate-wide impl index for self, typed
parameters and lets, struct fields, Self-returning constructors, dyn
traits, and Type::/Self:: associated calls, with foreign imports and
generics never guessed. Calls inside expression macros are re-parsed.
Every unresolved call records source.unresolved-reason, weaker resolutions
record source.resolution/source.extraction, and metrics.resolution reports
per-language call-site coverage. Declarations gain facts consumed by
caller-status queries (qualified names, linkage, virtual, trait impls,
attributes, name references, parse-incomplete). C++/Rust External targets
include the reason in their identity; out-of-line C++ methods keep their
IDs.
Linear node/edge scans and per-node ancestor walks are replaced with
indexes, cutting a YAMS scan from 575 s to 23 s.
New labeled cpp_xtu and rust_methods corpora run three times in the
quality gate.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>