diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClassFileFactory.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClassFileFactory.java index 4f471a4b69d..6d34d92495f 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClassFileFactory.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClassFileFactory.java @@ -88,25 +88,29 @@ public class ClassFileFactory implements OutputFileCollection { for (PackageCodegen codegen : packageCodegens) { codegen.done(); } - for (MultifileClassCodegen codegen : multifileClass2codegen.values()) { + Collection multifileClassCodegens = multifileClass2codegen.values(); + for (MultifileClassCodegen codegen : multifileClassCodegens) { codegen.done(); } - // TODO module mappings for multifile classes - writeModuleMappings(packageCodegens); + writeModuleMappings(packageCodegens, multifileClassCodegens); } } - private void writeModuleMappings(Collection values) { + private void writeModuleMappings( + @NotNull Collection packageCodegens, + @NotNull Collection multifileClassCodegens + ) { final JvmPackageTable.PackageTable.Builder builder = JvmPackageTable.PackageTable.newBuilder(); String outputFilePath = getMappingFileName(state.getModuleName()); - List parts = ContainerUtil.newArrayList(); + List parts = collectGeneratedPackageParts(packageCodegens, multifileClassCodegens); + Set sourceFiles = new HashSet(); - - for (PackageCodegen codegen : values) { - parts.add(codegen.getPackageParts()); - - // TODO extract common logic + // TODO extract common logic + for (PackageCodegen codegen : packageCodegens) { + sourceFiles.addAll(toIoFilesIgnoringNonPhysical(PackagePartClassUtils.getFilesWithCallables(codegen.getFiles()))); + } + for (MultifileClassCodegen codegen : multifileClassCodegens) { sourceFiles.addAll(toIoFilesIgnoringNonPhysical(PackagePartClassUtils.getFilesWithCallables(codegen.getFiles()))); } @@ -152,6 +156,34 @@ public class ClassFileFactory implements OutputFileCollection { } } + private static List collectGeneratedPackageParts( + @NotNull Collection packageCodegens, + @NotNull Collection multifileClassCodegens + ) { + Map mergedPartsByPackageName = new LinkedHashMap(); + + for (PackageCodegen packageCodegen : packageCodegens) { + PackageParts generatedParts = packageCodegen.getPackageParts(); + PackageParts premergedParts = new PackageParts(generatedParts.getPackageFqName()); + mergedPartsByPackageName.put(generatedParts.getPackageFqName(), premergedParts); + premergedParts.getParts().addAll(generatedParts.getParts()); + } + + for (MultifileClassCodegen multifileClassCodegen : multifileClassCodegens) { + PackageParts multifileClassParts = multifileClassCodegen.getPackageParts(); + PackageParts premergedParts = mergedPartsByPackageName.get(multifileClassParts.getPackageFqName()); + if (premergedParts == null) { + premergedParts = new PackageParts(multifileClassParts.getPackageFqName()); + mergedPartsByPackageName.put(multifileClassParts.getPackageFqName(), premergedParts); + } + premergedParts.getParts().addAll(multifileClassParts.getParts()); + } + + List result = new ArrayList(); + result.addAll(mergedPartsByPackageName.values()); + return result; + } + @NotNull @Override public List asList() { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/MultifileClassCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/MultifileClassCodegen.kt index 8b4a73915fa..f02dc103b9e 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/MultifileClassCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/MultifileClassCodegen.kt @@ -27,6 +27,7 @@ import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor import org.jetbrains.kotlin.diagnostics.DiagnosticUtils import org.jetbrains.kotlin.load.java.JvmAnnotationNames +import org.jetbrains.kotlin.load.kotlin.PackageParts import org.jetbrains.kotlin.load.kotlin.incremental.IncrementalPackageFragmentProvider import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus @@ -41,7 +42,7 @@ import java.util.* public class MultifileClassCodegen( private val state: GenerationState, - private val files: Collection, + public val files: Collection, private val facadeFqName: FqName ) { private val facadeClassType = AsmUtil.asmTypeByFqNameWithoutInnerClasses(facadeFqName) @@ -50,6 +51,8 @@ public class MultifileClassCodegen( private val compiledPackageFragment = getCompiledPackageFragment(facadeFqName.parent(), state) + public val packageParts = PackageParts(facadeFqName.parent().asString()) + // TODO incremental compilation support // TODO previouslyCompiledCallables // We can do this (probably without 'compiledPackageFragment') after modifications to part codegen. @@ -159,8 +162,8 @@ public class MultifileClassCodegen( partFqNames.add(partClassInfo.fileClassFqName) -// val name = partType.internalName -// packageParts.parts.add(name.substring(name.lastIndexOf('/') + 1)) + val name = partType.internalName + packageParts.parts.add(name.substring(name.lastIndexOf('/') + 1)) val builder = state.factory.newVisitor(MultifileClassPart(file, packageFragment, facadeFqName), partType, file) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java index 2cf3e7811c6..988adab4fc0 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java @@ -110,9 +110,9 @@ public class PropertyCodegen { assert kind == OwnerKind.PACKAGE || kind == OwnerKind.IMPLEMENTATION || kind == OwnerKind.TRAIT_IMPL : "Generating property with a wrong kind (" + kind + "): " + descriptor; - Type implClassType = CodegenContextUtil.getImplementationOwnerClassType(context); - if (implClassType != null) { - v.getSerializationBindings().put(IMPL_CLASS_NAME_FOR_CALLABLE, descriptor, shortNameByAsmType(implClassType)); + String implClassName = CodegenContextUtil.getImplementationClassShortName(context); + if (implClassName != null) { + v.getSerializationBindings().put(IMPL_CLASS_NAME_FOR_CALLABLE, descriptor, implClassName); } if (CodegenContextUtil.isImplClassOwner(context)) { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/context/CodegenContextUtil.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/context/CodegenContextUtil.kt index 7efcc145da2..b4b7b3d54b3 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/context/CodegenContextUtil.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/context/CodegenContextUtil.kt @@ -23,12 +23,9 @@ import org.jetbrains.org.objectweb.asm.Type public object CodegenContextUtil { public @JvmStatic fun getImplementationOwnerClassType(owner: CodegenContext<*>): Type? = when (owner) { - is DelegatingFacadeContext -> - owner.delegateToClassType - is DelegatingToPartContext -> - owner.implementationOwnerClassType - else -> - null + is DelegatingFacadeContext -> owner.delegateToClassType + is DelegatingToPartContext -> owner.implementationOwnerClassType + else -> null } public @JvmStatic fun getImplementationClassShortName(owner: CodegenContext<*>): String? = diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/context/DelegatingFacadeContext.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/context/DelegatingFacadeContext.java index b8857e9a680..478d6db2667 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/context/DelegatingFacadeContext.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/context/DelegatingFacadeContext.java @@ -21,5 +21,5 @@ import org.jetbrains.org.objectweb.asm.Type; public interface DelegatingFacadeContext { @Nullable - public Type getDelegateToClassType(); + Type getDelegateToClassType(); } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/JetTypeMapper.java index f0b68b22d8f..4823b105716 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/JetTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/JetTypeMapper.java @@ -30,16 +30,13 @@ import org.jetbrains.kotlin.codegen.binding.PsiCodegenPredictor; import org.jetbrains.kotlin.codegen.context.CodegenContext; import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter; import org.jetbrains.kotlin.descriptors.*; +import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil; import org.jetbrains.kotlin.fileClasses.JvmFileClassesProvider; import org.jetbrains.kotlin.load.java.JvmAbi; import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor; import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor; -import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils; -import org.jetbrains.kotlin.load.kotlin.nativeDeclarations.NativeDeclarationsPackage; -import org.jetbrains.kotlin.name.ClassId; -import org.jetbrains.kotlin.name.FqName; -import org.jetbrains.kotlin.name.FqNameUnsafe; -import org.jetbrains.kotlin.name.SpecialNames; +import org.jetbrains.kotlin.load.java.lazy.descriptors.LazyJavaPackageScope; +import org.jetbrains.kotlin.name.*; import org.jetbrains.kotlin.platform.JavaToKotlinClassMap; import org.jetbrains.kotlin.psi.JetExpression; import org.jetbrains.kotlin.psi.JetFile; @@ -59,6 +56,7 @@ import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind; import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature; import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature; import org.jetbrains.kotlin.serialization.deserialization.DeserializedType; +import org.jetbrains.kotlin.resolve.scopes.JetScope; import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor; import org.jetbrains.kotlin.types.*; import org.jetbrains.kotlin.types.expressions.OperatorConventions; @@ -142,10 +140,7 @@ public class JetTypeMapper { DeclarationDescriptor container = descriptor.getContainingDeclaration(); if (container instanceof PackageFragmentDescriptor) { - boolean effectiveInsideModule = isInsideModule && !NativeDeclarationsPackage.hasNativeAnnotation(descriptor); - return Type.getObjectType(internalNameForPackage( - (CallableMemberDescriptor) descriptor - )); + return Type.getObjectType(internalNameForPackage((CallableMemberDescriptor) descriptor)); } else if (container instanceof ClassDescriptor) { return mapClass((ClassDescriptor) container); @@ -174,9 +169,19 @@ public class JetTypeMapper { CallableMemberDescriptor directMember = getDirectMember(descriptor); if (directMember instanceof DeserializedCallableMemberDescriptor) { - // TODO private vs public - FqName packagePartFqName = PackagePartClassUtils.getPackagePartFqName((DeserializedCallableMemberDescriptor) directMember); - return internalNameByFqNameWithoutInnerClasses(packagePartFqName); + Name implClassName = JvmFileClassUtil.getImplClassName((DeserializedCallableMemberDescriptor) directMember); + DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration(); + if (containingDeclaration instanceof PackageFragmentDescriptor) { + PackageFragmentDescriptor packageFragmentDescriptor = (PackageFragmentDescriptor) containingDeclaration; + JetScope scope = packageFragmentDescriptor.getMemberScope(); + if (scope instanceof LazyJavaPackageScope) { + String facadeShortName = ((LazyJavaPackageScope) scope).getFacadeSimpleNameForPartSimpleName(implClassName.asString()); + if (facadeShortName != null) { + FqName facadeFqName = packageFragmentDescriptor.getFqName().child(Name.identifier(facadeShortName)); + return internalNameByFqNameWithoutInnerClasses(facadeFqName); + } + } + } } throw new RuntimeException("Unreachable state"); diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/fileClasses/JvmFileClassUtil.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/fileClasses/JvmFileClassUtil.kt index 587ecab9815..778b734b056 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/fileClasses/JvmFileClassUtil.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/fileClasses/JvmFileClassUtil.kt @@ -16,12 +16,14 @@ package org.jetbrains.kotlin.fileClasses -import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor +import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* -import org.jetbrains.kotlin.resolve.constants.StringValue +import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor +import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf + public object JvmFileClassUtil { public val JVM_NAME: FqName = FqName("kotlin.jvm.JvmName") @@ -49,6 +51,15 @@ public object JvmFileClassUtil { public @JvmStatic fun getFacadeFqName(file: JetFile, jvmFileClassAnnotations: ParsedJmvFileClassAnnotations): FqName = file.packageFqName.child(Name.identifier(jvmFileClassAnnotations.name)) + public @JvmStatic fun getPartFqNameForDeserializedCallable(callable: DeserializedCallableMemberDescriptor): FqName { + val implClassName = getImplClassName(callable) + val packageFqName = (callable.containingDeclaration as PackageFragmentDescriptor).fqName + return packageFqName.child(implClassName) + } + + public @JvmStatic fun getImplClassName(callable: DeserializedCallableMemberDescriptor): Name = + callable.nameResolver.getName(callable.proto.getExtension(JvmProtoBuf.implClassName)) + public @JvmStatic fun getHiddenPartFqName(file: JetFile, jvmFileClassAnnotations: ParsedJmvFileClassAnnotations): FqName = file.packageFqName.child(Name.identifier(manglePartName(jvmFileClassAnnotations.name, file.name))) diff --git a/compiler/testData/codegen/boxInline/multifileClasses/inlineFromOtherPackage.1.kt b/compiler/testData/codegen/boxInline/multifileClasses/inlineFromOtherPackage.1.kt new file mode 100644 index 00000000000..8716beb0dc9 --- /dev/null +++ b/compiler/testData/codegen/boxInline/multifileClasses/inlineFromOtherPackage.1.kt @@ -0,0 +1,3 @@ +import a.foo + +fun box(): String = foo { "OK" } \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/multifileClasses/inlineFromOtherPackage.2.kt b/compiler/testData/codegen/boxInline/multifileClasses/inlineFromOtherPackage.2.kt new file mode 100644 index 00000000000..074c3891b42 --- /dev/null +++ b/compiler/testData/codegen/boxInline/multifileClasses/inlineFromOtherPackage.2.kt @@ -0,0 +1,4 @@ +@file:[JvmName("MultifileClass") JvmMultifileClass] +package a + +inline fun foo(body: () -> String): String = body() \ No newline at end of file diff --git a/compiler/testData/codegen/boxMultiFile/callMultifileClassMemberFromOtherPackage/box.kt b/compiler/testData/codegen/boxMultiFile/callMultifileClassMemberFromOtherPackage/box.kt new file mode 100644 index 00000000000..fdda71fb581 --- /dev/null +++ b/compiler/testData/codegen/boxMultiFile/callMultifileClassMemberFromOtherPackage/box.kt @@ -0,0 +1,5 @@ +package test + +import b.bar + +fun box(): String = bar() \ No newline at end of file diff --git a/compiler/testData/codegen/boxMultiFile/callMultifileClassMemberFromOtherPackage/caller.kt b/compiler/testData/codegen/boxMultiFile/callMultifileClassMemberFromOtherPackage/caller.kt new file mode 100644 index 00000000000..b8b58154e62 --- /dev/null +++ b/compiler/testData/codegen/boxMultiFile/callMultifileClassMemberFromOtherPackage/caller.kt @@ -0,0 +1,5 @@ +package b + +import a.foo + +fun bar(): String = foo() \ No newline at end of file diff --git a/compiler/testData/codegen/boxMultiFile/callMultifileClassMemberFromOtherPackage/multifileClass.kt b/compiler/testData/codegen/boxMultiFile/callMultifileClassMemberFromOtherPackage/multifileClass.kt new file mode 100644 index 00000000000..4d1b4f46224 --- /dev/null +++ b/compiler/testData/codegen/boxMultiFile/callMultifileClassMemberFromOtherPackage/multifileClass.kt @@ -0,0 +1,4 @@ +@file:[JvmName("MultifileClass") JvmMultifileClass] +package a + +fun foo(): String = "OK" \ No newline at end of file diff --git a/compiler/testData/codegen/boxMultifileClasses/calls/callFromOtherPackage.1.kt b/compiler/testData/codegen/boxMultifileClasses/calls/callFromOtherPackage.1.kt new file mode 100644 index 00000000000..214494e4f16 --- /dev/null +++ b/compiler/testData/codegen/boxMultifileClasses/calls/callFromOtherPackage.1.kt @@ -0,0 +1,3 @@ +import a.foo + +fun box(): String = foo() \ No newline at end of file diff --git a/compiler/testData/codegen/boxMultifileClasses/calls/callFromOtherPackage.2.kt b/compiler/testData/codegen/boxMultifileClasses/calls/callFromOtherPackage.2.kt new file mode 100644 index 00000000000..4d1b4f46224 --- /dev/null +++ b/compiler/testData/codegen/boxMultifileClasses/calls/callFromOtherPackage.2.kt @@ -0,0 +1,4 @@ +@file:[JvmName("MultifileClass") JvmMultifileClass] +package a + +fun foo(): String = "OK" \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/InlineTestUtil.kt b/compiler/tests/org/jetbrains/kotlin/codegen/InlineTestUtil.kt index 3e907bb36bd..0007b4289c6 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/InlineTestUtil.kt +++ b/compiler/tests/org/jetbrains/kotlin/codegen/InlineTestUtil.kt @@ -89,11 +89,22 @@ public object InlineTestUtil { val notInlined = ArrayList() files.forEach { file -> - val cr = ClassReader(file.asByteArray()) cr.accept(object : ClassVisitorWithName() { + private var skipMethodsOfThisClass = false + + override fun visitAnnotation(desc: String, visible: Boolean): AnnotationVisitor? { + if (desc.endsWith("KotlinPackage;") || desc.endsWith("KotlinMultifileClass;")) { + skipMethodsOfThisClass = true + } + return null + } override fun visitMethod(access: Int, name: String, desc: String, signature: String, exceptions: Array): MethodVisitor? { + if (skipMethodsOfThisClass) { + return null + } + val classFqName = JvmClassName.byInternalName(className).getFqNameForClassNameWithoutDollars() if (PackageClassUtils.isPackageClassFqName(classFqName)) { return null diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxInlineCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxInlineCodegenTestGenerated.java index 3a4da929d4f..134d2c5c45f 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxInlineCodegenTestGenerated.java @@ -428,6 +428,21 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo } } + @TestMetadata("compiler/testData/codegen/boxInline/multifileClasses") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class MultifileClasses extends AbstractBlackBoxInlineCodegenTest { + public void testAllFilesPresentInMultifileClasses() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/multifileClasses"), Pattern.compile("^(.+)\\.1.kt$"), true); + } + + @TestMetadata("inlineFromOtherPackage.1.kt") + public void testInlineFromOtherPackage() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/multifileClasses/inlineFromOtherPackage.1.kt"); + doTestMultiFileWithInlineCheck(fileName); + } + } + @TestMetadata("compiler/testData/codegen/boxInline/noInline") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxMultiFileCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxMultiFileCodegenTestGenerated.java index dc642814a52..3244e8a9c00 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxMultiFileCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxMultiFileCodegenTestGenerated.java @@ -47,6 +47,12 @@ public class BlackBoxMultiFileCodegenTestGenerated extends AbstractBlackBoxCodeg JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxMultiFile"), Pattern.compile("^([^\\.]+)$"), false); } + @TestMetadata("callMultifileClassMemberFromOtherPackage") + public void testCallMultifileClassMemberFromOtherPackage() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxMultiFile/callMultifileClassMemberFromOtherPackage/"); + doTestMultiFile(fileName); + } + @TestMetadata("internalVisibility") public void testInternalVisibility() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxMultiFile/internalVisibility/"); diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/AbstractCompileKotlinAgainstMultifileKotlinTest.kt b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/AbstractCompileKotlinAgainstMultifileKotlinTest.kt new file mode 100644 index 00000000000..79bd9b6b273 --- /dev/null +++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/AbstractCompileKotlinAgainstMultifileKotlinTest.kt @@ -0,0 +1,58 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.jvm.compiler + +import org.jetbrains.kotlin.codegen.ClassFileFactory +import org.jetbrains.kotlin.codegen.InlineTestUtil +import org.jetbrains.kotlin.codegen.filterClassFiles +import java.io.File +import java.util.Collections + +public abstract class AbstractCompileKotlinAgainstMultifileKotlinTest : AbstractCompileKotlinAgainstKotlinTest(), AbstractSMAPBaseTest { + + public fun doBoxTest(firstFileName: String) { + val inputFiles = listOf(firstFileName, firstFileName.substringBeforeLast("1.kt") + "2.kt") + + val (factory1, factory2) = doBoxTest(inputFiles) + } + + private fun doBoxTest(files: List): Pair { + Collections.sort(files) + + var factory1: ClassFileFactory? = null + var factory2: ClassFileFactory? = null + try { + factory1 = compileA(File(files[1])) + factory2 = compileB(File(files[0])) + invokeBox() + } + catch (e: Throwable) { + var result = "" + if (factory1 != null) { + result += "FIRST: \n\n" + factory1.createText() + } + if (factory2 != null) { + result += "\n\nSECOND: \n\n" + factory2.createText() + } + System.out.println(result) + throw e + } + + return Pair(factory1!!, factory2!!) + } + +} diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java index 4c5f8f902a8..0e45e8887fc 100644 --- a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java @@ -428,6 +428,21 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi } } + @TestMetadata("compiler/testData/codegen/boxInline/multifileClasses") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class MultifileClasses extends AbstractCompileKotlinAgainstInlineKotlinTest { + public void testAllFilesPresentInMultifileClasses() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/multifileClasses"), Pattern.compile("^(.+)\\.1.kt$"), true); + } + + @TestMetadata("inlineFromOtherPackage.1.kt") + public void testInlineFromOtherPackage() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/multifileClasses/inlineFromOtherPackage.1.kt"); + doBoxTestWithInlineCheck(fileName); + } + } + @TestMetadata("compiler/testData/codegen/boxInline/noInline") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstMultifileKotlinTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstMultifileKotlinTestGenerated.java new file mode 100644 index 00000000000..3ebccef8abc --- /dev/null +++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstMultifileKotlinTestGenerated.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.jvm.compiler; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.JUnit3RunnerWithInners; +import org.jetbrains.kotlin.test.JetTestUtils; +import org.jetbrains.kotlin.test.TestMetadata; +import org.junit.runner.RunWith; + +import java.io.File; +import java.util.regex.Pattern; + +/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("compiler/testData/codegen/boxMultifileClasses") +@TestDataPath("$PROJECT_ROOT") +@RunWith(JUnit3RunnerWithInners.class) +public class CompileKotlinAgainstMultifileKotlinTestGenerated extends AbstractCompileKotlinAgainstMultifileKotlinTest { + public void testAllFilesPresentInBoxMultifileClasses() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxMultifileClasses"), Pattern.compile("^(.+)\\.1.kt$"), true); + } + + @TestMetadata("compiler/testData/codegen/boxMultifileClasses/calls") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Calls extends AbstractCompileKotlinAgainstMultifileKotlinTest { + public void testAllFilesPresentInCalls() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxMultifileClasses/calls"), Pattern.compile("^(.+)\\.1.kt$"), true); + } + + @TestMetadata("callFromOtherPackage.1.kt") + public void testCallFromOtherPackage() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxMultifileClasses/calls/callFromOtherPackage.1.kt"); + doBoxTest(fileName); + } + } +} diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaPackageScope.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaPackageScope.kt index e148ac91a10..6c478a775d6 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaPackageScope.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaPackageScope.kt @@ -30,6 +30,7 @@ import org.jetbrains.kotlin.load.java.structure.JavaClass import org.jetbrains.kotlin.load.java.structure.JavaPackage import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass import org.jetbrains.kotlin.load.kotlin.PackageClassUtils +import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.SpecialNames @@ -58,6 +59,22 @@ public class LazyJavaPackageScope( }.filterNotNull() } + private val partToFacade = c.storageManager.createLazyValue { + val result = hashMapOf() + for (kotlinClass in kotlinBinaryClasses()) { + val header = kotlinClass.classHeader + if (header.kind == KotlinClassHeader.Kind.MULTIFILE_CLASS_PART) { + val partName = kotlinClass.classId.shortClassName.asString() + val facadeName = header.multifileClassName ?: "" + result[partName] = facadeName + } + } + result + } + + public fun getFacadeSimpleNameForPartSimpleName(partName: String): String? = + partToFacade()[partName] + private val deserializedPackageScope = c.storageManager.createLazyValue { if (kotlinBinaryClasses().isEmpty()) JetScope.Empty diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/DeserializedDescriptorResolver.java b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/DeserializedDescriptorResolver.java index af1a84b4fec..38ad66e2e5b 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/DeserializedDescriptorResolver.java +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/DeserializedDescriptorResolver.java @@ -69,7 +69,7 @@ public final class DeserializedDescriptorResolver { @Nullable public JetScope createKotlinPackagePartScope(@NotNull PackageFragmentDescriptor descriptor, @NotNull KotlinJvmBinaryClass kotlinClass) { - String[] data = readData(kotlinClass, KotlinClassHeader.Kind.FILE_FACADE); + String[] data = readData(kotlinClass, null); if (data != null) { //all classes are included in java scope PackageData packageData = JvmProtoBufUtil.readPackageDataFrom(data); @@ -102,12 +102,12 @@ public final class DeserializedDescriptorResolver { } @Nullable - public String[] readData(@NotNull KotlinJvmBinaryClass kotlinClass, @NotNull KotlinClassHeader.Kind expectedKind) { + public String[] readData(@NotNull KotlinJvmBinaryClass kotlinClass, @Nullable KotlinClassHeader.Kind expectedKind) { KotlinClassHeader header = kotlinClass.getClassHeader(); if (!header.getIsCompatibleAbiVersion()) { errorReporter.reportIncompatibleAbiVersion(kotlinClass.getClassId(), kotlinClass.getLocation(), header.getVersion()); } - else if (header.getKind() == expectedKind) { + else if (expectedKind == null || header.getKind() == expectedKind) { return header.getAnnotationData(); } diff --git a/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt b/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt index b24d00af56a..0c78e20a243 100644 --- a/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt +++ b/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt @@ -183,6 +183,10 @@ fun main(args: Array) { model("codegen/boxInline", extension = "1.kt", testMethod = "doBoxTestWithInlineCheck") } + testClass(javaClass(), "CompileKotlinAgainstMultifileKotlinTestGenerated") { + model("codegen/boxMultifileClasses", extension = "1.kt", testMethod = "doBoxTest") + } + testClass(javaClass(), "BlackBoxMultiFileCodegenTestGenerated") { model("codegen/boxMultiFile", extension = null, recursive = false, testMethod = "doTestMultiFile") }