Skip to content

Cross-file calls resolution drops EXTRACTED edges when the callee name has multiple definitions (even with unambiguous import evidence) #1219

Description

@Alex-R-A

Summary

When a called function name is defined in more than one file, the cross-file calls resolution drops the call edge entirely — even when the caller has an explicit, unambiguous named import that identifies exactly which definition is meant. With a single definition the edge resolves correctly (EXTRACTED). Adding any second same-named definition anywhere in the corpus removes the edge.

Net effect: silent false-negative calls edges. For any function whose name is defined 2+ times, call-edge recall is unreliable, and the absence of a calls edge cannot be trusted.

Version: graphify 0.8.35

Minimal reproduction

Three files in an empty directory:

helper.js

export function getThing() { return 1; }

duplicate.js

export function getThing() { return 2; }

caller.js

import { getThing } from './helper.js';
export function useThing() { const x = getThing(); return x; }

Run:

graphify extract . --no-cluster

Expected: a calls edge useThing -> getThing, bound to helper.js's getThing (the named import identifies it unambiguously).

Actual: useThing has no outgoing calls edge at all. Two getThing nodes exist (helper_getthing, duplicate_getthing) and neither lists useThing as a caller. The edge is dropped, not mis-bound.

Control (single definition works)

Delete duplicate.js and re-extract: the useThing -> getThing edge appears, EXTRACTED. Extraction and same-file binding are fine; the drop is triggered purely by the existence of a second same-named definition elsewhere.

Likely area

This looks related to the ambiguous-candidate handling introduced for #543 (which fixed the opposite problem: over-connecting INFERRED edges to every same-named node). That correctly stops over-connection, but a legitimate, import-evidenced EXTRACTED edge is now dropped when the name is multiply defined — the named-import evidence (from './helper.js') is not consulted to disambiguate in this JS/TS path.

Secondary observation: on a larger real corpus the behavior is also inconsistent across callers — with the same duplicate name present, some call sites keep the edge while others drop it, which makes the recall gap easy to miss.

Impact

  • dependents / callers / impact / trace under-report for any multiply-defined name.
  • A missing calls edge is a false negative, not evidence of "no call".

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions