Skip to content

getCallersRecursive/getCalleesRecursive: depth guard returns before visited.add, causing duplicate results #1086

Description

@inth3shadows

File: src/graph/traversal.ts
Lines: 246–249 (getCallersRecursive), 296–299 (getCalleesRecursive)

Defect: The depth guard (if (currentDepth >= maxDepth || visited.has(nodeId)) return;) at L246/L296 returns without executing visited.add(nodeId) at L249/L299, so when currentDepth >= maxDepth fires the caller/callee node is never marked visited; a node reachable via multiple edges from the same parent is then pushed to result once per edge.

Failure trace:

  • Function X has two calls edges from Y (e.g., Y calls X twice in different expressions).
  • getCallersRecursive("X", 1, 0, result, visited): depth 0 < maxDepth 1 → continue; visited.add("X").
  • Push loop, edge e1 (Y→X): !visited.has("Y") = true → result.push({Y,e1}); recurse ("Y", 1, 1, …) → depth 1 ≥ maxDepth 1 → return without visited.add("Y").
  • Push loop, edge e2 (Y→X): !visited.has("Y") = true (Y was never added) → result.push({Y,e2})duplicate.
  • With default maxDepth=1 (as used in the public getCallers/getCallees at src/index.ts) any function called by the same caller via two edges produces a duplicate entry.

Expected fix:
Move visited.add(nodeId) to immediately after the visited.has(nodeId) arm of the guard and before the depth arm fires — or, equivalently, split the guard into two separate checks and add to visited unconditionally after the visited.has check:

if (visited.has(nodeId)) return;
visited.add(nodeId);                // mark before depth check
if (currentDepth >= maxDepth) return;

Alternatively, add visited.add(callerNode.id) (resp. calleeNode.id) in the push loop before the recursive call, to prevent the same node being pushed more than once per result set.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions