Summary
#1730 fixed call-edge resolution for renamed imports used as a bare call (import { collectFiles as collectFilesUtil } from './helpers'; collectFilesUtil()). While verifying that fix I found a distinct, still-broken variant: a renamed import used as a receiver (import { X as Y } from './mod'; Y.method()) does not resolve at all — no calls edge is created.
This is empirically confirmed (not speculative) — see repro below with raw DB inspection.
Repro
// helpers.js
export const NamespaceObj = {
doThing() { return 1; },
};
// consumer.js
import { NamespaceObj as NsAlias } from './helpers.js';
export function useReceiver() {
return NsAlias.doThing();
}
After codegraph build, querying edges shows useReceiver has no outgoing calls edge to doThing / NamespaceObj.doThing at all — the call is silently dropped. (Verified with sqlite3 directly against edges/nodes tables — useReceiver produces zero rows in edges.)
Root cause
This does not go through resolveCallTargets's import-aware branch (the one #1730 fixed) — doThing itself was never imported, only NsAlias was, so importedNames.get('doThing') is never populated. The call falls through to resolveByMethodOrGlobal → resolveByReceiver (src/domain/graph/resolver/strategy.ts) → resolveViaDirectQualifiedMethod:
function resolveViaDirectQualifiedMethod(
lookup: StrategyLookup,
effectiveReceiver: string,
call: { name: string },
relPath: string,
): ReadonlyArray<{ id: number; file: string }> {
const qualifiedName = `${effectiveReceiver}.${call.name}`;
return lookup.byName(qualifiedName) ...
}
effectiveReceiver here is the literal call-site receiver text (NsAlias), so it builds the qualified name NsAlias.doThing — but the actual definition is stored as NamespaceObj.doThing (the object literal's original name). The lookup misses because resolveByReceiver/resolveViaDirectQualifiedMethod has no way to know NsAlias is a renamed alias for NamespaceObj.
I have not checked whether the native Rust resolver (crates/codegraph-core/src/domain/graph/builder/stages/build_edges.rs, the receiver/qualified-method resolution branch of resolve_call_targets) has the identical gap — likely, given the mirrored-engine convention, but not yet confirmed.
Expected
When a call's receiver is itself a renamed import local name, receiver-based qualified-method resolution should substitute the original exported name (the same Import.renamedImports / RenamedImport data #1730 introduced) before building the qualified lookup key, so NsAlias.doThing resolves via NamespaceObj.doThing.
Scope note
Deliberately not fixed as part of #1730 — different resolution strategy entirely (resolveByReceiver/resolveViaDirectQualifiedMethod in resolver/strategy.ts, not resolveCallTargets's import-aware branch), and #1730's own repro (a bare function call) doesn't exercise this path.
Summary
#1730 fixed call-edge resolution for renamed imports used as a bare call (
import { collectFiles as collectFilesUtil } from './helpers'; collectFilesUtil()). While verifying that fix I found a distinct, still-broken variant: a renamed import used as a receiver (import { X as Y } from './mod'; Y.method()) does not resolve at all — nocallsedge is created.This is empirically confirmed (not speculative) — see repro below with raw DB inspection.
Repro
After
codegraph build, querying edges showsuseReceiverhas no outgoingcallsedge todoThing/NamespaceObj.doThingat all — the call is silently dropped. (Verified with sqlite3 directly againstedges/nodestables —useReceiverproduces zero rows inedges.)Root cause
This does not go through
resolveCallTargets's import-aware branch (the one #1730 fixed) —doThingitself was never imported, onlyNsAliaswas, soimportedNames.get('doThing')is never populated. The call falls through toresolveByMethodOrGlobal→resolveByReceiver(src/domain/graph/resolver/strategy.ts) →resolveViaDirectQualifiedMethod:effectiveReceiverhere is the literal call-site receiver text (NsAlias), so it builds the qualified nameNsAlias.doThing— but the actual definition is stored asNamespaceObj.doThing(the object literal's original name). The lookup misses becauseresolveByReceiver/resolveViaDirectQualifiedMethodhas no way to knowNsAliasis a renamed alias forNamespaceObj.I have not checked whether the native Rust resolver (
crates/codegraph-core/src/domain/graph/builder/stages/build_edges.rs, the receiver/qualified-method resolution branch ofresolve_call_targets) has the identical gap — likely, given the mirrored-engine convention, but not yet confirmed.Expected
When a call's receiver is itself a renamed import local name, receiver-based qualified-method resolution should substitute the original exported name (the same
Import.renamedImports/RenamedImportdata #1730 introduced) before building the qualified lookup key, soNsAlias.doThingresolves viaNamespaceObj.doThing.Scope note
Deliberately not fixed as part of #1730 — different resolution strategy entirely (
resolveByReceiver/resolveViaDirectQualifiedMethodinresolver/strategy.ts, notresolveCallTargets's import-aware branch), and #1730's own repro (a bare function call) doesn't exercise this path.