feat(code-graph-incremental): resolve imports and calls across files
What does this MR do and why?
Fifth slice of code-graph-incremental, stacked on !2631 (merged). Files now resolve against each other: an import points at the definition it names in another file, and calls, inheritance and member calls through imported types become cross-file edges. An import with no matching file stays dangling. A file that overruns its resolve budget keeps the edges it already has and is reported. Nothing is wired to the CLI or server yet.
Related Issues
Relates to #1284. Reference implementation: !2454 (closed).
Testing
cargo test -p code-graph-incremental: 38 tests. New in tests/resolve.rs: on a two-file Python repo, imports and calls resolve across files (s = Store(); s.get() through the imported type, class Child(Store) as EXTENDS); import missing points at nothing; under a zero resolve budget both files are reported, imports remain and inheritance is the edge that is lost.
cargo clippy -p code-graph-incremental --all-targets -- -D warnings: clean.
Performance Analysis
No runtime change: nothing calls this crate yet.
- This merge request does not introduce any performance regression. If a performance regression is expected, explain why.
Agent context: long-form analysis, file-by-file walkthroughs, profiler output, alternatives considered
What lands
src/resolver.rs Resolver: visible names per file, import requests, file index, two passes
src/file_tree.rs ProjectTree: __root/__dir/__file/__package tree, manifests parsed in, prefixes and aliases
src/pipeline/phases.rs Resolve (DirtyGraph -> Resolved)
tests/resolve.rsFiles are copied from !2454 (closed) at their final shape. The stub Resolver/FileIndex and their allow(dead_code) are replaced by the real file; Tree::node_mut loses its allow (Resolve writes resolved source-path symbols back).
Resolution runs in two passes. The import pass is global and links every import to its definition. The second pass runs per dirty file under file_resolve_ms and adds inheritance, decorators, destructuring, and member calls that the import pass cannot produce; that is the pass a kill drops, which is what the budget test asserts.
Base branch is michaelusa/code-graph-incremental-link (!2631 (merged)); retarget to main once that merges.
MR stack
| MR | Contents |
|---|---|
| !2620 (merged) | runner, budgets, errors, canonical alphabet, artifact and graph types |
| !2627 (merged) | Tree, Interner, tree-sitter languages, Env, inventory, Prepare + Each + Parse |
| !2629 (merged) | DSL engine, Rewrite + Canonicalize, Env.rules, Python rules |
| !2631 (merged) | SSA, linker, Link + Insert |
| 5 (this) | resolver, project tree, Resolve |
| 6 | export engine + export.yaml, Display + Export + Emit, index template; YAML suites through the integration-tests-codegraph runner with an engine switch; CI job |
| 7 | State save/load, Remap, reindex template, incremental suites |
| 8 | remaining language rule files |
| 9 | orbit index --engine incremental, full index through the existing DuckDB sink |
| 10 | snapshot next to the DuckDB file, changed paths from git, incremental CLI |
| 11 | default flip per language; old pipeline and its fixtures retire |
%{all_commits}