mirror of
https://github.com/colbymchenry/codegraph.git
synced 2026-11-15 03:08:20 +08:00
fix(kotlin): a call on an imported type reaches that package's class when two share a name
When several classes share a name, resolveMethodOnType picks the one the call file imports by matching the import's path against the candidate's file path (com/example/b/FooConverter.kt). That holds for Java, where a public class names its file, but a Kotlin class often lives in a file named otherwise (FooConverter in Converters.kt), so no candidate matched and the call went to whichever class came first. The imported name is now matched against each candidate's qualified name first: import com.example.b.FooConverter expects the method com.example.b::FooConverter::convert, which the package directive gives every JVM declaration whatever its file is called. The file-path match stays as the fallback. The Java calls this once fixed, a Java file calling a Kotlin class it imports (okhttp's Java tests and mockwebserver3.MockWebServer, SystemUI's BlurUtils), are now resolved on main by the receiver's declared type (#1942), so on today's main the change shows in Kotlin. From #539 we take only this change and its test. Its other two parts, indexing Kotlin class properties and reading Kotlin imports without a trailing semicolon, have since landed on main another way. Validation: - resolution.test.ts: the Kotlin same-name case (#314's shape in Converters.kt files) is red on main, green here. - A/B against main40f58517(with the Java receiver typing of #1942 and the Kotlin changes of #1933, #1761 and #2258): no edge changes on okhttp, SystemUI, nowinandroid, mihon, jextract, spring-modulith, Minestom, spring-ai, kestra-java, playframework, click or gin; none of them has the test's shape on a resolved call. Against main4eb8c2a5, before #1942, it moved the 8 Java calls above onto the Kotlin class their file imports; main now reaches them at 0.9. - Cost (mihon, median of 3 interleaved indexes, on main4eb8c2a5): CPU 25.7 s on main vs 25.2 s, wall 8.2 s vs 8.3 s. Original PR #539 by @arttttt. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
committed by
Colby Mchenry
co-authored by
Claude Opus 5.5
parent
40f5851787
commit
86c85cff02
@@ -13622,6 +13622,23 @@ export function resolveMethodOnType(
|
||||
if (chosen) return { original: ref, targetNodeId: chosen.id, confidence, resolvedBy };
|
||||
}
|
||||
if (matches.length > 1 && preferredFqn && ref.language !== 'go' && !ES_IMPORT_LANGUAGES.has(ref.language)) {
|
||||
// Prefer the candidate whose namespace-qualified name matches the imported
|
||||
// FQN. #412 indexes JVM declarations as `<pkg>::<Class>` from the file's
|
||||
// `package` directive — independent of the file name — so this disambiguates
|
||||
// Kotlin (where `FooConverter` can live in `Converters.kt`) that the
|
||||
// file-path-suffix heuristic below can't. `com.example.b.FooConverter`
|
||||
// → expected method qn `com.example.b::FooConverter::convert`.
|
||||
const lastDot = preferredFqn.lastIndexOf('.');
|
||||
if (lastDot > 0) {
|
||||
const expectedQn = `${preferredFqn.slice(0, lastDot)}::${preferredFqn.slice(lastDot + 1)}::${methodName}`;
|
||||
const byQn = matches.find((m) => m.qualifiedName === expectedQn);
|
||||
if (byQn) {
|
||||
return { original: ref, targetNodeId: byQn.id, confidence, resolvedBy };
|
||||
}
|
||||
}
|
||||
// Fall back to file-path-suffix match for Java's class-name = file-name
|
||||
// layout (covers files indexed before the namespace wrapper, or any case
|
||||
// the qn match misses).
|
||||
const ext = ref.language === 'kotlin' ? '.kt' : '.java';
|
||||
const fqnPath = preferredFqn.replace(/\./g, '/') + ext;
|
||||
const chosen = matches.find((m) => {
|
||||
|
||||
Reference in New Issue
Block a user