diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/BinaryJavaClass.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/BinaryJavaClass.kt index 8889cf142d0..a747aab8afc 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/BinaryJavaClass.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/BinaryJavaClass.kt @@ -33,7 +33,7 @@ import java.text.StringCharacterIterator class BinaryJavaClass( override val virtualFile: VirtualFile, override val fqName: FqName, - private val context: ClassifierResolutionContext, + internal val context: ClassifierResolutionContext, private val signatureParser: BinaryClassSignatureParser, override var access: Int = 0, override val outerClass: JavaClass?, diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/ClassifierResolutionContext.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/ClassifierResolutionContext.kt index 789b272f38f..67f3593021c 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/ClassifierResolutionContext.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/ClassifierResolutionContext.kt @@ -25,6 +25,7 @@ import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.util.javaslang.ImmutableHashMap import org.jetbrains.kotlin.util.javaslang.ImmutableMap import org.jetbrains.kotlin.util.javaslang.getOrNull +import org.jetbrains.kotlin.utils.SmartList typealias ClassIdToJavaClass = (ClassId) -> JavaClass? @@ -73,5 +74,49 @@ class ClassifierResolutionContext private constructor( return ClassId.topLevel(FqName(internalName.replace('/', '.'))) } - internal fun resolveByInternalName(c: String): Result = resolveClass(mapInternalNameToClassId(c)) + // See com.intellij.psi.impl.compiled.StubBuildingVisitor.GUESSING_MAPPER + private fun convertNestedClassInternalNameWithSimpleHeuristic(internalName: String): ClassId? { + val splitPoints = SmartList() + for (p in 0 until internalName.length) { + val c = internalName[p] + if (c == '$' && p > 0 && internalName[p - 1] != '/' && p < internalName.length - 1 && internalName[p + 1] != '$') { + splitPoints.add(p) + } + } + + if (splitPoints.isEmpty()) return null + + val substrings = (listOf(-1) + splitPoints).zip(splitPoints + internalName.length).map { (from, to) -> + internalName.substring(from + 1, to) + } + + val outerFqName = FqName(substrings[0].replace('/', '.')) + val packageFqName = outerFqName.parent() + val relativeName = FqName(outerFqName.shortName().asString() + "." + substrings.subList(1, substrings.size).joinToString(".")) + + return ClassId(packageFqName, relativeName, false) + } + + internal fun resolveByInternalName(internalName: String): Result { + val result = resolveClass(mapInternalNameToClassId(internalName)) + if (result.classifier == null && '$' in internalName) { + // Class files generated by some (non-javac) compilers lack the InnerClasses attribute which would make it possible to + // unambiguously determine how to parse a particular internal name found in the class file. For example, see + // https://issues.apache.org/jira/browse/GROOVY-8863. In this case, we're trying to treat all dollar characters in the class + // name as nested class separators, lookup the class with that ClassId, and see if its InnerClasses attribute confirms our + // suspicion that this class was in fact nested. + val heuristicName = convertNestedClassInternalNameWithSimpleHeuristic(internalName) + if (heuristicName != null) { + val heuristicResult = resolveClass(heuristicName) + if (heuristicResult.classifier is BinaryJavaClass) { + val realName = heuristicResult.classifier.context.mapInternalNameToClassId(internalName) + if (heuristicName == realName) { + return heuristicResult + } + } + } + } + + return result + } } diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/SimpleKotlinGradleIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/SimpleKotlinGradleIT.kt index d8d7e16c863..7394597e30c 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/SimpleKotlinGradleIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/SimpleKotlinGradleIT.kt @@ -109,8 +109,8 @@ class SimpleKotlinGradleIT : BaseGradleIT() { } @Test - fun testGroovyTraitsWithFields() { - Project("groovyTraitsWithFields").build("build") { + fun testGroovyInterop() { + Project("groovyInterop").build("build") { assertSuccessful() } } diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/groovyTraitsWithFields/build.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/groovyInterop/build.gradle similarity index 100% rename from libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/groovyTraitsWithFields/build.gradle rename to libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/groovyInterop/build.gradle diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/groovyTraitsWithFields/lib/build.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/groovyInterop/lib/build.gradle similarity index 100% rename from libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/groovyTraitsWithFields/lib/build.gradle rename to libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/groovyInterop/lib/build.gradle diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/groovyInterop/lib/src/main/groovy/ClassWithReferenceToInner.groovy b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/groovyInterop/lib/src/main/groovy/ClassWithReferenceToInner.groovy new file mode 100644 index 00000000000..08b7fe9bf5d --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/groovyInterop/lib/src/main/groovy/ClassWithReferenceToInner.groovy @@ -0,0 +1,9 @@ +public class ClassWithReferenceToInner { + public void f1(Thread.State state) {} + + public void f2(Outer.Nested nested) {} +} + +class Outer { + class Nested {} +} diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/groovyTraitsWithFields/lib/src/main/groovy/MyTrait.groovy b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/groovyInterop/lib/src/main/groovy/MyTrait.groovy similarity index 100% rename from libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/groovyTraitsWithFields/lib/src/main/groovy/MyTrait.groovy rename to libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/groovyInterop/lib/src/main/groovy/MyTrait.groovy diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/groovyTraitsWithFields/lib/src/main/groovy/MyTraitAccessor.groovy b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/groovyInterop/lib/src/main/groovy/MyTraitAccessor.groovy similarity index 100% rename from libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/groovyTraitsWithFields/lib/src/main/groovy/MyTraitAccessor.groovy rename to libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/groovyInterop/lib/src/main/groovy/MyTraitAccessor.groovy diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/groovyTraitsWithFields/settings.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/groovyInterop/settings.gradle similarity index 100% rename from libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/groovyTraitsWithFields/settings.gradle rename to libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/groovyInterop/settings.gradle diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/groovyInterop/src/main/kotlin/MyKotlinClass.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/groovyInterop/src/main/kotlin/MyKotlinClass.kt new file mode 100644 index 00000000000..1ddd25dfba0 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/groovyInterop/src/main/kotlin/MyKotlinClass.kt @@ -0,0 +1,6 @@ +fun main(args: Array) { + System.out.println(MyTraitAccessor().myField) + + System.out.println(ClassWithReferenceToInner().f1(null)) + System.out.println(ClassWithReferenceToInner().f2(null)) +} diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/groovyTraitsWithFields/src/main/kotlin/MyKotlinClass.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/groovyTraitsWithFields/src/main/kotlin/MyKotlinClass.kt deleted file mode 100644 index 0f51db3c229..00000000000 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/groovyTraitsWithFields/src/main/kotlin/MyKotlinClass.kt +++ /dev/null @@ -1,3 +0,0 @@ -fun main(args: Array) { - System.out.println(MyTraitAccessor().myField) -}