fix(resolution): resolve same-named methods to the call site's own file (#1079)#1107
Merged
Merged
Conversation
…le (#1079) When two files each declared a same-named class with a same-named method (e.g. `class Logger { void log(); }`), a call resolved to whichever definition was indexed first — so a call in `b/svc` wrongly targeted `a/svc`, mixing up that method's callers and blast radius. The reported case was C++ instance calls, but the underlying pattern — "multiple same-named candidates, pick the first-indexed, ignore the call site's file" — lived in three resolution paths, each firing for a different call shape and affecting different languages: - `obj.log()` instance -> resolveMethodOnType (C++) - `Logger.log()` class receiver -> matchMethodCall Strategy 1/2/3 (Python, TypeScript, Java, C#) - `Logger::log()` qualified -> matchByQualifiedName (C++, Rust) All five sites now share one helper, `preferCallSiteFile`, that prefers a candidate declared in the call site's own file when a name is ambiguous. It runs after the `preferredFqn` block in resolveMethodOnType, so Java/Kotlin import disambiguation (#314) — whose target is intentionally in another file — is unaffected. The helper is a no-op when there are fewer than two candidates or none share the call site's file, so the common single-definition case is unchanged. Adds 8 tests under `Same-name method disambiguation (#1079)`: the `preferCallSiteFile` contract, resolveMethodOnType precedence (including a guard that an import FQN still beats the same-file preference), `matchByQualifiedName` disambiguation, and end-to-end index tests for the C++ instance, TypeScript static, and C++ qualified call shapes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This was referenced Jul 1, 2026
Closed
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.
Closes #1079.
Problem
When two files each declared a same-named class with a same-named method —
class Logger { void log(); }in botha/svcandb/svc— a call resolved to whichever definition happened to be indexed first. So a call inb/wrongly pointed ata/'s method, mixing up that method's callers and blast radius.@inth3shadows reported this for C++ instance calls and diagnosed it precisely:
resolveMethodOnTypeonly disambiguated multiple matches when a Java/Kotlin import FQN was present (#314), and every other language fell through tomatches[0].Scope — it's a cross-language pattern, not one site
Validating "are other languages affected?" with two-file repros surfaced the same "pick the first-indexed, ignore the call site's file" pattern in three distinct resolution paths, each firing for a different call shape:
obj.log()— instanceresolveMethodOnTypeLogger.log()— class receivermatchMethodCallStrategy 1/2/3Logger::log()— qualifiedmatchByQualifiedName(The plain instance case only resolves to a method in C++ today — other languages don't infer a local variable's type, so they produced no edge rather than a wrong one. Constructor /
instantiatesresolution and the general name-match path were already file-aware via path proximity, which is why only these method paths were affected.)Fix
One shared helper —
preferCallSiteFile(nodes, callSiteFile)— prefers a candidate declared in the call site's own file when a name is ambiguous, and is a no-op when there are fewer than two candidates or none share the file. Applied at all five sites (resolveMethodOnType, both branches ofmatchByQualifiedName, andmatchMethodCallStrategies 1/2/3).In
resolveMethodOnTypeit runs after thepreferredFqnblock, so Java/Kotlin import disambiguation (#314) — whose target is intentionally in another file — is unaffected.Tests
8 tests under
Same-name method disambiguation (#1079): thepreferCallSiteFilecontract,resolveMethodOnTypeprecedence (including a guard that an import FQN still beats the same-file preference, #314),matchByQualifiedNamedisambiguation, and end-to-end index tests for the C++ instance, TypeScript static, and C++ qualified call shapes. Full suite green (1905 passed).🤖 Generated with Claude Code