kotlinx-metadata-jvm: Handle the jvmClassFlags extension
This commit is contained in:
committed by
Alexander Udalov
parent
9bc87b17bd
commit
c552b5f820
@@ -31,6 +31,31 @@ object JvmFlag {
|
||||
val IS_MOVED_FROM_INTERFACE_COMPANION = booleanFlag(JF.IS_MOVED_FROM_INTERFACE_COMPANION)
|
||||
}
|
||||
|
||||
/**
|
||||
* JVM-specific class flags in addition to common class flags declared in [Flag.Class].
|
||||
*/
|
||||
object Class {
|
||||
/**
|
||||
* Applied to an interface compiled with -Xjvm-default=all or all-compatibility.
|
||||
*
|
||||
* Without this flag or a `@JvmDefault` annotation on individual interface methods
|
||||
* the Kotlin compiler moves all interface method bodies into a nested `DefaultImpls`
|
||||
* class.
|
||||
*/
|
||||
@JvmField
|
||||
val HAS_METHOD_BODIES_IN_INTERFACE = booleanFlag(JF.ARE_INTERFACE_METHOD_BODIES_INSIDE)
|
||||
|
||||
/**
|
||||
* Applied to an interface compiled with -Xjvm-default=all-compatibility.
|
||||
*
|
||||
* In compatibility mode we generate method bodies directly in the interface,
|
||||
* but we also generate bridges in a nested `DefaultImpls` class for use by
|
||||
* clients compiled without all-compatibility.
|
||||
*/
|
||||
@JvmField
|
||||
val IS_COMPILED_IN_COMPATIBILITY_MODE = booleanFlag(JF.IS_ALL_COMPATIBILITY_MODE)
|
||||
}
|
||||
|
||||
private fun booleanFlag(f: F.BooleanFlagField): Flag =
|
||||
Flag(f.offset, f.bitWidth, 1)
|
||||
}
|
||||
|
||||
@@ -31,6 +31,8 @@ internal class JvmMetadataExtensions : MetadataExtensions {
|
||||
|
||||
ext.visitModuleName(proto.getExtensionOrNull(JvmProtoBuf.classModuleName)?.let(c::get) ?: JvmProtoBufUtil.DEFAULT_MODULE_NAME)
|
||||
|
||||
proto.getExtensionOrNull(JvmProtoBuf.jvmClassFlags)?.let(ext::visitJvmFlags)
|
||||
|
||||
ext.visitEnd()
|
||||
}
|
||||
|
||||
@@ -133,6 +135,12 @@ internal class JvmMetadataExtensions : MetadataExtensions {
|
||||
proto.setExtension(JvmProtoBuf.classModuleName, c[name])
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitJvmFlags(flags: Flags) {
|
||||
if (flags != 0) {
|
||||
proto.setExtension(JvmProtoBuf.jvmClassFlags, flags)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ internal class JvmClassExtension : JvmClassExtensionVisitor(), KmClassExtension
|
||||
val localDelegatedProperties: MutableList<KmProperty> = ArrayList(0)
|
||||
var moduleName: String? = null
|
||||
var anonymousObjectOriginName: String? = null
|
||||
var jvmFlags: Flags = 0
|
||||
|
||||
override fun visitLocalDelegatedProperty(flags: Flags, name: String, getterFlags: Flags, setterFlags: Flags): KmPropertyVisitor =
|
||||
KmProperty(flags, name, getterFlags, setterFlags).also { localDelegatedProperties.add(it) }
|
||||
@@ -47,6 +48,10 @@ internal class JvmClassExtension : JvmClassExtensionVisitor(), KmClassExtension
|
||||
this.anonymousObjectOriginName = internalName
|
||||
}
|
||||
|
||||
override fun visitJvmFlags(flags: Flags) {
|
||||
this.jvmFlags = flags
|
||||
}
|
||||
|
||||
override fun accept(visitor: KmClassExtensionVisitor) {
|
||||
require(visitor is JvmClassExtensionVisitor)
|
||||
localDelegatedProperties.forEach {
|
||||
@@ -54,6 +59,7 @@ internal class JvmClassExtension : JvmClassExtensionVisitor(), KmClassExtension
|
||||
}
|
||||
moduleName?.let(visitor::visitModuleName)
|
||||
anonymousObjectOriginName?.let(visitor::visitAnonymousObjectOriginName)
|
||||
jvmFlags.takeIf { it != 0 }?.let(visitor::visitJvmFlags)
|
||||
visitor.visitEnd()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,6 +61,13 @@ open class JvmClassExtensionVisitor @JvmOverloads constructor(
|
||||
delegate?.visitAnonymousObjectOriginName(internalName)
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits the JVM-specific flags of the class, consisting of [JvmFlag.Class] flags.
|
||||
*/
|
||||
open fun visitJvmFlags(flags: Flags) {
|
||||
delegate?.visitJvmFlags(flags)
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits the end of JVM extensions for the class.
|
||||
*/
|
||||
|
||||
@@ -41,6 +41,15 @@ var KmClass.anonymousObjectOriginName: String?
|
||||
jvm.anonymousObjectOriginName = value
|
||||
}
|
||||
|
||||
/**
|
||||
* JVM-specific flags of the class, consisting of [JvmFlag.Class] flags.
|
||||
*/
|
||||
var KmClass.jvmFlags: Flags
|
||||
get() = jvm.jvmFlags
|
||||
set(value) {
|
||||
jvm.jvmFlags = value
|
||||
}
|
||||
|
||||
/**
|
||||
* Metadata of local delegated properties used somewhere inside this package fragment (but not in any class).
|
||||
* Note that for classes produced by the Kotlin compiler, such properties will have default accessors.
|
||||
|
||||
@@ -214,4 +214,26 @@ class MetadataSmokeTest {
|
||||
|
||||
KotlinModuleMetadata.Writer().write(mv)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun jvmClassFlags() {
|
||||
// Test that we can (de-)serialize the jvmClassFlags extension. All the flags that currently
|
||||
// exist are controlled by compiler options, so we have to manually create metadata with the
|
||||
// flags set. Since the current flags only apply to interfaces with default functions we modify
|
||||
// the metadata for the kotlin.coroutines.CoroutineContext interface.
|
||||
val jvmClassFlags: Flags = flagsOf(
|
||||
JvmFlag.Class.IS_COMPILED_IN_COMPATIBILITY_MODE,
|
||||
JvmFlag.Class.HAS_METHOD_BODIES_IN_INTERFACE
|
||||
)
|
||||
|
||||
val metadata = CoroutineContext::class.java.readMetadata()
|
||||
val kmClass = (KotlinClassMetadata.read(metadata) as KotlinClassMetadata.Class).toKmClass()
|
||||
kmClass.jvmFlags = jvmClassFlags
|
||||
|
||||
val kmClassCopy = KotlinClassMetadata.Class.Writer()
|
||||
.also { kmClass.accept(it) }
|
||||
.write(metadata.metadataVersion, metadata.extraInt)
|
||||
.toKmClass()
|
||||
assertEquals(kmClassCopy.jvmFlags, jvmClassFlags)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user