From c67eb843698c520e1f84383c86cf1fb2631e0d2e Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Fri, 24 Mar 2017 18:33:32 +0300 Subject: [PATCH] Support nested classes in KotlinCliJavaFileManagerImpl.findClass findClass(String, GlobalSearchScope) is invoked for example when we're resolving supertypes of classes in Java libraries. Previously, it never found nested classes and falled back to CoreJavaFileManager's implementation, which lacks a fix for the original issue (KT-12664, which was fixed in JvmDependenciesIndex in 5a533a52 and 164c72e8) #KT-16931 Fixed --- .../compiler/KotlinCliJavaFileManagerImpl.kt | 29 +++++++++++++++---- .../library/test/Baz.java | 6 ++++ .../library/test/Foo.java | 2 +- .../innerClassPackageConflict/source.kt | 2 ++ .../kotlin/jps/build/KotlinJpsBuildTest.kt | 7 ++--- .../kotlinProject.iml | 0 .../kotlinProject.ipr | 0 .../src/JavaWithInner.java | 0 .../src/test.kt | 0 9 files changed, 35 insertions(+), 11 deletions(-) create mode 100644 compiler/testData/compileKotlinAgainstCustomBinaries/innerClassPackageConflict/library/test/Baz.java rename jps-plugin/testData/general/{SourcePackagePrefixKnownIssueWithInnerClasses => SourcePackagePrefixWithInnerClasses}/kotlinProject.iml (100%) rename jps-plugin/testData/general/{SourcePackagePrefixKnownIssueWithInnerClasses => SourcePackagePrefixWithInnerClasses}/kotlinProject.ipr (100%) rename jps-plugin/testData/general/{SourcePackagePrefixKnownIssueWithInnerClasses => SourcePackagePrefixWithInnerClasses}/src/JavaWithInner.java (100%) rename jps-plugin/testData/general/{SourcePackagePrefixKnownIssueWithInnerClasses => SourcePackagePrefixWithInnerClasses}/src/test.kt (100%) 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 007f591bb4b..b5f2ac06bb7 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 @@ -53,12 +53,31 @@ class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager) : CoreJ } } + // this method is called from IDEA to resolve dependencies in Java code + // which supposedly shouldn't have errors so the dependencies exist in general override fun findClass(qName: String, scope: GlobalSearchScope): PsiClass? { - // this method is called from IDEA to resolve dependencies in Java code - // which supposedly shouldn't have errors so the dependencies exist in general - // Most classes are top level classes so we will try to find them fast - // but we must sometimes fallback to support finding inner/nested classes - return qName.toSafeTopLevelClassId()?.let { classId -> findClass(classId, scope) } ?: super.findClass(qName, scope) + // String cannot be reliably converted to ClassId because we don't know where the package name ends and class names begin. + // For example, if qName is "a.b.c.d.e", we should either look for a top level class "e" in the package "a.b.c.d", + // or, for example, for a nested class with the relative qualified name "c.d.e" in the package "a.b". + // Below, we start by looking for the top level class "e" in the package "a.b.c.d" first, then for the class "d.e" in the package + // "a.b.c", and so on, until we find something. Most classes are top level, so most of the times the search ends quickly + + var classId = qName.toSafeTopLevelClassId() ?: return super.findClass(qName, scope) + + while (true) { + findClass(classId, scope)?.let { return it } + + val packageFqName = classId.packageFqName + if (packageFqName.isRoot) break + + classId = ClassId( + packageFqName.parent(), + FqName(packageFqName.shortName().asString() + "." + classId.relativeClassName.asString()), + false + ) + } + + return super.findClass(qName, scope) } override fun findClasses(qName: String, scope: GlobalSearchScope): Array { diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/innerClassPackageConflict/library/test/Baz.java b/compiler/testData/compileKotlinAgainstCustomBinaries/innerClassPackageConflict/library/test/Baz.java new file mode 100644 index 00000000000..24bdeb225d2 --- /dev/null +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/innerClassPackageConflict/library/test/Baz.java @@ -0,0 +1,6 @@ +package test; + +public class Baz implements Foo.Bar { + @Override + public void bar() {} +} diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/innerClassPackageConflict/library/test/Foo.java b/compiler/testData/compileKotlinAgainstCustomBinaries/innerClassPackageConflict/library/test/Foo.java index 93fc3998747..e67176fcedd 100644 --- a/compiler/testData/compileKotlinAgainstCustomBinaries/innerClassPackageConflict/library/test/Foo.java +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/innerClassPackageConflict/library/test/Foo.java @@ -2,6 +2,6 @@ package test; public class Foo { public interface Bar { - + void bar(); } } diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/innerClassPackageConflict/source.kt b/compiler/testData/compileKotlinAgainstCustomBinaries/innerClassPackageConflict/source.kt index bc8bfdcee8d..70438e02bd3 100644 --- a/compiler/testData/compileKotlinAgainstCustomBinaries/innerClassPackageConflict/source.kt +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/innerClassPackageConflict/source.kt @@ -1,3 +1,5 @@ import test.Foo.Bar +import test.Baz val f: Bar? = null +val g: Baz? = Baz().apply { bar() } diff --git a/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/build/KotlinJpsBuildTest.kt b/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/build/KotlinJpsBuildTest.kt index 80df674ea75..6111345beaf 100644 --- a/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/build/KotlinJpsBuildTest.kt +++ b/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/build/KotlinJpsBuildTest.kt @@ -277,12 +277,9 @@ class KotlinJpsBuildTest : AbstractKotlinJpsBuildTestCase() { assertEquals("Invalid package prefix name is ignored: invalid-prefix.test", warnings.first().messageText) } - fun testSourcePackagePrefixKnownIssueWithInnerClasses() { + fun testSourcePackagePrefixWithInnerClasses() { initProject() - val buildResult = buildAllModules() - buildResult.assertFailed() - val errors = buildResult.getMessages(BuildMessage.Kind.ERROR).map { it.messageText } - assertTrue("Message wasn't found. $errors", errors.first().contains("class xxx.JavaWithInner.TextRenderer, unresolved supertypes: TableRow")) + buildAllModules().assertSuccessful() } fun testKotlinJavaScriptProject() { diff --git a/jps-plugin/testData/general/SourcePackagePrefixKnownIssueWithInnerClasses/kotlinProject.iml b/jps-plugin/testData/general/SourcePackagePrefixWithInnerClasses/kotlinProject.iml similarity index 100% rename from jps-plugin/testData/general/SourcePackagePrefixKnownIssueWithInnerClasses/kotlinProject.iml rename to jps-plugin/testData/general/SourcePackagePrefixWithInnerClasses/kotlinProject.iml diff --git a/jps-plugin/testData/general/SourcePackagePrefixKnownIssueWithInnerClasses/kotlinProject.ipr b/jps-plugin/testData/general/SourcePackagePrefixWithInnerClasses/kotlinProject.ipr similarity index 100% rename from jps-plugin/testData/general/SourcePackagePrefixKnownIssueWithInnerClasses/kotlinProject.ipr rename to jps-plugin/testData/general/SourcePackagePrefixWithInnerClasses/kotlinProject.ipr diff --git a/jps-plugin/testData/general/SourcePackagePrefixKnownIssueWithInnerClasses/src/JavaWithInner.java b/jps-plugin/testData/general/SourcePackagePrefixWithInnerClasses/src/JavaWithInner.java similarity index 100% rename from jps-plugin/testData/general/SourcePackagePrefixKnownIssueWithInnerClasses/src/JavaWithInner.java rename to jps-plugin/testData/general/SourcePackagePrefixWithInnerClasses/src/JavaWithInner.java diff --git a/jps-plugin/testData/general/SourcePackagePrefixKnownIssueWithInnerClasses/src/test.kt b/jps-plugin/testData/general/SourcePackagePrefixWithInnerClasses/src/test.kt similarity index 100% rename from jps-plugin/testData/general/SourcePackagePrefixKnownIssueWithInnerClasses/src/test.kt rename to jps-plugin/testData/general/SourcePackagePrefixWithInnerClasses/src/test.kt