diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCliJavaFileManagerImpl.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCliJavaFileManagerImpl.kt index 7469338fc17..3eafef91c21 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCliJavaFileManagerImpl.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCliJavaFileManagerImpl.kt @@ -174,6 +174,15 @@ class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager) : CoreJ val result = ArrayList(1) forEachClassId(qName) { classId -> val relativeClassName = classId.relativeClassName.asString() + + // Search java sources first. For build tools, it makes sense to build new files passing all the + // class files for the previous build on the class path. + result.addIfNotNull( + singleJavaFileRootsIndex.findJavaSourceClass(classId) + ?.takeIf { it in scope } + ?.findPsiClassInVirtualFile(relativeClassName) + ) + index.traverseDirectoriesInPackage(classId.packageFqName) { dir, rootType -> val psiClass = findVirtualFileGivenPackage(dir, relativeClassName, rootType) @@ -186,12 +195,6 @@ class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager) : CoreJ true } - result.addIfNotNull( - singleJavaFileRootsIndex.findJavaSourceClass(classId) - ?.takeIf { it in scope } - ?.findPsiClassInVirtualFile(relativeClassName) - ) - if (result.isNotEmpty()) { return@time result.toTypedArray() } diff --git a/compiler/tests/org/jetbrains/kotlin/cli/JavaSourceInnerClassInClassPathTest.kt b/compiler/tests/org/jetbrains/kotlin/cli/JavaSourceInnerClassInClassPathTest.kt new file mode 100644 index 00000000000..8d0dff778a6 --- /dev/null +++ b/compiler/tests/org/jetbrains/kotlin/cli/JavaSourceInnerClassInClassPathTest.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.cli + +import org.jetbrains.kotlin.cli.common.ExitCode +import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler +import org.jetbrains.kotlin.test.TestCaseWithTmpdir + +class JavaSourceInnerClassInClassPathTest : TestCaseWithTmpdir() { + + // Test that a java source file for a class is taken before a class file for the same + // class on the class path. + fun test() { + val aJava = tmpdir.resolve("A.java").also { + it.writeText("class A { interface AInner { int foo(); } }") + } + val bJava = tmpdir.resolve("B.java").also { + it.writeText("class B implements A.AInner { public int foo() { return 42; } }") + } + val cKt = tmpdir.resolve("C.kt").also { + it.writeText("fun main() { B().foo() }") + } + val (output, exit) = AbstractCliTest.executeCompilerGrabOutput( + K2JVMCompiler(), + listOf(aJava.path, bJava.path, cKt.path, "-d", tmpdir.path, "-Xcompile-java", "-Xuse-javac") + ) + assert(exit == ExitCode.OK) { output } + val (output2, exit2) = AbstractCliTest.executeCompilerGrabOutput( + K2JVMCompiler(), + listOf(aJava.path, bJava.path, cKt.path, "-cp", tmpdir.path) + ) + assert(exit2 == ExitCode.OK) { output2 } + } +}