Support multiple MetadataExtensions instances in kotlinx-metadata
#KT-23198
This commit is contained in:
@@ -15,6 +15,7 @@ import kotlinx.metadata.impl.PackageWriter
|
||||
import kotlinx.metadata.impl.accept
|
||||
import kotlinx.metadata.jvm.impl.writeProtoBufData
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
|
||||
import org.jetbrains.kotlin.metadata.jvm.serialization.JvmStringTable
|
||||
import kotlin.LazyThreadSafetyMode.PUBLICATION
|
||||
|
||||
/**
|
||||
@@ -47,7 +48,7 @@ sealed class KotlinClassMetadata(val header: KotlinClassHeader) {
|
||||
/**
|
||||
* A [KmClassVisitor] that generates the metadata of a Kotlin class.
|
||||
*/
|
||||
class Writer : ClassWriter() {
|
||||
class Writer : ClassWriter(JvmStringTable()) {
|
||||
/**
|
||||
* Returns the metadata of the class that was written with this writer.
|
||||
*
|
||||
@@ -96,7 +97,7 @@ sealed class KotlinClassMetadata(val header: KotlinClassHeader) {
|
||||
/**
|
||||
* A [KmPackageVisitor] that generates the metadata of a Kotlin file facade.
|
||||
*/
|
||||
class Writer : PackageWriter() {
|
||||
class Writer : PackageWriter(JvmStringTable()) {
|
||||
/**
|
||||
* Returns the metadata of the file facade that was written with this writer.
|
||||
*
|
||||
@@ -161,7 +162,7 @@ sealed class KotlinClassMetadata(val header: KotlinClassHeader) {
|
||||
* call [Writer.visitFunction] and [Writer.visitEnd] on a newly created instance of this writer. If these methods are not called,
|
||||
* the resulting metadata will represent a _non-lambda_ synthetic class.
|
||||
*/
|
||||
class Writer : LambdaWriter() {
|
||||
class Writer : LambdaWriter(JvmStringTable()) {
|
||||
/**
|
||||
* Returns the metadata of the synthetic class that was written with this writer.
|
||||
*
|
||||
@@ -264,7 +265,7 @@ sealed class KotlinClassMetadata(val header: KotlinClassHeader) {
|
||||
/**
|
||||
* A [KmPackageVisitor] that generates the metadata of a multi-file class part.
|
||||
*/
|
||||
class Writer : PackageWriter() {
|
||||
class Writer : PackageWriter(JvmStringTable()) {
|
||||
/**
|
||||
* Returns the metadata of the multi-file class part that was written with this writer.
|
||||
*
|
||||
|
||||
@@ -16,7 +16,6 @@ import org.jetbrains.kotlin.metadata.deserialization.TypeTable
|
||||
import org.jetbrains.kotlin.metadata.deserialization.getExtensionOrNull
|
||||
import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
|
||||
import org.jetbrains.kotlin.metadata.jvm.serialization.JvmStringTable
|
||||
import org.jetbrains.kotlin.metadata.serialization.StringTable
|
||||
|
||||
internal class JvmMetadataExtensions : MetadataExtensions {
|
||||
@@ -69,8 +68,6 @@ internal class JvmMetadataExtensions : MetadataExtensions {
|
||||
ext.visitEnd()
|
||||
}
|
||||
|
||||
override fun createStringTable(): StringTable = JvmStringTable()
|
||||
|
||||
override fun writeFunctionExtensions(
|
||||
type: KmExtensionType, proto: ProtoBuf.Function.Builder, strings: StringTable
|
||||
): KmFunctionExtensionVisitor? {
|
||||
|
||||
+8
-9
@@ -23,8 +23,6 @@ interface MetadataExtensions {
|
||||
|
||||
fun readTypeExtensions(v: KmTypeVisitor, proto: ProtoBuf.Type, strings: NameResolver)
|
||||
|
||||
fun createStringTable(): StringTable
|
||||
|
||||
fun writeFunctionExtensions(type: KmExtensionType, proto: ProtoBuf.Function.Builder, strings: StringTable): KmFunctionExtensionVisitor?
|
||||
|
||||
fun writePropertyExtensions(type: KmExtensionType, proto: ProtoBuf.Property.Builder, strings: StringTable): KmPropertyExtensionVisitor?
|
||||
@@ -40,13 +38,14 @@ interface MetadataExtensions {
|
||||
fun writeTypeExtensions(type: KmExtensionType, proto: ProtoBuf.Type.Builder, strings: StringTable): KmTypeExtensionVisitor?
|
||||
|
||||
companion object {
|
||||
val INSTANCE: MetadataExtensions by lazy {
|
||||
ServiceLoader.load(MetadataExtensions::class.java).toList().firstOrNull()
|
||||
?: error(
|
||||
"No MetadataExtensions instances found in the classpath. Please ensure that the META-INF/services/ " +
|
||||
"is not stripped from your application and that the Java virtual machine is not running " +
|
||||
"under a security manager"
|
||||
)
|
||||
val INSTANCES: List<MetadataExtensions> by lazy {
|
||||
ServiceLoader.load(MetadataExtensions::class.java).toList().also {
|
||||
if (it.isEmpty()) error(
|
||||
"No MetadataExtensions instances found in the classpath. Please ensure that the META-INF/services/ " +
|
||||
"is not stripped from your application and that the Java virtual machine is not running " +
|
||||
"under a security manager"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ class ReadContext(
|
||||
internal val versionRequirements: VersionRequirementTable,
|
||||
private val parent: ReadContext? = null
|
||||
) {
|
||||
internal val extensions = MetadataExtensions.INSTANCE
|
||||
internal val extensions = MetadataExtensions.INSTANCES
|
||||
private val typeParameterNameToId = mutableMapOf<Int, Int>()
|
||||
|
||||
operator fun get(index: Int): String =
|
||||
@@ -137,7 +137,9 @@ private fun ProtoBuf.Constructor.accept(v: KmConstructorVisitor, c: ReadContext)
|
||||
v.visitVersionRequirement()?.let { acceptVersionRequirementVisitor(it, c) }
|
||||
}
|
||||
|
||||
c.extensions.readConstructorExtensions(v, this, c.strings, c.types)
|
||||
for (extension in c.extensions) {
|
||||
extension.readConstructorExtensions(v, this, c.strings, c.types)
|
||||
}
|
||||
|
||||
v.visitEnd()
|
||||
}
|
||||
@@ -169,7 +171,9 @@ private fun ProtoBuf.Function.accept(v: KmFunctionVisitor, outer: ReadContext) {
|
||||
v.visitVersionRequirement()?.let { acceptVersionRequirementVisitor(it, c) }
|
||||
}
|
||||
|
||||
c.extensions.readFunctionExtensions(v, this, c.strings, c.types)
|
||||
for (extension in c.extensions) {
|
||||
extension.readFunctionExtensions(v, this, c.strings, c.types)
|
||||
}
|
||||
|
||||
v.visitEnd()
|
||||
}
|
||||
@@ -198,7 +202,9 @@ private fun ProtoBuf.Property.accept(v: KmPropertyVisitor, outer: ReadContext) {
|
||||
v.visitVersionRequirement()?.let { acceptVersionRequirementVisitor(it, c) }
|
||||
}
|
||||
|
||||
c.extensions.readPropertyExtensions(v, this, c.strings, c.types)
|
||||
for (extension in c.extensions) {
|
||||
extension.readPropertyExtensions(v, this, c.strings, c.types)
|
||||
}
|
||||
|
||||
v.visitEnd()
|
||||
}
|
||||
@@ -259,7 +265,9 @@ private fun ProtoBuf.TypeParameter.accept(v: KmTypeParameterVisitor, c: ReadCont
|
||||
v.visitUpperBound(upperBound.typeFlags)?.let { upperBound.accept(it, c) }
|
||||
}
|
||||
|
||||
c.extensions.readTypeParameterExtensions(v, this, c.strings)
|
||||
for (extension in c.extensions) {
|
||||
extension.readTypeParameterExtensions(v, this, c.strings)
|
||||
}
|
||||
|
||||
v.visitEnd()
|
||||
}
|
||||
@@ -311,7 +319,9 @@ private fun ProtoBuf.Type.accept(v: KmTypeVisitor, c: ReadContext) {
|
||||
)?.let { upperBound.accept(it, c) }
|
||||
}
|
||||
|
||||
c.extensions.readTypeExtensions(v, this, c.strings)
|
||||
for (extension in c.extensions) {
|
||||
extension.readTypeExtensions(v, this, c.strings)
|
||||
}
|
||||
|
||||
v.visitEnd()
|
||||
}
|
||||
|
||||
@@ -12,9 +12,8 @@ import org.jetbrains.kotlin.metadata.deserialization.VersionRequirement
|
||||
import org.jetbrains.kotlin.metadata.serialization.MutableVersionRequirementTable
|
||||
import org.jetbrains.kotlin.metadata.serialization.StringTable
|
||||
|
||||
class WriteContext {
|
||||
internal val extensions = MetadataExtensions.INSTANCE
|
||||
val strings: StringTable = extensions.createStringTable()
|
||||
class WriteContext(val strings: StringTable) {
|
||||
internal val extensions = MetadataExtensions.INSTANCES
|
||||
val versionRequirements: MutableVersionRequirementTable = MutableVersionRequirementTable()
|
||||
|
||||
operator fun get(string: String): Int =
|
||||
@@ -22,6 +21,18 @@ class WriteContext {
|
||||
|
||||
fun getClassName(name: ClassName): Int =
|
||||
strings.getClassNameIndex(name)
|
||||
|
||||
internal fun <T : KmExtensionVisitor> applySingleExtension(type: KmExtensionType, block: MetadataExtensions.() -> T?): T? {
|
||||
var result: T? = null
|
||||
for (extension in extensions) {
|
||||
val current = block(extension) ?: continue
|
||||
if (result != null) {
|
||||
throw IllegalStateException("Multiple extensions handle the same extension type: $type")
|
||||
}
|
||||
result = current
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
private fun writeTypeParameter(
|
||||
@@ -35,7 +46,9 @@ private fun writeTypeParameter(
|
||||
writeType(c, flags) { t.addUpperBound(it) }
|
||||
|
||||
override fun visitExtensions(type: KmExtensionType): KmTypeParameterExtensionVisitor? =
|
||||
c.extensions.writeTypeParameterExtensions(type, t, c.strings)
|
||||
c.applySingleExtension(type) {
|
||||
writeTypeParameterExtensions(type, t, c.strings)
|
||||
}
|
||||
|
||||
override fun visitEnd() {
|
||||
t.name = c[name]
|
||||
@@ -102,7 +115,9 @@ private fun writeType(c: WriteContext, flags: Flags, output: (ProtoBuf.Type.Buil
|
||||
}
|
||||
|
||||
override fun visitExtensions(type: KmExtensionType): KmTypeExtensionVisitor? =
|
||||
c.extensions.writeTypeExtensions(type, t, c.strings)
|
||||
c.applySingleExtension(type) {
|
||||
writeTypeExtensions(type, t, c.strings)
|
||||
}
|
||||
|
||||
override fun visitEnd() {
|
||||
if (Flag.Type.IS_NULLABLE(flags)) {
|
||||
@@ -127,7 +142,9 @@ private fun writeConstructor(c: WriteContext, flags: Flags, output: (ProtoBuf.Co
|
||||
writeVersionRequirement(c) { t.versionRequirement = it }
|
||||
|
||||
override fun visitExtensions(type: KmExtensionType): KmConstructorExtensionVisitor? =
|
||||
c.extensions.writeConstructorExtensions(type, t, c.strings)
|
||||
c.applySingleExtension(type) {
|
||||
writeConstructorExtensions(type, t, c.strings)
|
||||
}
|
||||
|
||||
override fun visitEnd() {
|
||||
if (flags != ProtoBuf.Constructor.getDefaultInstance().flags) {
|
||||
@@ -160,7 +177,9 @@ private fun writeFunction(c: WriteContext, flags: Flags, name: String, output: (
|
||||
writeContract(c) { t.contract = it.build() }
|
||||
|
||||
override fun visitExtensions(type: KmExtensionType): KmFunctionExtensionVisitor? =
|
||||
c.extensions.writeFunctionExtensions(type, t, c.strings)
|
||||
c.applySingleExtension(type) {
|
||||
writeFunctionExtensions(type, t, c.strings)
|
||||
}
|
||||
|
||||
override fun visitEnd() {
|
||||
t.name = c[name]
|
||||
@@ -192,7 +211,9 @@ private fun writeProperty(
|
||||
writeVersionRequirement(c) { t.versionRequirement = it }
|
||||
|
||||
override fun visitExtensions(type: KmExtensionType): KmPropertyExtensionVisitor? =
|
||||
c.extensions.writePropertyExtensions(type, t, c.strings)
|
||||
c.applySingleExtension(type) {
|
||||
writePropertyExtensions(type, t, c.strings)
|
||||
}
|
||||
|
||||
override fun visitEnd() {
|
||||
t.name = c[name]
|
||||
@@ -384,9 +405,9 @@ private fun writeEffectExpression(c: WriteContext, output: (ProtoBuf.Expression.
|
||||
}
|
||||
}
|
||||
|
||||
open class ClassWriter : KmClassVisitor() {
|
||||
open class ClassWriter(stringTable: StringTable) : KmClassVisitor() {
|
||||
val t = ProtoBuf.Class.newBuilder()!!
|
||||
val c = WriteContext()
|
||||
val c = WriteContext(stringTable)
|
||||
|
||||
override fun visit(flags: Flags, name: ClassName) {
|
||||
if (flags != ProtoBuf.Class.getDefaultInstance().flags) {
|
||||
@@ -441,9 +462,9 @@ open class ClassWriter : KmClassVisitor() {
|
||||
}
|
||||
}
|
||||
|
||||
open class PackageWriter : KmPackageVisitor() {
|
||||
open class PackageWriter(stringTable: StringTable) : KmPackageVisitor() {
|
||||
val t = ProtoBuf.Package.newBuilder()!!
|
||||
val c = WriteContext()
|
||||
val c = WriteContext(stringTable)
|
||||
|
||||
override fun visitFunction(flags: Flags, name: String): KmFunctionVisitor? =
|
||||
writeFunction(c, flags, name) { t.addFunction(it) }
|
||||
@@ -461,9 +482,9 @@ open class PackageWriter : KmPackageVisitor() {
|
||||
}
|
||||
}
|
||||
|
||||
open class LambdaWriter : KmLambdaVisitor() {
|
||||
open class LambdaWriter(stringTable: StringTable) : KmLambdaVisitor() {
|
||||
var t: ProtoBuf.Function.Builder? = null
|
||||
val c = WriteContext()
|
||||
val c = WriteContext(stringTable)
|
||||
|
||||
override fun visitFunction(flags: Flags, name: String): KmFunctionVisitor? =
|
||||
writeFunction(c, flags, name) { t = it }
|
||||
|
||||
Reference in New Issue
Block a user