fix(db): resolve ::-qualified call targets without breaking namespaced-name storage#148
Conversation
…d-name storage The heuristic resolver reduced target_name on `.`/`\` but not `::`, so Rust path calls (`Pool::new`, `Config::load`) never matched a bare-stored callee and stayed unresolved — the largest driver of Rust's low resolution rate. Reduce past `::` too, but full-name-first with a guarded fallback: - full_name (split only on `.`/`\`) is tried first. Ruby stores namespaced symbols under their full name (`class Foo::Bar` -> name `Foo::Bar`), so a naive `::`-split would reduce an Inherits target `Baz::Quux` to `Quux` and miss it — a regression. - reduced_name (past `::`) is tried second, through the locality tiers (1-4) only. Those are file/dir/scope-guarded, so a fallback can only match a symbol already reachable from the caller. - The global tier (5+6) uses full_name only: a fully-qualified external call like `std::mem::swap` stays unresolved instead of reducing to `swap` and false-resolving onto a lone project symbol. Rust Calls resolution 45.47% -> 47.28% (+31 edges) on the webapp_rs fixture; Ruby, Python, PHP, TS, Go, Java byte-identical. Index wall-clock unchanged. Adds regression tests for the Rust gain, the Ruby full-name path, and the external- call guard; each fails on the naive `::`-split and passes here.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughThe edge resolver in resolve_edge_batch was refactored to compute both a full_name and a reduced_name (split on ChangesEdge Resolver Name Reduction
Estimated code review effort: 3 (Moderate) | ~25 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #148 +/- ##
=======================================
Coverage 88.38% 88.38%
=======================================
Files 96 96
Lines 32574 32573 -1
=======================================
Hits 28791 28791
+ Misses 3783 3782 -1 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Problem
The heuristic edge resolver reduced
target_nameto asimple_nameby splitting on.(method chains) and\(PHP namespaces) but not::(Rust/C++ path separator). So Rust path calls likePool::new,Config::load,Vec::newnever matched any bare-stored callee symbol and failed every one of the 6 resolution tiers — the largest driver of Rust being the lowest-scored language onmake bench-resolution(~45%).Fix: full-name-first,
::-reduced fallback through locality tiers onlyA naive "just split on
::too" is not all-language safe — Ruby stores namespaced symbols under their full name (class Foo::Bar→ symbolFoo::Bar,ruby.rsextract_constant_namekeeps the wholescope_resolution), so reducing anInheritstargetBaz::Quux→Quuxwould miss it and regress every Ruby namespaced inheritance/reference. It also lets a fully-qualified external callstd::mem::swapreduce toswapand false-resolve onto a lone project symbol.So the resolver now:
full_name(split only on./\, the prior behavior) is tried first — preserves qualified-name storage (RubyBaz::Quux, PHPApp\Auth\Foo).reduced_name(further past::,Someonly when it differs) is tried second, through locality tiers 1–4 only. Those are file/dir/scope-guarded, so a fallback can only match a symbol already reachable from the caller — safe.full_nameonly:std::mem::swapstays unresolved rather than reducing toswapand fabricating a call edge.Measurements (before → after, heuristic
--no-lsp)Concrete: on the
webapp_rsfixture,Config::load(10 call sites) resolved to nothing before (refs load→ "No references found"); after, all 10 resolve. The gain is a correct +31, not a naive::-split's inflated +68 — the 37-edge difference was exactly the false positives this design avoids. Index wall-clock unchanged (best-of-5 identical).Regression-first tests
Each new test was verified against three resolver versions:
::-split (rejected)std::mem::swapunresolvedPool::new, nested::, dot-then-colon,View::render)Review
Ran an xhigh workflow-backed code review on the first (naive) attempt; it caught the Ruby regression and the external-call false-positive, both independently reproduced and now fixed with guarding tests. Also addressed the review's test-quality findings (mislabeled tier, redundant internal-column read, a false-green ambiguity test).
Checks
cargo test --workspace(33 suites) ✅ —cartog-db208 passcargo test -p cartog-db --no-default-features✅cargo fmt --check,cargo clippy --all-targets [--no-default-features] -- -D warnings✅cargo test --doc -p cartog-db,cargo doc --no-deps -p cartog-db(warning-clean) ✅No extractor / ground-truth / docs / site change: stored
target_nameis untouched, and this is an internal resolver-quality fix (no new command/flag/config/MCP-tool/language/count).🤖 Generated with Claude Code
https://claude.ai/code/session_01AhoiweoMbZQ6FQgAcrfiWu
Summary by CodeRabbit
Bug Fixes
::,.or path separators.Tests