Skip to content

fix(graph): surface instantiates edges in callers/callees (#774)#801

Closed
maxmilian wants to merge 1 commit into
colbymchenry:mainfrom
maxmilian:fix/774-instantiates-caller-edge
Closed

fix(graph): surface instantiates edges in callers/callees (#774)#801
maxmilian wants to merge 1 commit into
colbymchenry:mainfrom
maxmilian:fix/774-instantiates-caller-edge

Conversation

@maxmilian

Copy link
Copy Markdown
Contributor

Fixes #774.

The actual gap (reframed)

#774 asks for class instantiation (Foo()) to count as a caller edge into the class. The extraction/resolution half already ships: resolveReferences() promotes a calls ref to an instantiates edge when the target resolves to a class (src/resolution/index.ts, covered by the existing test "promotes calls→instantiates when target resolves to a class (Python)"). And impact already surfaces it — getImpactRecursive walks every incoming edge except contains.

The residual bug is in traversal: getCallersRecursive and getCalleesRecursive whitelisted only ['calls', 'references', 'imports'], omitting instantiates. So after promotion, the edge exists in the graph but:

  • callers <Class> / codegraph_callers returns "No callers found" even though the class is instantiated, and
  • callees <site> omits the class the site constructs.

callers was the one inconsistent traversal (impact already included instantiation sites).

The fix

Add 'instantiates' to the edge-kind whitelist in both getCallersRecursive (incoming) and getCalleesRecursive (outgoing), so an instantiation site is reported as a caller of the class and the class as a callee of the site — matching what impact already does.

// getCallersRecursive
getIncomingEdges(nodeId, ['calls', 'references', 'imports', 'instantiates'])
// getCalleesRecursive
getOutgoingEdges(nodeId, ['calls', 'references', 'imports', 'instantiates'])

Test

Extends the existing calls→instantiates Python fixture (UserService + bootstrap) in __tests__/resolution.test.ts to assert the traversal: getCallers(UserService) now returns bootstrap via an instantiates edge, and getCallees(bootstrap) returns UserService. Red before the change, green after.

Validation

  • npm run build — clean.
  • The new regression test: red on main, green on this branch.
  • npm test — no new failures. Two pre-existing worker-exit flakes (in resolution.test.ts's real-SQLite/wasm run) reproduce identically on clean main, so they're unrelated to this change; all callers/callees/impact suites (foundation, explore-blast-radius, object-literal-methods) pass.

The reporter's original evidence was against v0.9.5 (before the calls→instantiates promotion landed in #134), so the symptom they saw was broader; on current main this traversal whitelist is the remaining piece.

…ry#774)

Resolution promotes a class-instantiation `calls` ref (e.g. Python
`Foo()`) to an `instantiates` edge, but getCallers/getCallees whitelisted
only ['calls','references','imports'] — so once the promotion ran,
`callers <Class>` and `codegraph_callers` returned no callers even though
the instantiation edge existed. impact already traverses instantiates
(it walks all incoming edges except contains), so callers was the
inconsistent one.

Add 'instantiates' to both the incoming whitelist in getCallersRecursive
and the symmetric outgoing whitelist in getCalleesRecursive, so an
instantiation site is reported as a caller of the class and the class as
a callee of the site. Regression test extends the existing
calls->instantiates resolution fixture to assert the traversal.
@maxmilian maxmilian marked this pull request as ready for review June 11, 2026 15:51
@maxmilian

Copy link
Copy Markdown
Contributor Author

Closing — this was superseded upstream by d0e6499 (PR #804, also for #774), which adds the instantiates edge to getCallersRecursive/getCalleesRecursive in src/graph/traversal.ts — equivalent to this PR. Thanks for landing it!

@maxmilian maxmilian closed this Jun 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Python: class instantiation ClassName() is not a caller edge; impact <Class> returns containment, not dependents

1 participant