feat: opt-in precise CALLS resolver for Python (cgh[lsp], jedi-backed)#73
Merged
Conversation
FEAT-14 proof of concept. Adds a jedi-backed resolver that does goto-definition on every Python call site and maps each resolved definition to the graph's Function id scheme, so cross-file call edges are exact instead of name-matched. jedi is the same static engine python-lsp-server wraps, which keeps the machinery far lighter than spawning a real LSP subprocess while leaving resolve_calls_for_file as the seam a true LSP backend could replace later. Strictly opt-in and Python-only. The new precise_calls config flag (off by default, CGH_PRECISE_CALLS env override) gates it, and the resolver imports jedi lazily behind the new cgh[lsp] extra. With the flag off or the extra absent, the indexer falls back to the existing name-matched resolver and behavior is unchanged. The resolver rebuilds target paths from the indexer's repo_root so ids match stored Function nodes even when jedi resolves symlinks, restores the recursion limit parso lowers on import, and caps call sites per file. Tests cover cross-file resolution, the Class.method id form, the env override, and the same-name collision the name matcher cannot get right; all degrade to a skip when jedi is missing.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
FEAT-14 (minimal proof of concept). Opt-in, Python-only precise call resolution that fixes the cross-file / same-name-collision gap the name matcher (BUG-2) can't.
Design
Rather than spawn a real LSP server (pyright/pylsp subprocess + JSON-RPC — heavy, fragile), this uses jedi, the same static-analysis engine python-lsp-server wraps.
analysis/precise_calls.pyis the seam where a true LSP backend could slot in later.Gating (default behavior UNCHANGED)
Three guards, all required:
precise_callsconfig flag on (default False;[codegraph].precise_callsorCGH_PRECISE_CALLS), jedi importable (the newlspextra), and file is Python. Any other case falls back to the existing name-matched_resolve_callsexactly as today. jedi import is lazy + guarded.What it does
For each Python call site,
jedi.Script(...).goto(follow_imports=True)resolves the precise definition, mapped to the graph's{file}::{name}/{file}::{Class}.{method}id scheme; only callees inside the repo are kept. Handles the macOS symlink path mismatch and restores the recursion limit parso lowers on import.Proof
test_precise_calls_beats_same_name_collision: a.py imports b.helper, defines a decoy helper(), calls b.helper() — the name matcher links to the decoy, the precise resolver correctly links to b.py::helper.Test plan
lspextra + uv.lock; ruff + no-ai-tells clean