Repository navigation
fix(js,ts): a nested function takes calls to a name the file imports from a package - #2855
Merged
Merged
Conversation
…from a package
When a JavaScript or TypeScript file imports a name from outside the
repository, like import { resolve } from 'node:path', matchByExactName
returns no edge for a bare call of that name (the early return main added
for issue 2101). A call to a function declared inside the calling function
under that name, which shadows the import, lost its edge with it.
The candidates for such a call are now narrowed to the calling file's
declarations nested in a function or method (innerScopeShadows), instead
of giving up; a top-level one is the import's own binding. Lexical
reachability, applied later, keeps only the nested declarations visible
where the call is.
Our changes: tests for a sibling function's nested declaration and one
nested a level below the call, which neither may take the call (both hold
through the reachability rule), and for a call from a function nested in
the declaring one; the CHANGELOG bullet moved next to the JS/TS import
bullets, with credit.
Validation: the tests fail 2 of 6 on main and pass here. A/B against main
on 8 repos, kernel per arm: flask, gin, excalidraw, codegraph, pixijs,
pdf.js and three.js byte-identical; vite gains 1 right link, scanImports'
call to its nested scan() beside import { scan } from
'rolldown/experimental'. Index CPU
time on codegraph, test files full of vitest imports, within noise:
81.7 s to 81.9 s (median of 3, interleaved).
Original PR #1715 by @danusha2345.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
danusha2345
pushed a commit
to danusha2345/codegraph
that referenced
this pull request
Oct 24, 2026
…mchenry#2876; 11 landed PRs yield to main; EXTRACTION_VERSION 55) Main landed eleven of our PRs as our own commits with the maintainer's additions (colbymchenry#2847, colbymchenry#2848, colbymchenry#2850, colbymchenry#2851, colbymchenry#2853, colbymchenry#2854, colbymchenry#2855, colbymchenry#2856, colbymchenry#2868, colbymchenry#2874, colbymchenry#2875), the traversal half of colbymchenry#2839 (colbymchenry#2860) and the trail hardening of colbymchenry#1667 (colbymchenry#2869). Where the integration carried our original version, main's wins: play.ts, routes.ts, the tsjs kernel extractor, import-resolver's PHP alias lookup, isDecisiveSameFileMatch, matchNewReceiverCall and the tests of those PRs. Kept beside main: colbymchenry#1952's enclosing-scope member pick, colbymchenry#1936's closest-copy confidence, colbymchenry#2258's Kotlin imported-type block, colbymchenry#1875's commitHdlProfile on indexFiles and hdlAccess, colbymchenry#1583's impact budget (the type-hierarchy walk itself is main's), colbymchenry#1736's C #if tests. 22 changelog bullets of closed PRs removed where main has its own wording. EXTRACTION_VERSION 55: Rust receiver chains (colbymchenry#2846), `new C().m` shapes (colbymchenry#2854), Java records (colbymchenry#2868), Go method exportedness (colbymchenry#2857), generic supertypes (colbymchenry#2856). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
In JavaScript and TypeScript, a function declared inside another function now takes the calls made to its name inside that function, even when the file also imports that name from a package:
On main such a call linked to nothing.
Root cause
When a bare call's name is imported from outside the repository,
matchByExactNamereturned no edge at all (the early return added for #2101), since the call means the package's function and no project symbol of that name. A declaration of the name in an inner scope of the calling file shadows the import, but the early return skipped it too.The fix (from the contributor)
For such a call, the candidates are narrowed to the calling file's own declarations that sit inside a function or method (
innerScopeShadows), instead of giving up. A top-level declaration is the import's own binding (var request = require('supertest')), not a shadow. The lexical-reachability rule already in the candidate filter (#1230) then keeps only a declaration that is in scope where the call is.What we changed on top
innerScopeShadowsaccepts a declaration nested in any function of the file, not only one around the call. It does, but the reachability rule later in the same filter drops one that isn't in scope. Two new cases pin that down, and both pass on main and here: a call in a sibling function next tofunction a() { function resolve() {} }, and one inouter()beside aresolvenested a level deeper inmid(). A third case checks the positive side: a call from a function nested inside the declaring one links to the declaration. It fails on main.Validation
out-of-repo-import-shadow.test.tsfails 2 of 6 on main (the two shadowing cases) and passes 6 of 6 here.packages/vite/src/node/optimizer/scan.tsimportsscanfromrolldown/experimentaland declaresasync function scan()insidescanImports, and the callconst result = scan()inscanImportsnow links to that nested function.The A/B was run against main 9c4794d and re-checked against main with fix(js,ts): a call on an element of a class field reaches the element's type #2852 in it (449eefa): vite again gains that one edge, and excalidraw is still identical. The tests fail 2 of 6 on today's main 0d46dba too.
expect/it, is within noise: 81.7 s → 81.9 s (median of 3, interleaved).CODEGRAPH_KERNEL_EXPECT=1 npx vitest run --maxWorkers=4 --minWorkers=1, on this commit): 759 files, 9,048 tests, 8,966 passed, 0 failed, 82 skipped.Lands #1715 by @danusha2345.
🤖 Generated with Claude Code