Repository navigation
Description
A call two fields deep from this (this.a.b.m()) is matched by the bare name m. It links to any project symbol with that name: an unrelated class's method, or even a non-callable interface field.
// heap.ts
export class BinaryHeap { push(x: number): void {} }
export interface Conf { includes: string[]; }
// use.ts
export class Scene {
cache = { list: [] as number[], names: [] as string[] };
a() { this.cache.list.push(1); }
b(t: string) { return this.cache.names.includes(t); }
}
export function c(o: { data: number[] }) { o.data.push(1); }
export function d(w: { dbg?: { data: number[] } }) { w.dbg?.data.push(1); }
export function e(list: number[]) { list.push(1); }| call | edge on main |
expected |
|---|---|---|
this.cache.list.push(1) |
BinaryHeap.push (exact-match) |
none |
this.cache.names.includes(t) |
Conf.includes, a string[] field (exact-match) |
none |
o.data.push(1) |
none | none |
w.dbg?.data.push(1) |
none | none |
list.push(1) |
none | none |
Only the this-rooted chain falls through to name matching. The same depth on a parameter correctly links nothing, so the receiver-evidence rule for built-in method names (#2028) seems to be skipped for this shape. A calls edge to a property is wrong whatever the receiver.
Reproduced on main at 31ec908 (6162d872 since then only touches the watcher), with CODEGRAPH_KERNEL=0. Linux/WSL2, Node 22.23.2.
Scale (found by checking every TS calls edge against the TypeScript checker). 44 edges on excalidraw (14bb42e) and 15 on this repo. Examples:
this.extractor?.functionTypes.includes(nodeType)insrc/extraction/tree-sitter.ts:1132links to theincludes: string[]field insrc/extraction/kernel/loader.ts.this.collab.excalidrawAPI.getSceneElementsIncludingDeleted()in excalidraw'sexcalidraw-app/collab/Portal.tsxlinks toCollab's own same-named method rather than the API's.
Expected. Type the chain through the field declarations where they are known. Failing that, give the call the same treatment as o.data.push(): no edge for a built-in name, and never an edge to a property. Rust had the same shape in #2836, fixed by #2846 (keep the whole receiver chain). #1792 (shipped in 1.6.1) covers the one-level this.<field>.m(); #920 was closed as covered by it.
Related: #2836, #2846, #920, #2028, and #1566 (closed: built-in Map.get/set landing on project methods), the general case this shape still escapes.
Edited 2026-11-04: re-checked on main at f72c9d2 (with CODEGRAPH_KERNEL=0 and with the native kernel, Node 22.22.2): still reproduces. Corrected the status of #920: it was open when I filed this and has since been closed in favor of #1792. The in-repo line numbers have moved since filing.
Activity
inth3shadows commentedon Oct 29, 2026
Re-checked on
mainat 60b0d7a (2026-10-29): still reproduces as described.More real cases from codegraph's own source, found by diffing call edges against
scip-typescript:this.detectionInputs.diskPaths.has(rel)(src/extraction/index.ts:2307), wherediskPathsis declared as aMap<string, string>on the field's type, links toLRUCache::hasinsrc/resolution/lru-cache.ts..set(...)on the same line links toLRUCache::set.this.extractor.functionTypes.includes(nodeType)(src/extraction/tree-sitter.ts:1134, 1653), astring[], links to the propertyCfnptrFactsOut::includes.Library-typed locals elsewhere in the same file follow the patterns of #2947 and #2946:
ignore().add(...)followed by.ignores(...)links toScopeIgnore::ignores;defaultsOnlyIgnore(), then.ignores(...), does the same.I filed these again by mistake as #3036, which is now closed in favour of this issue, #2947 and #2946.