Skip to content

fix(ts): resolve static calls made through the class name - #810

Open
kunalgoesbyken wants to merge 1 commit into
trailhq:mainfrom
kunalgoesbyken:fix/ts-static-method-calls-dropped
Open

kunalgoesbyken wants to merge 1 commit into
trailhq:mainfrom
kunalgoesbyken:fix/ts-static-method-calls-dropped

Conversation

@kunalgoesbyken

Copy link
Copy Markdown
Contributor

Summary

Cache.create() names the class as the receiver, but a TS/JS receiver with no local binding got no type, so the call was dropped and callers Cache.create found nothing, in the same file or imported.

Changes

  • extract.ts: collect the names that stand for a class in a file: a class declared there, and a named import from a relative module, mapped to the class's own name (import { Cache as Store } reads Store as Cache). A function drops any of these names it declares again, as a local, a parameter (including an arrow callback's), a nested function or a class.
  • bindings.ts: resolveRecvType reads a receiver in that set as the class. An external, default or namespace import, and a local value such as const Cache = {...}, are not in it and still drop. A class that owns no such method (Math.max, Promise.all) finds no owner-qualified match and drops as before.
$ graft callers Cache.create      # before
create · method · cache.ts:L2-L4
  no indexed callers

$ graft callers Cache.create      # after
create · method · cache.ts:L2-L4
  calls ← local (cache.ts:L7-L9)
      8: return Cache.create();
  calls ← build (use.ts:L3-L5)
      4: return Cache.create();

Two classes with the same name in different files stay ambiguous and drop, and a static and an instance method of the same name in one class still collapse to one target, both as before.

Testing

On Windows 11 with Node 26:

  • test/graph-ts-static.test.ts (new): same-file, imported and .js calls, a capitalised receiver without the method and a parameter named like a class, and the cases that must not resolve: an external named, default or namespace import, a local object named like the class, a callback parameter that shadows it (with a later call in the same file still resolving), and an aliased relative import that does. All three fail on main.
  • test/graph*, blast*, ask*, generic*, depth*, resolve* and covers* suites: 675 tests, 1 fail. The one failure is discoverWorkspaceChildren follows a symlinked child repo, a symlink permission error on Windows that fails the same way on main.
  • tsc --noEmit passes.

Fixes #809

`Cache.create()` names the class itself as the receiver, but a TS/JS
receiver with no local binding gave no type, so the call was dropped and
`callers Cache.create` found nothing, in the same file or imported.

Read a capitalised receiver as the class when the file declares that class
or imports it by name from a relative module (an alias maps to the class's
own name). An external, default or namespace import, a local value such as
`const Cache = {...}`, and a parameter or nested declaration of the same
name are not the class and still drop, as does a class that owns no such
method (`Math.max`).
@trailhq-graft

trailhq-graft Bot commented Nov 10, 2026 •

Copy link
Copy Markdown

🌱 graft blast radius

1 area changed → 2 areas can be affected. 4 dependent symbols, depth 2.
Tests: no test reaches AST Traversal.
Tag: @shhdwi — 3 of 3 areas · @anirudhkumar-nanonets — Graph Construction · @Faeeth — Overlap Detection

flowchart TB
  A0(("Graph Construction<br/>3 symbols"))
  A1(("Overlap Detection<br/>1 symbol"))
  classDef reached fill:#D9EDF3,stroke:#3AA7C9,stroke-width:1.5px,color:#0E313C;
  class A0,A1 reached;
Loading
Can be affected Symbols Nearest hop Reached from
Graph Construction 3 src/graph/build.ts:L217-L492 buildGraph — calls, depth 2 AST Traversal
Overlap Detection 1 src/notes/edit-overlap.ts:L79-L94 symbolsIn — calls, depth 2 AST Traversal
Who knows this code — 3 people across 3 areas
Area Who knows it
AST Traversal · changed @shhdwi — 7 commits, last 13d ago
Graph Construction · affected @anirudhkumar-nanonets — 19 commits, last 27d ago · @shhdwi — 9 commits, last 13d ago
Overlap Detection · affected @Faeeth — 1 commit, last 2d ago · @shhdwi — 1 commit, last 18d ago

Ownership is git history over each area's own files, weighted towards recent work (120-day half-life). Merge commits and bots are dropped, and you are dropped from your own PR. A name with no @ has no GitHub handle in its commit email — tag them by hand, or add a .mailmap entry. A suggestion from history, not a CODEOWNERS rule.

All 4 dependent symbols, grouped by area

Graph Construction — 3 symbols in 3 files

  • src/graph/build.ts:L217-L492 — buildGraph (calls, depth 2)
  • src/graph/check.ts:L59-L159 — checkGraph (calls, depth 2)
  • src/graph/container.ts:L204-L269 — extractContainer (calls, depth 2)

Overlap Detection — 1 symbol in 1 file

  • src/notes/edit-overlap.ts:L79-L94 — symbolsIn (calls, depth 2)
Test signal per changed area — 1 ✗

Reached = a node under a test path has a resolved edge into the changed symbol. It undercounts anything called indirectly — through a CLI, a spawned process or a dynamic import — so read a low ratio as “look here”, never as a coverage gate.

  • ✗ AST Traversal — 0 of 6 reached · no test file reaches it
    • not reached: resolveRecvType, extractTree, walk, collectTsClassRefs, collect, visit
12 test suites also reference this code

16 symbols, kept out of the diagram and the table so they cannot crowd out the areas a reviewer has to look at.

  • test/ask-index.test.ts
  • test/depth-grammars.test.ts
  • test/generic-node24-probe.ts
  • test/graph-bindings.test.ts
  • test/graph-extract-dedup.test.ts
  • test/graph-php-references.test.ts
  • test/graph-php.test.ts
  • test/graph-r-phase3.test.ts
  • test/graph-r-phase5.test.ts
  • test/graph-resolve-imported-calls.test.ts
  • test/graph-resolve-typed.test.ts
  • test/graph-swift.test.ts

graft blast · origin/main...HEAD · depth 2 · 3 changed files

Open the interactive graph → — click an area to see its dependent symbols at file:line.

github-actions Bot added a commit that referenced this pull request Nov 10, 2026

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TS/JS: static calls through the class name (Cache.create()) produce no call edge

1 participant