MCPcopy Create free account
hub / github.com/colbymchenry/codegraph / getCallersRecursive

Method getCallersRecursive

src/graph/traversal.ts:270–310  ·  view source on GitHub ↗
(
    nodeId: string,
    maxDepth: number,
    currentDepth: number,
    result: Array<{ node: Node; edge: Edge }>,
    visited: Set<string>
  )

Source from the content-addressed store, hash-verified

268 }
269
270 private getCallersRecursive(
271 nodeId: string,
272 maxDepth: number,
273 currentDepth: number,
274 result: Array<{ node: Node; edge: Edge }>,
275 visited: Set<string>
276 ): void {
277 // Mark visited BEFORE the depth check, not after. Folding both into one
278 // guard meant that when `currentDepth >= maxDepth` fired we returned without
279 // marking the node — so a caller reachable from the same parent via two
280 // edges (two call sites, or calls + references) was pushed once per edge,
281 // duplicating it in `result` at the default `maxDepth=1` (#1086).
282 if (visited.has(nodeId)) {
283 return;
284 }
285 visited.add(nodeId);
286 if (currentDepth >= maxDepth) {
287 return;
288 }
289
290 // `instantiates` counts as a caller: constructing a class (`Foo(...)` /
291 // `new Foo()`) is calling its constructor, so the instantiation site is a
292 // caller of the class. Without it, `callers <Class>` surfaced only the
293 // importing file (via `imports`) and missed every construction site —
294 // the opposite of "what breaks if I change this class?" (#774).
295 const incomingEdges = this.queries.getIncomingEdges(nodeId, ['calls', 'references', 'imports', 'instantiates']);
296 if (incomingEdges.length === 0) return;
297
298 // Batch-fetch all caller nodes in one round-trip instead of one
299 // getNodeById per edge (was N+1 — meaningful on functions with many callers).
300 const sourceIds = incomingEdges.map((e) => e.source);
301 const callerNodes = this.queries.getNodesByIds(sourceIds);
302
303 for (const edge of incomingEdges) {
304 const callerNode = callerNodes.get(edge.source);
305 if (callerNode && !visited.has(callerNode.id)) {
306 result.push({ node: callerNode, edge });
307 this.getCallersRecursive(callerNode.id, maxDepth, currentDepth + 1, result, visited);
308 }
309 }
310 }
311
312 /**
313 * Find all functions/methods called by a function

Callers 1

getCallersMethod · 0.95

Calls 4

hasMethod · 0.80
getNodesByIdsMethod · 0.80
getMethod · 0.65
getIncomingEdgesMethod · 0.45

Tested by

no test coverage detected