diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/kotlin/VirtualFileKotlinClass.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/kotlin/VirtualFileKotlinClass.java index 4ce65d70bb4..14bd6bd6e33 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/kotlin/VirtualFileKotlinClass.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/kotlin/VirtualFileKotlinClass.java @@ -16,6 +16,7 @@ package org.jetbrains.jet.lang.resolve.kotlin; +import com.intellij.ide.highlighter.JavaClassFileType; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Ref; @@ -80,6 +81,7 @@ public class VirtualFileKotlinClass implements KotlinJvmBinaryClass { @Nullable /* package */ static VirtualFileKotlinClass create(@NotNull VirtualFile file) { + assert file.getFileType() == JavaClassFileType.INSTANCE : "Trying to read binary data from a non-class file " + file; try { byte[] fileContents = file.contentsToByteArray(); Pair nameAndHeader = readClassNameAndHeader(fileContents); diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/kotlin/VirtualFileKotlinClassFinder.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/kotlin/VirtualFileKotlinClassFinder.java index af0b0b33336..bf999ba3f33 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/kotlin/VirtualFileKotlinClassFinder.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/kotlin/VirtualFileKotlinClassFinder.java @@ -16,9 +16,12 @@ package org.jetbrains.jet.lang.resolve.kotlin; +import com.intellij.ide.highlighter.JavaClassFileType; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.resolve.java.structure.JavaClass; +import org.jetbrains.jet.lang.resolve.java.structure.impl.JavaClassImpl; import org.jetbrains.jet.lang.resolve.name.FqName; public abstract class VirtualFileKotlinClassFinder implements VirtualFileFinder { @@ -28,4 +31,27 @@ public abstract class VirtualFileKotlinClassFinder implements VirtualFileFinder VirtualFile file = findVirtualFileWithHeader(fqName); return file == null ? null : KotlinBinaryClassCache.getKotlinBinaryClass(file); } + + @Override + @Nullable + public KotlinJvmBinaryClass findKotlinClass(@NotNull JavaClass javaClass) { + VirtualFile file = ((JavaClassImpl) javaClass).getPsi().getContainingFile().getVirtualFile(); + if (javaClass.getOuterClass() != null) { + // For nested classes we get a file of the containing class, to get the actual class file for A.B.C, + // we take the file for A, take its parent directory, then in this directory we look for A$B$C.class + file = file.getParent().findChild(classFileName(javaClass) + ".class"); + assert file != null : "Virtual file not found for " + javaClass; + } + + if (file.getFileType() != JavaClassFileType.INSTANCE) return null; + + return KotlinBinaryClassCache.getKotlinBinaryClass(file); + } + + @NotNull + private static String classFileName(@NotNull JavaClass jClass) { + JavaClass outerClass = jClass.getOuterClass(); + if (outerClass == null) return jClass.getName().asString(); + return classFileName(outerClass) + "$" + jClass.getName().asString(); + } } diff --git a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/lazy/LazyJavaPackageFragmentProvider.kt b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/lazy/LazyJavaPackageFragmentProvider.kt index 5e725820870..9db7c8c16d0 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/lazy/LazyJavaPackageFragmentProvider.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/lazy/LazyJavaPackageFragmentProvider.kt @@ -27,9 +27,7 @@ import org.jetbrains.jet.lang.resolve.java.resolver.DescriptorResolverUtils import org.jetbrains.jet.lang.resolve.java.resolver.JavaPackageFragmentProvider import org.jetbrains.jet.lang.resolve.java.lazy.descriptors.LazyJavaPackageFragment import org.jetbrains.jet.lang.resolve.kotlin.KotlinJvmBinaryClass -import org.jetbrains.jet.storage.MemoizedFunctionToNotNull import org.jetbrains.jet.lang.resolve.java.lazy.descriptors.LazyJavaClassDescriptor -import org.jetbrains.kotlin.util.sure public class LazyJavaPackageFragmentProvider( outerContext: GlobalJavaResolverContext, @@ -124,7 +122,7 @@ public class LazyJavaPackageFragmentProvider( } val outerClass = javaClass.getOuterClass() if (outerClass == null) { - return topLevelClasses(javaClass) + return c.lookupBinaryClass(javaClass) ?: topLevelClasses(javaClass) } val outerClassScope = resolveClass(outerClass)?.getUnsubstitutedInnerClassesScope() val nestedClass = outerClassScope?.getClassifier(javaClass.getName()) as? ClassDescriptor diff --git a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/lazy/resolvers.kt b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/lazy/resolvers.kt index 29e98e7b423..36ba831bc82 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/lazy/resolvers.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/lazy/resolvers.kt @@ -25,6 +25,7 @@ import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor import org.jetbrains.jet.lang.resolve.name.FqName import org.jetbrains.jet.lang.resolve.kotlin.header.KotlinClassHeader import org.jetbrains.jet.lang.resolve.java.resolver.DescriptorResolverUtils +import org.jetbrains.jet.lang.resolve.kotlin.KotlinJvmBinaryClass trait LazyJavaClassResolver { fun resolveClass(javaClass: JavaClass): ClassDescriptor? @@ -67,6 +68,11 @@ fun LazyJavaResolverContext.findJavaClass(fqName: FqName): JavaClass? = findClas data class JavaClassLookupResult(val jClass: JavaClass? = null, val kClass: ClassDescriptor? = null) +fun LazyJavaResolverContext.lookupBinaryClass(javaClass: JavaClass): ClassDescriptor? { + val kotlinJvmBinaryClass = kotlinClassFinder.findKotlinClass(javaClass) + return resolveBinaryClass(kotlinJvmBinaryClass)?.kClass +} + fun LazyJavaResolverContext.findClassInJava(fqName: FqName): JavaClassLookupResult { // TODO: this should be governed by module separation logic // Do not look for JavaClasses for Kotlin binaries & built-ins @@ -75,22 +81,8 @@ fun LazyJavaResolverContext.findClassInJava(fqName: FqName): JavaClassLookupResu } val kotlinClass = kotlinClassFinder.findKotlinClass(fqName) - if (kotlinClass != null) { - val header = kotlinClass.getClassHeader() - if (header.kind == KotlinClassHeader.Kind.CLASS) { - val descriptor = packageFragmentProvider.resolveKotlinBinaryClass(kotlinClass) - if (descriptor != null) { - return JavaClassLookupResult(kClass = descriptor) - } - } - else if (header.kind == KotlinClassHeader.Kind.INCOMPATIBLE_ABI_VERSION) { - errorReporter.reportIncompatibleAbiVersion(kotlinClass, header.version) - } - else { - // This is a package or trait-impl or something like that - return JavaClassLookupResult() - } - } + val binaryClassResult = resolveBinaryClass(kotlinClass) + if (binaryClassResult != null) return binaryClassResult val javaClass = finder.findClass(fqName) if (javaClass == null) return JavaClassLookupResult() @@ -100,4 +92,25 @@ fun LazyJavaResolverContext.findClassInJava(fqName: FqName): JavaClassLookupResu return JavaClassLookupResult(javaClass) -} \ No newline at end of file +} + +private fun LazyJavaResolverContext.resolveBinaryClass(kotlinClass: KotlinJvmBinaryClass?): JavaClassLookupResult? { + if (kotlinClass == null) return null + + val header = kotlinClass.getClassHeader() + if (header.kind == KotlinClassHeader.Kind.CLASS) { + val descriptor = packageFragmentProvider.resolveKotlinBinaryClass(kotlinClass) + if (descriptor != null) { + return JavaClassLookupResult(kClass = descriptor) + } + } + else if (header.kind == KotlinClassHeader.Kind.INCOMPATIBLE_ABI_VERSION) { + errorReporter.reportIncompatibleAbiVersion(kotlinClass, header.version) + } + else { + // This is a package or trait-impl or something like that + return JavaClassLookupResult() + } + + return null +} diff --git a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/KotlinClassFinder.java b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/KotlinClassFinder.java index 6331b5b7120..48e0a34cdb0 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/KotlinClassFinder.java +++ b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/KotlinClassFinder.java @@ -18,10 +18,14 @@ package org.jetbrains.jet.lang.resolve.kotlin; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.resolve.java.structure.JavaClass; import org.jetbrains.jet.lang.resolve.name.FqName; public interface KotlinClassFinder { @Nullable KotlinJvmBinaryClass findKotlinClass(@NotNull FqName fqName); + + @Nullable + KotlinJvmBinaryClass findKotlinClass(@NotNull JavaClass javaClass); } diff --git a/idea/src/org/jetbrains/jet/plugin/libraries/DeserializerForDecompiler.kt b/idea/src/org/jetbrains/jet/plugin/libraries/DeserializerForDecompiler.kt index c0040d62304..13b676ff6c6 100644 --- a/idea/src/org/jetbrains/jet/plugin/libraries/DeserializerForDecompiler.kt +++ b/idea/src/org/jetbrains/jet/plugin/libraries/DeserializerForDecompiler.kt @@ -44,6 +44,7 @@ import org.jetbrains.jet.lang.resolve.kotlin.DescriptorDeserializers import org.jetbrains.jet.lang.resolve.kotlin.DescriptorDeserializersStorage import org.jetbrains.jet.lang.resolve.kotlin.ConstantDescriptorDeserializer import org.jetbrains.jet.descriptors.serialization.descriptors.MemberFilter +import org.jetbrains.jet.lang.resolve.java.structure.JavaClass public fun DeserializerForDecompiler(classFile: VirtualFile): DeserializerForDecompiler { val kotlinClass = KotlinBinaryClassCache.getKotlinBinaryClass(classFile) @@ -79,6 +80,7 @@ public class DeserializerForDecompiler(val packageDirectory: VirtualFile, val di private val localClassFinder = object: KotlinClassFinder { override fun findKotlinClass(fqName: FqName) = findKotlinClass(fqName.toClassId()) + override fun findKotlinClass(javaClass: JavaClass) = findKotlinClass(javaClass.getFqName()!!) fun findKotlinClass(classId: ClassId): KotlinJvmBinaryClass? { if (classId.getPackageFqName() != directoryPackageFqName) { diff --git a/jps-plugin/test/org/jetbrains/jet/jps/build/SimpleKotlinJpsBuildTest.kt b/jps-plugin/test/org/jetbrains/jet/jps/build/SimpleKotlinJpsBuildTest.kt index 651fcebdffc..1adc05168c3 100644 --- a/jps-plugin/test/org/jetbrains/jet/jps/build/SimpleKotlinJpsBuildTest.kt +++ b/jps-plugin/test/org/jetbrains/jet/jps/build/SimpleKotlinJpsBuildTest.kt @@ -71,4 +71,39 @@ public class SimpleKotlinJpsBuildTest : JpsBuildTestCase() { rebuildAll() } + + public fun testLoadingKotlinFromDifferentModules() { + val aFile = createFile("m1/K.kt", + """ + package m1; + + trait K { + } + """) + createFile("m1/J.java", + """ + package m1; + + public interface J { + K bar(); + } + """) + val a = addModule("m1", PathUtil.getParentPath(aFile)) + + val bFile = createFile("m2/m2.kt", + """ + import m1.J; + import m1.K; + + trait M2: J { + override fun bar(): K + } + """) + val b = addModule("b", PathUtil.getParentPath(bFile)) + JpsJavaExtensionService.getInstance().getOrCreateDependencyExtension( + b.getDependenciesList().addModuleDependency(a) + ).setExported(false) + + rebuildAll() + } }