From e1a4bd01f561b49179ab7cc9a099e5eeaf99ea56 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Wed, 16 May 2018 15:23:25 +0200 Subject: [PATCH] Add anonymousObjectOriginName/lambdaClassOriginName to kotlinx-metadata #KT-21320 #KT-23198 --- .../compiledKotlin/inline/inlineFunction.kt | 9 +++-- .../compiledKotlin/inline/inlineFunction.txt | 2 +- .../jvm/impl/JvmMetadataExtensions.kt | 29 ++++++++++++++++ .../src/kotlinx/metadata/jvm/jvmExtensions.kt | 33 +++++++++++++++++++ .../src/kotlinx/metadata/extensions.kt | 5 +++ .../impl/extensions/MetadataExtensions.kt | 4 +++ .../src/kotlinx/metadata/impl/readers.kt | 4 +++ .../src/kotlinx/metadata/impl/writers.kt | 5 +++ .../src/kotlinx/metadata/visitors.kt | 8 +++++ .../org/jetbrains/kotlin/kotlinp/printers.kt | 21 ++++++++++++ 10 files changed, 117 insertions(+), 3 deletions(-) diff --git a/compiler/testData/loadJava/compiledKotlin/inline/inlineFunction.kt b/compiler/testData/loadJava/compiledKotlin/inline/inlineFunction.kt index 87211fc54a6..7691e8c76e1 100644 --- a/compiler/testData/loadJava/compiledKotlin/inline/inlineFunction.kt +++ b/compiler/testData/loadJava/compiledKotlin/inline/inlineFunction.kt @@ -5,6 +5,11 @@ inline fun a() {} inline fun b() {} -inline fun c() {} +inline fun c(crossinline f: () -> Unit) { + object { init { f() }} + { f() } +} -inline fun d() {} \ No newline at end of file +inline fun d() { + c {} +} diff --git a/compiler/testData/loadJava/compiledKotlin/inline/inlineFunction.txt b/compiler/testData/loadJava/compiledKotlin/inline/inlineFunction.txt index 77ea3256fda..31e59579ef8 100644 --- a/compiler/testData/loadJava/compiledKotlin/inline/inlineFunction.txt +++ b/compiler/testData/loadJava/compiledKotlin/inline/inlineFunction.txt @@ -2,5 +2,5 @@ package test public inline fun a(): kotlin.Unit public inline fun b(): kotlin.Unit -public inline fun c(): kotlin.Unit +public inline fun c(/*0*/ crossinline f: () -> kotlin.Unit): kotlin.Unit public inline fun d(): kotlin.Unit diff --git a/libraries/kotlinx-metadata/jvm/src/kotlinx/metadata/jvm/impl/JvmMetadataExtensions.kt b/libraries/kotlinx-metadata/jvm/src/kotlinx/metadata/jvm/impl/JvmMetadataExtensions.kt index 3e551886e49..7a49b6773d0 100644 --- a/libraries/kotlinx-metadata/jvm/src/kotlinx/metadata/jvm/impl/JvmMetadataExtensions.kt +++ b/libraries/kotlinx-metadata/jvm/src/kotlinx/metadata/jvm/impl/JvmMetadataExtensions.kt @@ -19,9 +19,23 @@ import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil import org.jetbrains.kotlin.metadata.serialization.StringTable internal class JvmMetadataExtensions : MetadataExtensions { + override fun readClassExtensions(v: KmClassVisitor, proto: ProtoBuf.Class, strings: NameResolver, types: TypeTable) { + val ext = v.visitExtensions(JvmClassExtensionVisitor.TYPE) as? JvmClassExtensionVisitor ?: return + + val anonymousObjectOriginName = proto.getExtensionOrNull(JvmProtoBuf.anonymousObjectOriginName) + if (anonymousObjectOriginName != null) { + ext.visitAnonymousObjectOriginName(strings.getString(anonymousObjectOriginName)) + } + } + override fun readFunctionExtensions(v: KmFunctionVisitor, proto: ProtoBuf.Function, strings: NameResolver, types: TypeTable) { val ext = v.visitExtensions(JvmFunctionExtensionVisitor.TYPE) as? JvmFunctionExtensionVisitor ?: return ext.visit(JvmProtoBufUtil.getJvmMethodSignature(proto, strings, types)) + + val lambdaClassOriginName = proto.getExtensionOrNull(JvmProtoBuf.lambdaClassOriginName) + if (lambdaClassOriginName != null) { + ext.visitLambdaClassOriginName(strings.getString(lambdaClassOriginName)) + } } override fun readPropertyExtensions(v: KmPropertyVisitor, proto: ProtoBuf.Property, strings: NameResolver, types: TypeTable) { @@ -68,6 +82,17 @@ internal class JvmMetadataExtensions : MetadataExtensions { ext.visitEnd() } + override fun writeClassExtensions( + type: KmExtensionType, proto: ProtoBuf.Class.Builder, strings: StringTable + ): KmClassExtensionVisitor? { + if (type != JvmClassExtensionVisitor.TYPE) return null + return object : JvmClassExtensionVisitor() { + override fun visitAnonymousObjectOriginName(internalName: String) { + proto.setExtension(JvmProtoBuf.anonymousObjectOriginName, strings.getStringIndex(internalName)) + } + } + } + override fun writeFunctionExtensions( type: KmExtensionType, proto: ProtoBuf.Function.Builder, strings: StringTable ): KmFunctionExtensionVisitor? { @@ -78,6 +103,10 @@ internal class JvmMetadataExtensions : MetadataExtensions { proto.setExtension(JvmProtoBuf.methodSignature, desc.toJvmMethodSignature(strings)) } } + + override fun visitLambdaClassOriginName(internalName: String) { + proto.setExtension(JvmProtoBuf.lambdaClassOriginName, strings.getStringIndex(internalName)) + } } } diff --git a/libraries/kotlinx-metadata/jvm/src/kotlinx/metadata/jvm/jvmExtensions.kt b/libraries/kotlinx-metadata/jvm/src/kotlinx/metadata/jvm/jvmExtensions.kt index ddada1eff4f..0572d8f9e00 100644 --- a/libraries/kotlinx-metadata/jvm/src/kotlinx/metadata/jvm/jvmExtensions.kt +++ b/libraries/kotlinx-metadata/jvm/src/kotlinx/metadata/jvm/jvmExtensions.kt @@ -8,6 +8,31 @@ package kotlinx.metadata.jvm import kotlinx.metadata.* import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil +/** + * A visitor to visit JVM extensions for a function. + */ +open class JvmClassExtensionVisitor @JvmOverloads constructor( + private val delegate: JvmClassExtensionVisitor? = null +) : KmClassExtensionVisitor { + /** + * 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. + */ + open fun visitAnonymousObjectOriginName(internalName: String) { + delegate?.visitAnonymousObjectOriginName(internalName) + } + + companion object { + /** + * The type of this extension visitor. + * + * @see KmExtensionType + */ + @JvmField + val TYPE: KmExtensionType = KmExtensionType(JvmClassExtensionVisitor::class) + } +} + /** * A visitor to visit JVM extensions for a function. */ @@ -24,6 +49,14 @@ open class JvmFunctionExtensionVisitor @JvmOverloads constructor( delegate?.visit(desc) } + /** + * Visits the JVM internal name of the original class the lambda class for this function is copied from. + * This information is present for lambdas copied from bodies of inline functions to the use site by the Kotlin compiler. + */ + open fun visitLambdaClassOriginName(internalName: String) { + delegate?.visitLambdaClassOriginName(internalName) + } + companion object { /** * The type of this extension visitor. diff --git a/libraries/kotlinx-metadata/src/kotlinx/metadata/extensions.kt b/libraries/kotlinx-metadata/src/kotlinx/metadata/extensions.kt index a10ad3a48b3..9dcdb202365 100644 --- a/libraries/kotlinx-metadata/src/kotlinx/metadata/extensions.kt +++ b/libraries/kotlinx-metadata/src/kotlinx/metadata/extensions.kt @@ -35,6 +35,11 @@ data class KmExtensionType(val klass: KClass) */ interface KmExtensionVisitor +/** + * A visitor to visit platform-specific extensions for a class. + */ +interface KmClassExtensionVisitor : KmExtensionVisitor + /** * A visitor to visit platform-specific extensions for a function. */ diff --git a/libraries/kotlinx-metadata/src/kotlinx/metadata/impl/extensions/MetadataExtensions.kt b/libraries/kotlinx-metadata/src/kotlinx/metadata/impl/extensions/MetadataExtensions.kt index b7bdea8c68c..82020488764 100644 --- a/libraries/kotlinx-metadata/src/kotlinx/metadata/impl/extensions/MetadataExtensions.kt +++ b/libraries/kotlinx-metadata/src/kotlinx/metadata/impl/extensions/MetadataExtensions.kt @@ -13,6 +13,8 @@ import org.jetbrains.kotlin.metadata.serialization.StringTable import java.util.* interface MetadataExtensions { + fun readClassExtensions(v: KmClassVisitor, proto: ProtoBuf.Class, strings: NameResolver, types: TypeTable) + fun readFunctionExtensions(v: KmFunctionVisitor, proto: ProtoBuf.Function, strings: NameResolver, types: TypeTable) fun readPropertyExtensions(v: KmPropertyVisitor, proto: ProtoBuf.Property, strings: NameResolver, types: TypeTable) @@ -23,6 +25,8 @@ interface MetadataExtensions { fun readTypeExtensions(v: KmTypeVisitor, proto: ProtoBuf.Type, strings: NameResolver) + fun writeClassExtensions(type: KmExtensionType, proto: ProtoBuf.Class.Builder, strings: StringTable): KmClassExtensionVisitor? + fun writeFunctionExtensions(type: KmExtensionType, proto: ProtoBuf.Function.Builder, strings: StringTable): KmFunctionExtensionVisitor? fun writePropertyExtensions(type: KmExtensionType, proto: ProtoBuf.Property.Builder, strings: StringTable): KmPropertyExtensionVisitor? diff --git a/libraries/kotlinx-metadata/src/kotlinx/metadata/impl/readers.kt b/libraries/kotlinx-metadata/src/kotlinx/metadata/impl/readers.kt index bdf80844b45..bba90440713 100644 --- a/libraries/kotlinx-metadata/src/kotlinx/metadata/impl/readers.kt +++ b/libraries/kotlinx-metadata/src/kotlinx/metadata/impl/readers.kt @@ -81,6 +81,10 @@ fun ProtoBuf.Class.accept(v: KmClassVisitor, strings: NameResolver) { v.visitVersionRequirement()?.let { acceptVersionRequirementVisitor(it, c) } } + for (extension in c.extensions) { + extension.readClassExtensions(v, this, c.strings, c.types) + } + v.visitEnd() } diff --git a/libraries/kotlinx-metadata/src/kotlinx/metadata/impl/writers.kt b/libraries/kotlinx-metadata/src/kotlinx/metadata/impl/writers.kt index d1662c0e37a..f4685def273 100644 --- a/libraries/kotlinx-metadata/src/kotlinx/metadata/impl/writers.kt +++ b/libraries/kotlinx-metadata/src/kotlinx/metadata/impl/writers.kt @@ -455,6 +455,11 @@ open class ClassWriter(stringTable: StringTable) : KmClassVisitor() { override fun visitVersionRequirement(): KmVersionRequirementVisitor? = writeVersionRequirement(c) { t.versionRequirement = it } + override fun visitExtensions(type: KmExtensionType): KmClassExtensionVisitor? = + c.applySingleExtension(type) { + writeClassExtensions(type, t, c.strings) + } + override fun visitEnd() { c.versionRequirements.serialize()?.let { t.versionRequirementTable = it diff --git a/libraries/kotlinx-metadata/src/kotlinx/metadata/visitors.kt b/libraries/kotlinx-metadata/src/kotlinx/metadata/visitors.kt index 309a872e47b..2536086d281 100644 --- a/libraries/kotlinx-metadata/src/kotlinx/metadata/visitors.kt +++ b/libraries/kotlinx-metadata/src/kotlinx/metadata/visitors.kt @@ -131,6 +131,14 @@ abstract class KmClassVisitor @JvmOverloads constructor(delegate: KmClassVisitor open fun visitVersionRequirement(): KmVersionRequirementVisitor? = delegate?.visitVersionRequirement() + /** + * Visits the extensions of the given type on the class. + * + * @param type the type of extension visitor to be returned + */ + open fun visitExtensions(type: KmExtensionType): KmClassExtensionVisitor? = + delegate?.visitExtensions(type) + /** * Visits the end of the class. */ diff --git a/libraries/tools/kotlinp/src/org/jetbrains/kotlin/kotlinp/printers.kt b/libraries/tools/kotlinp/src/org/jetbrains/kotlin/kotlinp/printers.kt index 7cf0ac7b19f..ed3ca5e9b36 100644 --- a/libraries/tools/kotlinp/src/org/jetbrains/kotlin/kotlinp/printers.kt +++ b/libraries/tools/kotlinp/src/org/jetbrains/kotlin/kotlinp/printers.kt @@ -20,6 +20,7 @@ private fun visitFunction(settings: KotlinpSettings, sb: StringBuilder, flags: F var returnType: String? = null var versionRequirement: String? = null var jvmDesc: String? = null + var lambdaClassOriginName: String? = null override fun visitReceiverParameterType(flags: Flags): KmTypeVisitor? = printType(flags) { receiverParameterType = it } @@ -44,11 +45,18 @@ private fun visitFunction(settings: KotlinpSettings, sb: StringBuilder, flags: F override fun visit(desc: String?) { jvmDesc = desc } + + override fun visitLambdaClassOriginName(internalName: String) { + lambdaClassOriginName = internalName + } } } override fun visitEnd() { sb.appendln() + if (lambdaClassOriginName != null) { + sb.appendln(" // lambda class origin: $lambdaClassOriginName") + } if (versionRequirement != null) { sb.appendln(" // $versionRequirement") } @@ -520,6 +528,7 @@ class ClassPrinter(private val settings: KotlinpSettings) : KmClassVisitor(), Ab private val typeParams = mutableListOf() private val supertypes = mutableListOf() private var versionRequirement: String? = null + private var anonymousObjectOriginName: String? = null override fun visit(flags: Flags, name: ClassName) { this.flags = flags @@ -527,6 +536,9 @@ class ClassPrinter(private val settings: KotlinpSettings) : KmClassVisitor(), Ab } override fun visitEnd() { + if (anonymousObjectOriginName != null) { + result.appendln("// anonymous object origin: $anonymousObjectOriginName") + } if (versionRequirement != null) { result.appendln(" // $versionRequirement") } @@ -585,6 +597,15 @@ class ClassPrinter(private val settings: KotlinpSettings) : KmClassVisitor(), Ab override fun visitVersionRequirement(): KmVersionRequirementVisitor? = printVersionRequirement { versionRequirement = it } + override fun visitExtensions(type: KmExtensionType): KmClassExtensionVisitor? { + if (type != JvmClassExtensionVisitor.TYPE) return null + return object : JvmClassExtensionVisitor() { + override fun visitAnonymousObjectOriginName(internalName: String) { + anonymousObjectOriginName = internalName + } + } + } + override fun print(klass: KotlinClassMetadata.Class): String { klass.accept(this) return result.toString()