diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt index a916e7df9d5..f73008b06f8 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ClassCodegen.kt @@ -214,6 +214,10 @@ open class ClassCodegen protected constructor( writeKotlinMetadata(visitor, state, KotlinClassHeader.Kind.CLASS, 0) { AsmUtil.writeAnnotationData(it, serializer, classProto) } + + assert(irClass !in context.classNameOverride) { + "JvmPackageName is not supported for classes: ${irClass.render()}" + } } is MetadataSource.File -> { val packageFqName = irClass.getPackageFragment()!!.fqName @@ -230,7 +234,9 @@ open class ClassCodegen protected constructor( av.visit(JvmAnnotationNames.METADATA_MULTIFILE_CLASS_NAME_FIELD_NAME, facadeClassName.internalName) } - // TODO: JvmPackageName + if (irClass in context.classNameOverride) { + av.visit(JvmAnnotationNames.METADATA_PACKAGE_NAME_FIELD_NAME, irClass.fqNameWhenAvailable!!.parent().asString()) + } } } else -> { diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FileClassLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FileClassLowering.kt index 4b9c556cdc9..44863c3175f 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FileClassLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FileClassLowering.kt @@ -29,6 +29,7 @@ import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.impl.IrClassImpl import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl +import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable import org.jetbrains.kotlin.psi2ir.PsiSourceManager import org.jetbrains.kotlin.resolve.jvm.JvmClassName import org.jetbrains.kotlin.resolve.source.KotlinSourceElement @@ -112,7 +113,10 @@ private class FileClassLowering(val context: JvmBackendContext) : FileLoweringPa if (fileClassInfo.withJvmMultifileClass) AsmUtil.asmTypeByFqNameWithoutInnerClasses(fileClassInfo.facadeClassFqName) else null context.state.factory.packagePartRegistry.addPart(irFile.fqName, partClassType.internalName, facadeClassType?.internalName) - context.classNameOverride[this] = JvmClassName.byInternalName(partClassType.internalName) + + if (fileClassInfo.fileClassFqName != fqNameWhenAvailable) { + context.classNameOverride[this] = JvmClassName.byInternalName(partClassType.internalName) + } if (facadeClassType != null) { val jvmClassName = JvmClassName.byInternalName(facadeClassType.internalName) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/GenerateMultifileFacades.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/GenerateMultifileFacades.kt index 7e91fda560d..14a6b6ad9e3 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/GenerateMultifileFacades.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/GenerateMultifileFacades.kt @@ -39,6 +39,7 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols +import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable import org.jetbrains.kotlin.ir.util.transformFlat import org.jetbrains.kotlin.ir.visitors.IrElementTransformer import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid @@ -100,14 +101,27 @@ private fun generateMultifileFacades( functionDelegates: MutableMap ): List = context.multifileFacadesToAdd.map { (jvmClassName, partClasses) -> + val kotlinPackageFqName = partClasses.first().fqNameWhenAvailable!!.parent() + if (!partClasses.all { it.fqNameWhenAvailable!!.parent() == kotlinPackageFqName }) { + throw UnsupportedOperationException( + "Multi-file parts of a facade with JvmPackageName should all lie in the same Kotlin package:\n " + + partClasses.joinToString("\n ") { klass -> + "Class ${klass.fqNameWhenAvailable}, JVM name ${context.classNameOverride[klass]}" + } + ) + } + val fileEntry = MultifileFacadeFileEntry(jvmClassName, partClasses.map(IrClass::fileParent)) - val file = IrFileImpl(fileEntry, EmptyPackageFragmentDescriptor(module, jvmClassName.packageFqName)) + val file = IrFileImpl(fileEntry, EmptyPackageFragmentDescriptor(module, kotlinPackageFqName)) val facadeClass = buildClass { name = jvmClassName.fqNameForTopLevelClassMaybeWithDollars.shortName() }.apply { parent = file createImplicitParameterDeclarationWithWrappedDescriptor() + if (jvmClassName.packageFqName != kotlinPackageFqName) { + context.classNameOverride[this] = jvmClassName + } } file.declarations.add(facadeClass) diff --git a/compiler/testData/codegen/box/jvmPackageName/metadataField.kt b/compiler/testData/codegen/box/jvmPackageName/metadataField.kt index 1bab482ee7c..7efd2b4eb9e 100644 --- a/compiler/testData/codegen/box/jvmPackageName/metadataField.kt +++ b/compiler/testData/codegen/box/jvmPackageName/metadataField.kt @@ -1,8 +1,7 @@ -// IGNORE_BACKEND: JVM_IR // TARGET_BACKEND: JVM // WITH_RUNTIME -// FILE: foo.kt +// FILE: singleFileFacade.kt @file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") @file:JvmPackageName("baz.foo.quux.bar") @@ -10,17 +9,35 @@ package foo.bar fun f() {} +// FILE: multiFile.kt + +@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") +@file:JvmPackageName("bar.baz.quux.foo") +@file:JvmMultifileClass +@file:JvmName("Facade") +package foo.bar + +fun g() {} + // FILE: bar.kt +package test + fun getPackageName(classFqName: String): String = Class.forName(classFqName).getAnnotation(Metadata::class.java).packageName fun box(): String { - val bar = getPackageName("BarKt") + val bar = getPackageName("test.BarKt") if (bar != "") return "Fail 1: $bar" - val foo = getPackageName("baz.foo.quux.bar.FooKt") - if (foo != "foo.bar") return "Fail 2: $foo" + val singleFileFacade = getPackageName("baz.foo.quux.bar.SingleFileFacadeKt") + if (singleFileFacade != "foo.bar") return "Fail 2: $singleFileFacade" + + val multiFileFacade = getPackageName("bar.baz.quux.foo.Facade") + if (multiFileFacade != "foo.bar") return "Fail 3: $multiFileFacade" + + val multiFilePart = getPackageName("bar.baz.quux.foo.Facade__MultiFileKt") + if (multiFilePart != "foo.bar") return "Fail 4: $multiFilePart" return "OK" }