From 164c72e8772ab2206c7d0bbc0e3dd127bb2794cc Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Thu, 29 Dec 2016 18:38:35 +0300 Subject: [PATCH] Prefer package with class files to class with the same name See comments in JvmDependenciesIndexImpl and in the test #KT-15464 Fixed --- .../cli/jvm/index/JvmDependenciesIndexImpl.kt | 17 +++++++++---- .../library1/test/Boo.java | 5 ++++ .../library1/test/Foo.java | 6 +++++ .../library2/test/Boo/SubBoo/C.java | 5 ++++ .../library2/test/Foo/Bar.java | 4 ++++ .../innerClassPackageConflict2/output.txt | 10 ++++++++ .../innerClassPackageConflict2/source.kt | 14 +++++++++++ ...ompileKotlinAgainstCustomBinariesTest.java | 24 +++++++++++++++++++ 8 files changed, 80 insertions(+), 5 deletions(-) create mode 100644 compiler/testData/compileKotlinAgainstCustomBinaries/innerClassPackageConflict2/library1/test/Boo.java create mode 100644 compiler/testData/compileKotlinAgainstCustomBinaries/innerClassPackageConflict2/library1/test/Foo.java create mode 100644 compiler/testData/compileKotlinAgainstCustomBinaries/innerClassPackageConflict2/library2/test/Boo/SubBoo/C.java create mode 100644 compiler/testData/compileKotlinAgainstCustomBinaries/innerClassPackageConflict2/library2/test/Foo/Bar.java create mode 100644 compiler/testData/compileKotlinAgainstCustomBinaries/innerClassPackageConflict2/output.txt create mode 100644 compiler/testData/compileKotlinAgainstCustomBinaries/innerClassPackageConflict2/source.kt diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/index/JvmDependenciesIndexImpl.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/index/JvmDependenciesIndexImpl.kt index 71d657a0003..85943c24419 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/index/JvmDependenciesIndexImpl.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/index/JvmDependenciesIndexImpl.kt @@ -16,6 +16,9 @@ package org.jetbrains.kotlin.cli.jvm.index +import com.intellij.ide.highlighter.JavaClassFileType +import com.intellij.ide.highlighter.JavaFileType +import com.intellij.openapi.vfs.VfsUtilCore import com.intellij.openapi.vfs.VirtualFile import com.intellij.util.containers.IntArrayList import org.jetbrains.kotlin.name.ClassId @@ -236,15 +239,19 @@ class JvmDependenciesIndexImpl(_roots: List): JvmDependenciesIndex { private fun VirtualFile.findChildPackage(subPackageName: String, rootType: JavaRoot.RootType): VirtualFile? { val childDirectory = findChild(subPackageName) ?: return null - // Resolve conflicts between files and packages with the same qualified name in favor of files val fileExtension = when (rootType) { - JavaRoot.RootType.BINARY -> ".class" - JavaRoot.RootType.SOURCE -> ".java" + JavaRoot.RootType.BINARY -> JavaClassFileType.INSTANCE.defaultExtension + JavaRoot.RootType.SOURCE -> JavaFileType.INSTANCE.defaultExtension } - if (findChild(subPackageName + fileExtension)?.isDirectory == false) { - return null + // If in addition to a directory "foo" there's a class file "foo.class" AND there are no classes anywhere in the directory "foo", + // then we ignore the directory and let the resolution choose the class "foo" instead. + if (findChild("$subPackageName.$fileExtension")?.isDirectory == false) { + if (VfsUtilCore.processFilesRecursively(childDirectory) { file -> file.extension != fileExtension }) { + return null + } } + return childDirectory } diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/innerClassPackageConflict2/library1/test/Boo.java b/compiler/testData/compileKotlinAgainstCustomBinaries/innerClassPackageConflict2/library1/test/Boo.java new file mode 100644 index 00000000000..2d2a874fb9a --- /dev/null +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/innerClassPackageConflict2/library1/test/Boo.java @@ -0,0 +1,5 @@ +package test; + +public class Boo { + public interface Nested {} +} diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/innerClassPackageConflict2/library1/test/Foo.java b/compiler/testData/compileKotlinAgainstCustomBinaries/innerClassPackageConflict2/library1/test/Foo.java new file mode 100644 index 00000000000..6cccd522992 --- /dev/null +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/innerClassPackageConflict2/library1/test/Foo.java @@ -0,0 +1,6 @@ +package test; + +public class Foo { + public interface Nested { + } +} diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/innerClassPackageConflict2/library2/test/Boo/SubBoo/C.java b/compiler/testData/compileKotlinAgainstCustomBinaries/innerClassPackageConflict2/library2/test/Boo/SubBoo/C.java new file mode 100644 index 00000000000..2675c1b4c55 --- /dev/null +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/innerClassPackageConflict2/library2/test/Boo/SubBoo/C.java @@ -0,0 +1,5 @@ +package test.Boo.SubBoo; + +public class C { + public interface Nested {} +} diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/innerClassPackageConflict2/library2/test/Foo/Bar.java b/compiler/testData/compileKotlinAgainstCustomBinaries/innerClassPackageConflict2/library2/test/Foo/Bar.java new file mode 100644 index 00000000000..cd456e01487 --- /dev/null +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/innerClassPackageConflict2/library2/test/Foo/Bar.java @@ -0,0 +1,4 @@ +package test.Foo; + +public class Bar { +} diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/innerClassPackageConflict2/output.txt b/compiler/testData/compileKotlinAgainstCustomBinaries/innerClassPackageConflict2/output.txt new file mode 100644 index 00000000000..a55bdb09fd0 --- /dev/null +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/innerClassPackageConflict2/output.txt @@ -0,0 +1,10 @@ +compiler/testData/compileKotlinAgainstCustomBinaries/innerClassPackageConflict2/source.kt:10:9: error: unresolved reference: Nested +val v3: Nested? = null + ^ +compiler/testData/compileKotlinAgainstCustomBinaries/innerClassPackageConflict2/source.kt:11:18: error: unresolved reference: Nested +val v4: test.Foo.Nested? = null + ^ +compiler/testData/compileKotlinAgainstCustomBinaries/innerClassPackageConflict2/source.kt:14:18: error: unresolved reference: Nested +val v6: test.Boo.Nested? = null + ^ +COMPILATION_ERROR \ No newline at end of file diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/innerClassPackageConflict2/source.kt b/compiler/testData/compileKotlinAgainstCustomBinaries/innerClassPackageConflict2/source.kt new file mode 100644 index 00000000000..1fe5612c8b4 --- /dev/null +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/innerClassPackageConflict2/source.kt @@ -0,0 +1,14 @@ +import test.Foo.* + +// Note that unlike in Java, in Kotlin we currently mostly prefer package to class in qualified name resolution. +// So here, for example, we see both the package and the class with the name test.Foo, and prefer the former. +// So 'Bar' should be resolved, 'Nested' should be unresolved. +// For javac, the opposite is true: 'Bar' would be unresolved in a similar situation, 'Nested' would be resolved. + +val v1: Bar? = null +val v2: test.Foo.Bar? = null +val v3: Nested? = null +val v4: test.Foo.Nested? = null + +val v5: test.Boo.SubBoo.C.Nested? = null +val v6: test.Boo.Nested? = null diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstCustomBinariesTest.java b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstCustomBinariesTest.java index 2901560d2a8..b6e0863f284 100644 --- a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstCustomBinariesTest.java +++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstCustomBinariesTest.java @@ -20,6 +20,7 @@ import com.google.common.collect.Iterables; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.io.FileUtil; import com.intellij.util.ArrayUtil; +import com.intellij.util.Processor; import kotlin.Pair; import kotlin.collections.SetsKt; import kotlin.io.FilesKt; @@ -565,4 +566,27 @@ public class CompileKotlinAgainstCustomBinariesTest extends TestCaseWithTmpdir { Pair output = compileKotlin("source.kt", tmpdir, jarPath); KotlinTestUtils.assertEqualsToFile(new File(getTestDataDirectory(), "output.txt"), normalizeOutput(output)); } + + public void testInnerClassPackageConflict2() throws Exception { + final File library1 = compileJava("library1"); + final File library2 = compileJava("library2"); + + // Copy everything from library2 to library1 + FileUtil.visitFiles(library2, new Processor() { + @Override + public boolean process(File file) { + if (!file.isDirectory()) { + File newFile = new File(library1, FilesKt.relativeTo(file, library2).getPath()); + if (!newFile.getParentFile().exists()) { + assert newFile.getParentFile().mkdirs(); + } + assert file.renameTo(newFile); + } + return true; + } + }); + + Pair output = compileKotlin("source.kt", tmpdir, library1); + KotlinTestUtils.assertEqualsToFile(new File(getTestDataDirectory(), "output.txt"), normalizeOutput(output)); + } }