Skip to content

Call-expression receivers drop the receiver and fabricate a calls edge to any same-named top-level symbol — Python AND JavaScript, live in 1.6.0 #1683

Description

@inth3shadows

Summary

A member call whose receiver is a call expression loses the receiver at extraction time, degrades to a bare method-name ref, and then exact-matches any top-level project symbol with that name — fabricating a call edge from an unrelated function.

Reproduced in Python and JavaScript, so this is the shared extractor, not a per-language heuristic.

Not the same as #1230/#1317 (literal receivers, fixed — control C below passes) or #645 (C++ chained getters binding to the wrong class; here the receiver is dropped entirely and the edge lands on a top-level function).

Environment

@colbymchenry/codegraph 1.5.0 and 1.6.0 (npm latest), Linux, fresh codegraph init per run.

Repro — Python

# pkg/ledger.py
def append(row): return row
def path():      return "/x"
# pkg/uses.py
from . import ledger

def plain_identifier(out, k):
    out.append(k)                   # C: plain ident      -> no edge   (correct)

def chained_receiver(d, k, v):
    d.setdefault(k, []).append(v)   # D: call-expr recv   -> calls ledger.append  WRONG

Repro — JavaScript

// src/lib.js
export function push(row) { return row; }
export function path() { return "/x"; }
// src/use.js
import * as lib from './lib.js';

export function realNamespaceCall(row) {
  lib.push(row);              // A -> calls lib.push  "import"    (correct)
}
export function plainIdent(out, k) {
  out.push(k);                // C -> no edge                     (correct)
}
export function chained(m, k, v) {
  m.getOrInit(k, []).push(v); // D -> calls lib.push  "exact-match"  WRONG
}

Observed — both languages, identical

shape receiver edge
plain identifier (out.append(k)) ident none — correct
literal (", ".join(v)) literal none — correct (#1317)
namespace/module member ident resolves via import — correct
call expression (d.setdefault(k,[]).append(v)) call fabricated exact-match edge to the top-level append/push

Only the receiver shape differs between the correct and incorrect rows.

Impact

Any project with a top-level export named like a common collection method (append, push, get, update, run, close) accumulates fabricated inbound edges proportional to how often that method is used on chained locals elsewhere. callers/impact then return a populated, plausible list that is wrong — worse than an empty one, which is visibly wrong.

Suspected mechanism

In the extractor, the qualified receiver.method shape is preserved only when the receiver is a plain identifier; a call-chain receiver degrades to a bare method ref. That bare ref passes the codebase-wide name check (a real top-level symbol of that name exists) and is exact-matched as the sole candidate.

Verification

Both versions, both languages, fresh index each time; cross-checked via the codegraph CLI and direct SQL against .codegraph/codegraph.db, which agree.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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