fixup! Java Direct: implement main class finder functionality
diff --git a/compiler/java-direct/src/org/jetbrains/kotlin/java/direct/model/JavaTypeOverAst.kt b/compiler/java-direct/src/org/jetbrains/kotlin/java/direct/model/JavaTypeOverAst.kt index eaed996..1af76bc 100644 --- a/compiler/java-direct/src/org/jetbrains/kotlin/java/direct/model/JavaTypeOverAst.kt +++ b/compiler/java-direct/src/org/jetbrains/kotlin/java/direct/model/JavaTypeOverAst.kt
@@ -115,24 +115,17 @@ // were reordered after the nested-class lookup below. findTypeParameter(parts[0])?.let { return it } // 2. Inner/local class names (shadow INHERITED outer type params) - val localClass = findClassInCurrentScope(parts[0]) - if (localClass != null) return localClass + val localClass = findClassInCurrentScope(parts[0])?.let { return it } // 3. INHERITED type parameters from outer class (low priority — shadowed by inner classes) findInheritedTypeParameter(parts[0])?.let { return it } } - // In-scope navigation, kept as a distinct pass *before* the [resolve] fallback below — - // NOT redundant with it. Resolve the head via [findClassInCurrentScope], then walk each - // remaining part with [declaredOrFullyInherited] (declared members plus fully-inherited - // member types from any supertype representation). This pass is load-bearing because: - // - it does not depend on a `FirSession` symbol provider, whereas [resolve]'s - // class-existence probe does (which also helps with parser-only tests); - // - even with a session present it resolves in-scope references straight from the - // AST/model, avoiding a symbol-provider round-trip per segment. - // A missing segment off an in-scope head is a hard miss (`return null`, JLS 6.5.2): - // once `parts[0]` is a class in scope, the tail must be its member type, so we do not - // fall through to [resolve]'s package/import reinterpretation of the whole reference. - var current: JavaClassifier? = findClassInCurrentScope(Name.identifier(parts[0])) + // In-scope (AST/model) navigation, kept as a distinct pass *before* the [resolve] + // fallback below: + // - it needs no `FirSession` symbol provider, unlike [resolve]'s class-existence probe + // (so it also serves parser-only tests); + // - even with a session it avoids a symbol-provider round-trip per segment. + var current: JavaClassifier? = findClassInCurrentScope(parts[0]) if (current is JavaClass) { for (i in 1 until parts.size) {
diff --git a/compiler/java-direct/src/org/jetbrains/kotlin/java/direct/resolution/JavaInheritedClassResolver.kt b/compiler/java-direct/src/org/jetbrains/kotlin/java/direct/resolution/JavaInheritedClassResolver.kt index 934aaeb..ba51916 100644 --- a/compiler/java-direct/src/org/jetbrains/kotlin/java/direct/resolution/JavaInheritedClassResolver.kt +++ b/compiler/java-direct/src/org/jetbrains/kotlin/java/direct/resolution/JavaInheritedClassResolver.kt
@@ -101,18 +101,3 @@ } return foundClassId } - -internal fun fqNameInPackageToClassId(fqName: FqName, packageFqName: FqName): ClassId { - val fqnString = fqName.asString() - val pkgString = packageFqName.asString() - - val className = if (pkgString.isEmpty()) { - fqnString - } else if (fqnString.startsWith(pkgString) && fqnString.length > pkgString.length && fqnString[pkgString.length] == '.') { - fqnString.substring(pkgString.length + 1) - } else { - fqnString - } - - return ClassId(packageFqName, FqName(className), isLocal = false) -}
diff --git a/compiler/java-direct/src/org/jetbrains/kotlin/java/direct/resolution/JavaTypeResolver.kt b/compiler/java-direct/src/org/jetbrains/kotlin/java/direct/resolution/JavaTypeResolver.kt index a1b7b65..937ac04 100644 --- a/compiler/java-direct/src/org/jetbrains/kotlin/java/direct/resolution/JavaTypeResolver.kt +++ b/compiler/java-direct/src/org/jetbrains/kotlin/java/direct/resolution/JavaTypeResolver.kt
@@ -6,7 +6,6 @@ package org.jetbrains.kotlin.java.direct.resolution import org.jetbrains.annotations.TestOnly -import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin import org.jetbrains.kotlin.fir.declarations.FirRegularClass @@ -60,13 +59,11 @@ parts: List<String>, fullResolution: Boolean, ): ClassId? { - // Try every split point of `parts` into an outer-class prefix and a nested-class tail, from - // the shortest outer prefix up. Every split is tried (not just the last one, `outerParts = - // parts[0..n-2]`) because the outer/nested boundary is not known up front: for `a.b.C.D` the - // outer class might be `a.b.C` (tail `D`) or `a.b` might be the package with `C.D` a two-part - // nested chain. Each candidate outer prefix is resolved with the same rules (recursively for - // multi-part prefixes), so JLS 6.5.2 is respected — a nested-class interpretation wins as soon - // as the outer prefix resolves to a class in scope. + // Try each split of `parts` into an outer-class prefix and a nested tail, shortest prefix first. + // The boundary isn't known up front (for `a.b.C.D`, the outer class could be `a.b.C` with tail + // `D`, or `a.b` with `C.D` a two-part nested tail), so every split is tried; each prefix resolves + // by the same rules (recursively when multi-part). Per JLS 6.5.2, the first prefix resolving to a + // class in scope wins. require(parts.size > 1) for (i in 1 until parts.size) { val outerParts = parts.subList(0, i) @@ -75,7 +72,7 @@ val outerClassId = if (outerParts.size > 1) { resolveQualifiedNameToClassIdFromParts(outerParts, fullResolution) } else { - resolveSimpleNameToClassIdImpl(outerParts[0], fullResolution = fullResolution) + resolveSimpleNameToClassIdImpl(outerParts[0], fullResolution) } if (outerClassId != null) { @@ -85,17 +82,11 @@ val nestedClassId = ClassId(outerClassId.packageFqName, nestedClassName, isLocal = false) if (classExists(nestedClassId, fullResolution)) return nestedClassId - // Nested class not directly declared — search the outer class's supertypes for an - // inherited inner class. Handles cases like `SimpleFunctionDescriptor.CopyBuilder`, - // where `CopyBuilder` is declared in the `FunctionDescriptor` superinterface but - // referenced via the subtype `SimpleFunctionDescriptor`. - // - // Restricted to a single inherited segment. A tail of size >= 2 (e.g. resolving - // `Outer.CopyBuilder.Deeper`) is reached one recursion level down: the split at the - // next `i` resolves `outerClassId` for the prefix `Outer.CopyBuilder` via the recursive - // `resolveQualifiedNameToClassIdFromParts` call above, and that call's own loop hits its - // `i` where `nestedParts == [CopyBuilder]` (size 1) and performs the inherited lookup - // there. So every "outer class plus one inherited segment" sub-problem is still covered. + // Not directly declared — search the outer class's supertypes for an inherited inner + // class (e.g. `SimpleFunctionDescriptor.CopyBuilder`, where `CopyBuilder` comes from the + // `FunctionDescriptor` superinterface). Restricted to a single tail segment; longer tails + // (`Outer.CopyBuilder.Deeper`) are covered one recursion level down, where the prefix + // `Outer.CopyBuilder` resolves and its own loop reaches a size-1 tail. if (fullResolution && nestedParts.size == 1) { val inherited = findInheritedNestedClass(outerClassId, nestedParts[0]) if (inherited != null) return inherited @@ -234,10 +225,7 @@ context(c: JavaResolutionContext) private fun resolveFromJavaLang(simpleName: String, fullResolution: Boolean): ClassId? { val classId = ClassId(FqName("java.lang"), Name.identifier(simpleName)) - if (JavaToKotlinClassMap.mapJavaToKotlin(classId.asSingleFqName()) != null || classExists(classId, fullResolution)) { - return classId - } - return null + return if (classExists(classId, fullResolution)) classId else null } /** @@ -574,8 +562,19 @@ } context(c: JavaResolutionContext) -private fun fqNameToClassId(fqName: FqName): ClassId = - fqNameInPackageToClassId(fqName, c.packageFqName) +private fun fqNameToClassId(fqName: FqName): ClassId { + val fqnString = fqName.asString() + val pkgString = c.packageFqName.asString() + val className = if (pkgString.isEmpty()) { + fqnString + } else if (fqnString.startsWith(pkgString) && fqnString.length > pkgString.length && fqnString[pkgString.length] == '.') { + fqnString.substring(pkgString.length + 1) + } else { + fqnString + } + return ClassId(c.packageFqName, FqName(className), isLocal = false) +} + /** * Resolves a FqName to a ClassId by trying all package/class splits from longest package to