JVM IR: generate kotlin.Metadata.packageName value for JvmPackageName files

Support this for single file facades as well as for multi-file classes,
similar to code in
MultifileClassCodegen.writeKotlinMultifileFacadeAnnotationIfNeeded.
Extend the test on this attribute to also cover multi-file classes.
This commit is contained in:
Alexander Udalov
2019-11-08 20:30:33 +01:00
parent 808000e458
commit 9772de0088
4 changed files with 49 additions and 8 deletions
@@ -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 -> {
@@ -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)
@@ -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<IrFunctionSymbol, IrFunctionSymbol>
): List<IrFile> =
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)
@@ -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"
}