Support local delegated properties in kotlinx-metadata-jvm

This commit is contained in:
Alexander Udalov
2018-06-13 19:17:02 +02:00
parent b00f765255
commit fec2c14ea5
12 changed files with 330 additions and 20 deletions
@@ -1,5 +1,9 @@
# kotlinx-metadata-jvm
## 0.0.3
- Support metadata of local delegated properties (see `JvmDeclarationContainerExtensionVisitor.visitLocalDelegatedProperty`)
## 0.0.2
- Change group ID from `org.jetbrains.kotlin` to `org.jetbrains.kotlinx`
@@ -6,11 +6,8 @@
package kotlinx.metadata.jvm.impl
import kotlinx.metadata.*
import kotlinx.metadata.impl.ReadContext
import kotlinx.metadata.impl.WriteContext
import kotlinx.metadata.impl.*
import kotlinx.metadata.impl.extensions.MetadataExtensions
import kotlinx.metadata.impl.readAnnotation
import kotlinx.metadata.impl.writeAnnotation
import kotlinx.metadata.jvm.*
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.getExtensionOrNull
@@ -25,6 +22,26 @@ internal class JvmMetadataExtensions : MetadataExtensions {
if (anonymousObjectOriginName != null) {
ext.visitAnonymousObjectOriginName(c[anonymousObjectOriginName])
}
for (property in proto.getExtension(JvmProtoBuf.classLocalVariable)) {
ext.visitLocalDelegatedProperty(
property.flags, c[property.name], property.getPropertyGetterFlags(), property.getPropertySetterFlags()
)?.let { property.accept(it, c) }
}
ext.visitEnd()
}
override fun readPackageExtensions(v: KmPackageVisitor, proto: ProtoBuf.Package, c: ReadContext) {
val ext = v.visitExtensions(JvmPackageExtensionVisitor.TYPE) as? JvmPackageExtensionVisitor ?: return
for (property in proto.getExtension(JvmProtoBuf.packageLocalVariable)) {
ext.visitLocalDelegatedProperty(
property.flags, c[property.name], property.getPropertyGetterFlags(), property.getPropertySetterFlags()
)?.let { property.accept(it, c) }
}
ext.visitEnd()
}
override fun readFunctionExtensions(v: KmFunctionVisitor, proto: ProtoBuf.Function, c: ReadContext) {
@@ -86,6 +103,25 @@ internal class JvmMetadataExtensions : MetadataExtensions {
override fun visitAnonymousObjectOriginName(internalName: String) {
proto.setExtension(JvmProtoBuf.anonymousObjectOriginName, c[internalName])
}
override fun visitLocalDelegatedProperty(
flags: Flags, name: String, getterFlags: Flags, setterFlags: Flags
): KmPropertyVisitor = writeProperty(c, flags, name, getterFlags, setterFlags) {
proto.addExtension(JvmProtoBuf.classLocalVariable, it.build())
}
}
}
override fun writePackageExtensions(
type: KmExtensionType, proto: ProtoBuf.Package.Builder, c: WriteContext
): KmPackageExtensionVisitor? {
if (type != JvmPackageExtensionVisitor.TYPE) return null
return object : JvmPackageExtensionVisitor() {
override fun visitLocalDelegatedProperty(
flags: Flags, name: String, getterFlags: Flags, setterFlags: Flags
): KmPropertyVisitor = writeProperty(c, flags, name, getterFlags, setterFlags) {
proto.addExtension(JvmProtoBuf.packageLocalVariable, it.build())
}
}
}
@@ -9,11 +9,40 @@ import kotlinx.metadata.*
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
/**
* A visitor to visit JVM extensions for a function.
* A visitor containing the common code to visit JVM extensions for Kotlin declaration containers, such as classes and package fragments.
*/
abstract class JvmDeclarationContainerExtensionVisitor @JvmOverloads constructor(
protected open val delegate: JvmDeclarationContainerExtensionVisitor? = null
) : KmDeclarationContainerExtensionVisitor {
/**
* Visits the metadata of a local delegated property used somewhere inside this container (but not in a nested declaration container).
* Note that for classes produced by the Kotlin compiler, such properties will have default accessors.
*
* The order of visited local delegated properties is important. The Kotlin compiler generates the corresponding property's index
* at the call site, so that reflection would be able to load the metadata of the property with that index at runtime.
* If an incorrect index is used, either the `KProperty<*>` object passed to delegate methods will point to the wrong property
* at runtime, or an exception will be thrown.
*
* @param flags property flags, consisting of [Flag.HAS_ANNOTATIONS], visibility flag, modality flag and [Flag.Property] flags
* @param name the name of the property
* @param getterFlags property accessor flags, consisting of [Flag.HAS_ANNOTATIONS], visibility flag, modality flag
* and [Flag.PropertyAccessor] flags
* @param setterFlags property accessor flags, consisting of [Flag.HAS_ANNOTATIONS], visibility flag, modality flag
* and [Flag.PropertyAccessor] flags
*/
open fun visitLocalDelegatedProperty(flags: Flags, name: String, getterFlags: Flags, setterFlags: Flags): KmPropertyVisitor? =
delegate?.visitLocalDelegatedProperty(flags, name, getterFlags, setterFlags)
}
/**
* A visitor to visit JVM extensions for a class.
*/
open class JvmClassExtensionVisitor @JvmOverloads constructor(
private val delegate: JvmClassExtensionVisitor? = null
) : KmClassExtensionVisitor {
delegate: JvmClassExtensionVisitor? = null
) : KmClassExtensionVisitor, JvmDeclarationContainerExtensionVisitor(delegate) {
override val delegate: JvmClassExtensionVisitor?
get() = super.delegate as JvmClassExtensionVisitor?
/**
* Visits the JVM internal name of the original class this anonymous object is copied from. This method is called for
* anonymous objects copied from bodies of inline functions to the use site by the Kotlin compiler.
@@ -22,6 +51,13 @@ open class JvmClassExtensionVisitor @JvmOverloads constructor(
delegate?.visitAnonymousObjectOriginName(internalName)
}
/**
* Visits the end of JVM extensions for the class.
*/
open fun visitEnd() {
delegate?.visitEnd()
}
companion object {
/**
* The type of this extension visitor.
@@ -33,6 +69,33 @@ open class JvmClassExtensionVisitor @JvmOverloads constructor(
}
}
/**
* A visitor to visit JVM extensions for a package fragment.
*/
open class JvmPackageExtensionVisitor @JvmOverloads constructor(
delegate: JvmPackageExtensionVisitor? = null
) : KmPackageExtensionVisitor, JvmDeclarationContainerExtensionVisitor(delegate) {
override val delegate: JvmPackageExtensionVisitor?
get() = super.delegate as JvmPackageExtensionVisitor?
/**
* Visits the end of JVM extensions for the package fragment.
*/
open fun visitEnd() {
delegate?.visitEnd()
}
companion object {
/**
* The type of this extension visitor.
*
* @see KmExtensionType
*/
@JvmField
val TYPE: KmExtensionType = KmExtensionType(JvmPackageExtensionVisitor::class)
}
}
/**
* A visitor to visit JVM extensions for a function.
*/
@@ -35,10 +35,20 @@ data class KmExtensionType(val klass: KClass<out KmExtensionVisitor>)
*/
interface KmExtensionVisitor
/**
* A visitor to visit platform-specific extensions for a declaration container, such as a class or a package fragment.
*/
interface KmDeclarationContainerExtensionVisitor : KmExtensionVisitor
/**
* A visitor to visit platform-specific extensions for a class.
*/
interface KmClassExtensionVisitor : KmExtensionVisitor
interface KmClassExtensionVisitor : KmDeclarationContainerExtensionVisitor
/**
* A visitor to visit platform-specific extensions for a package fragment.
*/
interface KmPackageExtensionVisitor : KmDeclarationContainerExtensionVisitor
/**
* A visitor to visit platform-specific extensions for a function.
@@ -14,6 +14,8 @@ import java.util.*
interface MetadataExtensions {
fun readClassExtensions(v: KmClassVisitor, proto: ProtoBuf.Class, c: ReadContext)
fun readPackageExtensions(v: KmPackageVisitor, proto: ProtoBuf.Package, c: ReadContext)
fun readFunctionExtensions(v: KmFunctionVisitor, proto: ProtoBuf.Function, c: ReadContext)
fun readPropertyExtensions(v: KmPropertyVisitor, proto: ProtoBuf.Property, c: ReadContext)
@@ -26,6 +28,8 @@ interface MetadataExtensions {
fun writeClassExtensions(type: KmExtensionType, proto: ProtoBuf.Class.Builder, c: WriteContext): KmClassExtensionVisitor?
fun writePackageExtensions(type: KmExtensionType, proto: ProtoBuf.Package.Builder, c: WriteContext): KmPackageExtensionVisitor?
fun writeFunctionExtensions(type: KmExtensionType, proto: ProtoBuf.Function.Builder, c: WriteContext): KmFunctionExtensionVisitor?
fun writePropertyExtensions(type: KmExtensionType, proto: ProtoBuf.Property.Builder, c: WriteContext): KmPropertyExtensionVisitor?
@@ -93,6 +93,10 @@ fun ProtoBuf.Package.accept(v: KmPackageVisitor, strings: NameResolver) {
v.visitDeclarations(functionList, propertyList, typeAliasList, c)
for (extension in c.extensions) {
extension.readPackageExtensions(v, this, c)
}
v.visitEnd()
}
@@ -107,15 +111,8 @@ private fun KmDeclarationContainerVisitor.visitDeclarations(
}
for (property in properties) {
val flags = property.flags
val defaultAccessorFlags = F.getAccessorFlags(
F.HAS_ANNOTATIONS.get(flags), F.VISIBILITY.get(flags), F.MODALITY.get(flags), false, false, false
)
visitProperty(
flags,
c[property.name],
if (property.hasGetterFlags()) property.getterFlags else defaultAccessorFlags,
if (property.hasSetterFlags()) property.setterFlags else defaultAccessorFlags
property.flags, c[property.name], property.getPropertyGetterFlags(), property.getPropertySetterFlags()
)?.let { property.accept(it, c) }
}
@@ -182,7 +179,7 @@ private fun ProtoBuf.Function.accept(v: KmFunctionVisitor, outer: ReadContext) {
v.visitEnd()
}
private fun ProtoBuf.Property.accept(v: KmPropertyVisitor, outer: ReadContext) {
fun ProtoBuf.Property.accept(v: KmPropertyVisitor, outer: ReadContext) {
val c = outer.withTypeParameters(typeParameterList)
for (typeParameter in typeParameterList) {
@@ -425,3 +422,12 @@ private val ProtoBuf.Type.typeFlags: Flags
private val ProtoBuf.TypeParameter.typeParameterFlags: Flags
get() = if (reified) 1 else 0
fun ProtoBuf.Property.getPropertyGetterFlags(): Flags =
if (hasGetterFlags()) getterFlags else getDefaultPropertyAccessorFlags(flags)
fun ProtoBuf.Property.getPropertySetterFlags(): Flags =
if (hasSetterFlags()) setterFlags else getDefaultPropertyAccessorFlags(flags)
private fun getDefaultPropertyAccessorFlags(flags: Flags): Flags =
F.getAccessorFlags(F.HAS_ANNOTATIONS.get(flags), F.VISIBILITY.get(flags), F.MODALITY.get(flags), false, false, false)
@@ -190,7 +190,7 @@ private fun writeFunction(c: WriteContext, flags: Flags, name: String, output: (
}
}
private fun writeProperty(
fun writeProperty(
c: WriteContext, flags: Flags, name: String, getterFlags: Flags, setterFlags: Flags, output: (ProtoBuf.Property.Builder) -> Unit
): KmPropertyVisitor = object : KmPropertyVisitor() {
val t = ProtoBuf.Property.newBuilder()
@@ -480,6 +480,11 @@ open class PackageWriter(stringTable: StringTable) : KmPackageVisitor() {
override fun visitTypeAlias(flags: Flags, name: String): KmTypeAliasVisitor? =
writeTypeAlias(c, flags, name) { t.addTypeAlias(it) }
override fun visitExtensions(type: KmExtensionType): KmPackageExtensionVisitor? =
c.applySingleExtension(type) {
writePackageExtensions(type, t, c)
}
override fun visitEnd() {
c.versionRequirements.serialize()?.let {
t.versionRequirementTable = it
@@ -6,7 +6,7 @@
package kotlinx.metadata
/**
* A visitor to visit Kotlin declarations, which are containers of other declarations: functions, properties and type aliases.
* A visitor containing the common code to visit Kotlin declaration containers, such as classes and package fragments.
*/
abstract class KmDeclarationContainerVisitor @JvmOverloads constructor(protected open val delegate: KmDeclarationContainerVisitor? = null) {
/**
@@ -39,6 +39,13 @@ abstract class KmDeclarationContainerVisitor @JvmOverloads constructor(protected
*/
open fun visitTypeAlias(flags: Flags, name: String): KmTypeAliasVisitor? =
delegate?.visitTypeAlias(flags, name)
/**
* Visits the extensions of the given type on the container.
*
* @param type the type of extension visitor to be returned
*/
abstract fun visitExtensions(type: KmExtensionType): KmDeclarationContainerExtensionVisitor?
}
/**
@@ -136,7 +143,7 @@ abstract class KmClassVisitor @JvmOverloads constructor(delegate: KmClassVisitor
*
* @param type the type of extension visitor to be returned
*/
open fun visitExtensions(type: KmExtensionType): KmClassExtensionVisitor? =
override fun visitExtensions(type: KmExtensionType): KmClassExtensionVisitor? =
delegate?.visitExtensions(type)
/**
@@ -156,6 +163,14 @@ abstract class KmPackageVisitor @JvmOverloads constructor(delegate: KmPackageVis
override val delegate: KmPackageVisitor?
get() = super.delegate as KmPackageVisitor?
/**
* Visits the extensions of the given type on the package fragment.
*
* @param type the type of extension visitor to be returned
*/
override fun visitExtensions(type: KmExtensionType): KmPackageExtensionVisitor? =
delegate?.visitExtensions(type)
/**
* Visits the end of the package fragment.
*/