fixup! Java Direct: implement main class finder functionality
diff --git a/compiler/java-direct/src/org/jetbrains/kotlin/java/direct/model/JavaClassOverAst.kt b/compiler/java-direct/src/org/jetbrains/kotlin/java/direct/model/JavaClassOverAst.kt
index a277e58..0634504 100644
--- a/compiler/java-direct/src/org/jetbrains/kotlin/java/direct/model/JavaClassOverAst.kt
+++ b/compiler/java-direct/src/org/jetbrains/kotlin/java/direct/model/JavaClassOverAst.kt
@@ -303,11 +303,13 @@
         }
 
     override val constructors: Collection<JavaConstructor>
+        // A constructor is a METHOD node with no return TYPE (mirrors PSI's
+        // `getReturnTypeElement() == null`); the name is irrelevant. A malformed nameless
+        // declaration like `void () {}` — whose `void` is an error element, not a return type —
+        // is therefore a (package-private) constructor, matching PSI and suppressing the
+        // synthesized default constructor.
         get() = tree.getChildrenByType(node, JavaSyntaxElementType.METHOD)
-            .filter {
-                tree.findChildByType(it, JavaSyntaxElementType.TYPE) == null &&
-                        tree.findChildByType(it, JavaSyntaxTokenType.IDENTIFIER) != null
-            }
+            .filter { tree.findChildByType(it, JavaSyntaxElementType.TYPE) == null }
             .map { JavaConstructorOverAst(it, tree, this) }
 
     override val recordComponents: Collection<JavaRecordComponent>
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..cdb1a31 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
@@ -5,10 +5,11 @@
 
 package org.jetbrains.kotlin.java.direct.resolution
 
+import org.jetbrains.kotlin.descriptors.Visibilities
+import org.jetbrains.kotlin.descriptors.java.JavaVisibilities
 import org.jetbrains.kotlin.load.java.structure.JavaClass
 import org.jetbrains.kotlin.load.java.structure.impl.splitCanonicalFqName
 import org.jetbrains.kotlin.name.ClassId
-import org.jetbrains.kotlin.name.FqName
 import org.jetbrains.kotlin.name.Name
 
 /**
@@ -87,7 +88,7 @@
             if (!visited.add(ancestorId)) continue
 
             val innerClassId = ancestorId.createNestedClassId(Name.identifier(simpleName))
-            if (tryResolveInherited(innerClassId)) {
+            if (tryResolveInherited(innerClassId) && isInheritedNestedClassAccessible(innerClassId)) {
                 if (foundClassId != null && foundClassId != innerClassId) return null
                 foundClassId = innerClassId
             } else {
@@ -102,17 +103,23 @@
     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
+/**
+ * JLS 6.6 accessibility of an inherited nested class from the file being resolved. An inaccessible
+ * nested class is not inherited (JLS 8.2), so it is not in scope and must not shadow a same-named
+ * top-level or same-package class:
+ *  - `private` — never inherited;
+ *  - package-private — inherited only within the declaring package;
+ *  - `public` / `protected` (the reference site is always a subtype here) / Kotlin `internal`
+ *    (public in bytecode) — in scope.
+ *
+ * Defaults to accessible when the nested class cannot be materialised.
+ */
+context(c: JavaResolutionContext)
+private fun isInheritedNestedClassAccessible(innerClassId: ClassId): Boolean {
+    val nestedClass = classifierAdapterFor(innerClassId) ?: return true
+    return when (nestedClass.visibility) {
+        Visibilities.Private -> false
+        JavaVisibilities.PackageVisibility -> innerClassId.packageFqName == c.packageFqName
+        else -> true
     }
-
-    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
diff --git a/compiler/java-direct/test/org/jetbrains/kotlin/java/direct/JavaParsingBasicTest.kt b/compiler/java-direct/test/org/jetbrains/kotlin/java/direct/JavaParsingBasicTest.kt
index 19b90b0..3f63aea 100644
--- a/compiler/java-direct/test/org/jetbrains/kotlin/java/direct/JavaParsingBasicTest.kt
+++ b/compiler/java-direct/test/org/jetbrains/kotlin/java/direct/JavaParsingBasicTest.kt
@@ -65,33 +65,6 @@
     }
 
     @Test
-    fun testPublicClassWithMalformedMembers() {
-        val source = """
-            package p;
-            public class Nameless {
-                void () {}
-                int ;
-            }
-        """.trimIndent()
-        val parsed = parseSource(source)
-        val tree = parsed.tree
-        val classNode = tree.getChildrenByType(parsed.root, JavaSyntaxElementType.CLASS)
-            .first {
-                tree.findChildByType(it, JavaSyntaxTokenType.IDENTIFIER)?.let { id -> tree.getText(id).toString() } == "Nameless"
-            }
-        val javaClass = JavaClassOverAst(classNode, tree, parsed.context)
-        assert(javaClass.visibility.toString() == "public") {
-            "Expected public visibility for 'public class Nameless', got ${javaClass.visibility}"
-        }
-        assert(javaClass.constructors.isEmpty()) {
-            "Malformed 'void () {}' should not be treated as a constructor"
-        }
-        assert(javaClass.hasDefaultConstructor()) {
-            "Class with no valid constructors should have a default constructor"
-        }
-    }
-
-    @Test
     fun testWildcardAST() {
         val source = """
             import java.util.List;