fix(resolution): resolve cross-file static method calls to the method, not the class (#825)#833
Open
maxmilian wants to merge 1 commit into
Open
Conversation
…, not the class (colbymchenry#825) `Foo.bar()` after `import { Foo } from './helpers'` was a `calls` ref whose named-import resolution matched the `Foo.` prefix and resolved the receiver to the class `Foo`. createEdges then promoted the `calls` edge to `instantiates` on the class and dropped the method, so callers/impact for the static method came back empty and a bare-name fallback surfaced unrelated same-named symbols. When the imported receiver is a class/struct and the trailing member names one of its methods, resolve to that method — keyed on the exact owner segment of the qualifiedName so a substring-named sibling (`FooBar::bar`) can't soak the call. Genuine `new Foo()` construction still instantiates. Co-Authored-By: Claude Opus 4.8 (1M context) <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.
Fixes #825.
Problem
A cross-file static method call resolves to the class, not the method, and is then recorded as a construction:
codegraph callers "Foo.bar"→ empty.runends up with a singleinstantiates → Fooedge and nocalls → Foo::bar, so callers/impact for the static method are empty (false negatives) and the CLI's bare-name fallback surfaces unrelated same-named symbols (false positives).Root cause
In
resolveViaImport(src/resolution/import-resolver.ts), the generic named-import loop matchesref.referenceName.startsWith(imp.localName + '.')for the refFoo.bar. For a non-namespace importmemberNameis leftnull, sofindExportedSymbolreturns the classFoo.resolveViaImportreturns that at confidence0.9, andresolveOnereturns immediately — so the name-matcher'smatchMethodCall(which already resolvesFoo.bar→Foo::barvia its class-name strategy) never runs.createEdgesthen promotes thecallsedge toinstantiatesbecause the target is a class, dropping the method.So the
calls → instantiatespromotion is the relabel; the actual interception is the import resolver picking the class as the target. Guarding the promotion alone would leave the edge pointing at the class with the method still dropped — hence the fix is in the import resolver.Fix
When the imported receiver is a
class/structand thecallsref is shapedlocalName.member, resolve the trailing member to that class's method (keyed on the exact owner segment of the qualifiedName, so a substring-named sibling likeFooBar::barcan't soak the call) and return it — preserving the exact-file precision the import gives over a name-match fallback. If no matching method exists, behavior is unchanged. Genuinenew Foo()construction is unaffected (stillinstantiates).Tests
Added a regression test in
__tests__/resolution.test.tsthat locks:run --calls--> Foo::bar(exactly one edge), not mis-promoted toinstantiatesFooBar::bargetCallers(Foo::bar)surfacesrunnew Foo()boundary still instantiates the classFull suite green locally (
npm run build && npm test): 1429 passed, 2 skipped.🤖 Generated with Claude Code