Introduce kotlinx-metadata-klib.

`kotlinx-metadata-klib` is an extension of `kotlinx-metadata` that can be used to read and write metadata that is stored inside KLIBs.
Note: current version is in its early days and in active development. Almost nothing is stable or properly tested.
This commit is contained in:
Sergey Bogolepov
2019-10-29 16:21:09 +07:00
parent d91453fb7a
commit 95399b3a41
25 changed files with 1378 additions and 15 deletions
@@ -48,6 +48,9 @@ internal class JvmMetadataExtensions : MetadataExtensions {
ext.visitEnd()
}
// ModuleFragment is not used by JVM backend.
override fun readModuleFragmentExtensions(v: KmModuleFragmentVisitor, proto: ProtoBuf.PackageFragment, c: ReadContext) {}
override fun readFunctionExtensions(v: KmFunctionVisitor, proto: ProtoBuf.Function, c: ReadContext) {
val ext = v.visitExtensions(JvmFunctionExtensionVisitor.TYPE) as? JvmFunctionExtensionVisitor ?: return
ext.visit(JvmProtoBufUtil.getJvmMethodSignature(proto, c.strings, c.types)?.wrapAsPublic())
@@ -144,6 +147,13 @@ internal class JvmMetadataExtensions : MetadataExtensions {
}
}
// PackageFragment is not used by JVM backend.
override fun writeModuleFragmentExtensions(
type: KmExtensionType,
proto: ProtoBuf.PackageFragment.Builder,
c: WriteContext
): KmModuleFragmentExtensionVisitor? = null
override fun writeFunctionExtensions(
type: KmExtensionType, proto: ProtoBuf.Function.Builder, c: WriteContext
): KmFunctionExtensionVisitor? {
@@ -262,6 +272,9 @@ internal class JvmMetadataExtensions : MetadataExtensions {
override fun createPackageExtension(): KmPackageExtension = JvmPackageExtension()
override fun createModuleFragmentExtensions(): KmModuleFragmentExtension =
error("metadata-jvm doesn't have any extensions for module fragment!")
override fun createFunctionExtension(): KmFunctionExtension = JvmFunctionExtension()
override fun createPropertyExtension(): KmPropertyExtension = JvmPropertyExtension()
@@ -0,0 +1,69 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
description = "Kotlin Library (KLIB) metadata manipulation library"
plugins {
kotlin("jvm")
id("jps-compatible")
}
group = "org.jetbrains.kotlinx"
val deployVersion = findProperty("kotlinxMetadataKlibDeployVersion") as String?
version = deployVersion ?: "0.0.1-SNAPSHOT"
jvmTarget = "1.6"
javaHome = rootProject.extra["JDK_16"] as String
sourceSets {
"main" { projectDefault() }
}
val shadows by configurations.creating {
isTransitive = false
}
configurations.getByName("compileOnly").extendsFrom(shadows)
configurations.getByName("testCompile").extendsFrom(shadows)
dependencies {
compile(kotlinStdlib())
shadows(project(":kotlinx-metadata"))
shadows(project(":core:metadata"))
shadows(project(":compiler:serialization"))
shadows(project(":kotlin-util-klib-metadata"))
shadows(project(":kotlin-util-klib"))
shadows(protobufLite())
}
if (deployVersion != null) {
publish()
}
noDefaultJar()
tasks.register<ShadowJar>("shadowJar") {
callGroovy("manifestAttributes", manifest, project)
manifest.attributes["Implementation-Version"] = version
from(mainSourceSet.output)
exclude("**/*.proto")
configurations = listOf(shadows)
relocate("org.jetbrains.kotlin", "kotlinx.metadata.internal")
val artifactRef = outputs.files.singleFile
runtimeJarArtifactBy(this, artifactRef)
addArtifact("runtime", this, artifactRef)
}
sourcesJar {
for (dependency in shadows.dependencies) {
if (dependency is ProjectDependency) {
val javaPlugin = dependency.dependencyProject.convention.findPlugin(JavaPluginConvention::class.java)
if (javaPlugin != null) {
from(javaPlugin.sourceSets["main"].allSource)
}
}
}
}
javadocJar()
@@ -0,0 +1 @@
kotlinx.metadata.klib.impl.KlibMetadataExtensions
@@ -0,0 +1,16 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package kotlinx.metadata.klib
import kotlinx.metadata.KmAnnotation
class KlibHeader(
val moduleName: String,
val file: List<KlibSourceFile>,
val packageFragmentName: List<String>,
val emptyPackage: List<String>,
val annotation: List<KmAnnotation>
)
@@ -0,0 +1,137 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package kotlinx.metadata.klib
import kotlinx.metadata.KmAnnotation
import kotlinx.metadata.KmModuleFragment
import kotlinx.metadata.impl.WriteContext
import kotlinx.metadata.impl.accept
import kotlinx.metadata.klib.impl.*
import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataStringTable
import org.jetbrains.kotlin.library.metadata.parseModuleHeader
import org.jetbrains.kotlin.library.metadata.parsePackageFragment
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.NameResolverImpl
/**
* Allows to modify the way fragments of the single package are read by [KlibModuleMetadata.read].
* For example, it may be convenient to join fragments into a single one.
*/
interface KlibModuleFragmentReadStrategy {
fun processModuleParts(parts: List<KmModuleFragment>): List<KmModuleFragment>
companion object {
val DEFAULT = object : KlibModuleFragmentReadStrategy {
override fun processModuleParts(parts: List<KmModuleFragment>) =
parts
}
}
}
/**
* Allows to modify the way module fragments are written by [KlibModuleMetadata.write].
* For example, splitting big fragments into several small one allows to improve IDE performance.
*/
interface KlibModuleFragmentWriteStrategy {
fun processPackageParts(parts: List<KmModuleFragment>): List<KmModuleFragment>
companion object {
val DEFAULT = object : KlibModuleFragmentWriteStrategy {
override fun processPackageParts(parts: List<KmModuleFragment>): List<KmModuleFragment> =
parts
}
}
}
/**
* Represents the parsed metadata of KLIB.
*/
class KlibModuleMetadata(
val name: String,
val fragments: List<KmModuleFragment>,
val annotations: List<KmAnnotation>
) {
/**
* Serialized representation of module metadata.
*/
class SerializedKlibMetadata(
val header: ByteArray,
val fragments: List<List<ByteArray>>,
val fragmentNames: List<String>
)
/**
* Specifies access to library's metadata.
*/
interface MetadataLibraryProvider {
val moduleHeaderData: ByteArray
fun packageMetadataParts(fqName: String): Set<String>
fun packageMetadata(fqName: String, partName: String): ByteArray
}
companion object {
/**
* Deserializes metadata from the given [library].
* @param readStrategy specifies the way module fragments of a single package are modified (e.g. merged) after deserialization.
*/
fun read(
library: MetadataLibraryProvider,
readStrategy: KlibModuleFragmentReadStrategy = KlibModuleFragmentReadStrategy.DEFAULT
): KlibModuleMetadata {
val moduleHeaderProto = parseModuleHeader(library.moduleHeaderData)
val nameResolver = NameResolverImpl(moduleHeaderProto.strings, moduleHeaderProto.qualifiedNames)
val moduleHeader = moduleHeaderProto.readHeader(nameResolver)
val fileIndex = SourceFileIndexReadExtension(moduleHeader.file)
val moduleFragments = moduleHeader.packageFragmentName.flatMap { packageFqName ->
library.packageMetadataParts(packageFqName).map { part ->
val packageFragment = parsePackageFragment(library.packageMetadata(packageFqName, part))
KmModuleFragment().apply { packageFragment.accept(this, nameResolver, listOf(fileIndex)) }
}.let(readStrategy::processModuleParts)
}
return KlibModuleMetadata(moduleHeader.moduleName, moduleFragments, moduleHeader.annotation)
}
}
/**
* Writes metadata back to serialized representation.
* @param writeStrategy specifies the way module fragments are modified (e.g. split) before serialization.
*/
fun write(
writeStrategy: KlibModuleFragmentWriteStrategy = KlibModuleFragmentWriteStrategy.DEFAULT
): SerializedKlibMetadata {
val reverseIndex = ReverseSourceFileIndexWriteExtension()
val c = WriteContext(KlibMetadataStringTable(), listOf(reverseIndex))
val groupedFragments = fragments
.groupBy(KmModuleFragment::fqNameOrFail)
.mapValues { writeStrategy.processPackageParts(it.value) }
val header = KlibHeader(
name,
reverseIndex.fileIndex,
groupedFragments.map { it.key },
groupedFragments.filter { it.value.all(KmModuleFragment::isEmpty) }.map { it.key },
annotations
)
val groupedProtos = groupedFragments.mapValues { (_, fragments) ->
fragments.map {
KlibModuleFragmentWriter(c.strings as KlibMetadataStringTable, c.contextExtensions).also(it::accept).write()
}
}
return SerializedKlibMetadata(
header.writeHeader(c).build().toByteArray(),
groupedProtos.map { it.value.map(ProtoBuf.PackageFragment::toByteArray) },
header.packageFragmentName
)
}
}
private fun KmModuleFragment.fqNameOrFail(): String =
fqName ?: error("Module fragment must have a fully-qualified name.")
private fun KmModuleFragment.isEmpty(): Boolean =
classes.isEmpty() && (pkg?.let { it.functions.isEmpty() && it.properties.isEmpty() && it.typeAliases.isEmpty() } ?: true)
@@ -0,0 +1,11 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package kotlinx.metadata.klib
class KlibSourceFile(
val name: String
)
@@ -0,0 +1,8 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package kotlinx.metadata.klib
class UniqId(val index: Long)
@@ -0,0 +1,224 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package kotlinx.metadata.klib.impl
import kotlinx.metadata.*
import kotlinx.metadata.impl.extensions.*
import kotlinx.metadata.klib.*
internal val KmFunction.klibExtensions: KlibFunctionExtension
get() = visitExtensions(KlibFunctionExtensionVisitor.TYPE) as KlibFunctionExtension
internal val KmClass.klibExtensions: KlibClassExtension
get() = visitExtensions(KlibClassExtensionVisitor.TYPE) as KlibClassExtension
internal val KmType.klibExtensions: KlibTypeExtension
get() = visitExtensions(KlibTypeExtensionVisitor.TYPE) as KlibTypeExtension
internal val KmProperty.klibExtensions: KlibPropertyExtension
get() = visitExtensions(KlibPropertyExtensionVisitor.TYPE) as KlibPropertyExtension
internal val KmConstructor.klibExtensions: KlibConstructorExtension
get() = visitExtensions(KlibConstructorExtensionVisitor.TYPE) as KlibConstructorExtension
internal val KmTypeParameter.klibExtensions: KlibTypeParameterExtension
get() = visitExtensions(KlibTypeParameterExtensionVisitor.TYPE) as KlibTypeParameterExtension
internal val KmPackage.klibExtensions: KlibPackageExtension
get() = visitExtensions(KlibPackageExtensionVisitor.TYPE) as KlibPackageExtension
internal val KmModuleFragment.klibExtensions: KlibModuleFragmentExtension
get() = visitExtensions(KlibModuleFragmentExtensionVisitor.TYPE) as KlibModuleFragmentExtension
internal class KlibFunctionExtension : KlibFunctionExtensionVisitor(), KmFunctionExtension {
val annotations: MutableList<KmAnnotation> = mutableListOf()
var uniqId: UniqId? = null
var file: KlibSourceFile? = null
override fun visitUniqId(uniqId: UniqId) {
this.uniqId = uniqId
}
override fun visitAnnotation(annotation: KmAnnotation) {
annotations += annotation
}
override fun visitFile(file: KlibSourceFile) {
this.file = file
}
override fun accept(visitor: KmFunctionExtensionVisitor) {
require(visitor is KlibFunctionExtensionVisitor)
annotations.forEach(visitor::visitAnnotation)
uniqId?.let(visitor::visitUniqId)
file?.let(visitor::visitFile)
}
}
internal class KlibClassExtension : KlibClassExtensionVisitor(), KmClassExtension {
val annotations: MutableList<KmAnnotation> = mutableListOf()
var uniqId: UniqId? = null
var file: KlibSourceFile? = null
override fun visitAnnotation(annotation: KmAnnotation) {
annotations += annotation
}
override fun visitUniqId(uniqId: UniqId) {
this.uniqId = uniqId
}
override fun visitFile(file: KlibSourceFile) {
this.file = file
}
override fun accept(visitor: KmClassExtensionVisitor) {
require(visitor is KlibClassExtensionVisitor)
annotations.forEach(visitor::visitAnnotation)
uniqId?.let(visitor::visitUniqId)
file?.let(visitor::visitFile)
}
}
internal class KlibTypeExtension : KlibTypeExtensionVisitor(), KmTypeExtension {
val annotations: MutableList<KmAnnotation> = mutableListOf()
override fun visitAnnotation(annotation: KmAnnotation) {
annotations += annotation
}
override fun accept(visitor: KmTypeExtensionVisitor) {
require(visitor is KlibTypeExtensionVisitor)
annotations.forEach(visitor::visitAnnotation)
}
}
internal class KlibPropertyExtension : KlibPropertyExtensionVisitor(), KmPropertyExtension {
val annotations: MutableList<KmAnnotation> = mutableListOf()
val getterAnnotations: MutableList<KmAnnotation> = mutableListOf()
val setterAnnotations: MutableList<KmAnnotation> = mutableListOf()
var uniqId: UniqId? = null
var file: Int? = null
var compileTimeValue: KmAnnotationArgument<*>? = null
override fun visitAnnotation(annotation: KmAnnotation) {
annotations += annotation
}
override fun visitGetterAnnotation(annotation: KmAnnotation) {
getterAnnotations += annotation
}
override fun visitSetterAnnotation(annotation: KmAnnotation) {
setterAnnotations += annotation
}
override fun visitFile(file: Int) {
this.file = file
}
override fun visitUniqId(uniqId: UniqId) {
this.uniqId = uniqId
}
override fun visitCompileTimeValue(value: KmAnnotationArgument<*>) {
this.compileTimeValue = value
}
override fun accept(visitor: KmPropertyExtensionVisitor) {
require(visitor is KlibPropertyExtensionVisitor)
annotations.forEach(visitor::visitAnnotation)
getterAnnotations.forEach(visitor::visitGetterAnnotation)
setterAnnotations.forEach(visitor::visitSetterAnnotation)
file?.let(visitor::visitFile)
uniqId?.let(visitor::visitUniqId)
compileTimeValue?.let(visitor::visitCompileTimeValue)
}
}
internal class KlibConstructorExtension : KlibConstructorExtensionVisitor(), KmConstructorExtension {
val annotations: MutableList<KmAnnotation> = mutableListOf()
var uniqId: UniqId? = null
override fun visitAnnotation(annotation: KmAnnotation) {
annotations += annotation
}
override fun visitUniqId(uniqId: UniqId) {
this.uniqId = uniqId
}
override fun accept(visitor: KmConstructorExtensionVisitor) {
require(visitor is KlibConstructorExtensionVisitor)
annotations.forEach(visitor::visitAnnotation)
uniqId?.let(visitor::visitUniqId)
}
}
internal class KlibTypeParameterExtension : KlibTypeParameterExtensionVisitor(), KmTypeParameterExtension {
val annotations: MutableList<KmAnnotation> = mutableListOf()
var uniqId: UniqId? = null
override fun visitAnnotation(annotation: KmAnnotation) {
annotations += annotation
}
override fun visitUniqId(uniqId: UniqId) {
this.uniqId = uniqId
}
override fun accept(visitor: KmTypeParameterExtensionVisitor) {
require(visitor is KlibTypeParameterExtensionVisitor)
annotations.forEach(visitor::visitAnnotation)
uniqId?.let(visitor::visitUniqId)
}
}
internal class KlibPackageExtension : KlibPackageExtensionVisitor(), KmPackageExtension {
var fqName: String? = null
override fun visitFqName(name: String) {
fqName = name
}
override fun accept(visitor: KmPackageExtensionVisitor) {
require(visitor is KlibPackageExtensionVisitor)
fqName?.let(visitor::visitFqName)
}
}
internal class KlibModuleFragmentExtension : KlibModuleFragmentExtensionVisitor(), KmModuleFragmentExtension {
val moduleFragmentFiles: MutableList<KlibSourceFile> = ArrayList()
var fqName: String? = null
val className: MutableList<ClassName> = ArrayList()
override fun visitFile(file: KlibSourceFile) {
moduleFragmentFiles += file
}
override fun visitFqName(fqName: String) {
this.fqName = fqName
}
override fun visitClassName(className: ClassName) {
this.className += className
}
override fun accept(visitor: KmModuleFragmentExtensionVisitor) {
require(visitor is KlibModuleFragmentExtensionVisitor)
moduleFragmentFiles.forEach(visitor::visitFile)
fqName?.let(visitor::visitFqName)
className.forEach(visitor::visitClassName)
}
}
@@ -0,0 +1,350 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package kotlinx.metadata.klib.impl
import kotlinx.metadata.*
import kotlinx.metadata.impl.*
import kotlinx.metadata.impl.extensions.*
import kotlinx.metadata.klib.*
import org.jetbrains.kotlin.library.metadata.KlibMetadataProtoBuf
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.NameResolverImpl
import org.jetbrains.kotlin.metadata.deserialization.getExtensionOrNull
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.serialization.StringTableImpl
internal class KlibMetadataExtensions : MetadataExtensions {
private fun ReadContext.getSourceFile(index: Int) =
contextExtensions.filterIsInstance<SourceFileIndexReadExtension>().first().getSourceFile(index)
private fun WriteContext.getIndexOf(file: KlibSourceFile) =
contextExtensions.filterIsInstance<ReverseSourceFileIndexWriteExtension>().first().getIndexOf(file)
override fun readClassExtensions(v: KmClassVisitor, proto: ProtoBuf.Class, c: ReadContext) {
val extension = v.visitExtensions(KlibClassExtensionVisitor.TYPE) as? KlibClassExtensionVisitor ?: return
proto.getExtension(KlibMetadataProtoBuf.classAnnotation).forEach { annotation ->
extension.visitAnnotation(annotation.readAnnotation(c.strings))
}
proto.getExtensionOrNull(KlibMetadataProtoBuf.classUniqId)?.let { descriptorUniqId ->
extension.visitUniqId(descriptorUniqId.readUniqId())
}
proto.getExtensionOrNull(KlibMetadataProtoBuf.classFile)?.let {
extension.visitFile(c.getSourceFile(it))
}
}
override fun readPackageExtensions(v: KmPackageVisitor, proto: ProtoBuf.Package, c: ReadContext) {
val extension = v.visitExtensions(KlibPackageExtensionVisitor.TYPE) as? KlibPackageExtensionVisitor ?: return
proto.getExtensionOrNull(KlibMetadataProtoBuf.packageFqName)?.let {
val fqName = (c.strings as NameResolverImpl).getPackageFqName(it)
extension.visitFqName(fqName)
}
}
override fun readModuleFragmentExtensions(v: KmModuleFragmentVisitor, proto: ProtoBuf.PackageFragment, c: ReadContext) {
val extension = v.visitExtensions(KlibModuleFragmentExtensionVisitor.TYPE) as? KlibModuleFragmentExtensionVisitor ?: return
proto.getExtension(KlibMetadataProtoBuf.packageFragmentFiles)
.map { c.getSourceFile(it) }
.forEach(extension::visitFile)
proto.getExtensionOrNull(KlibMetadataProtoBuf.fqName)?.let(extension::visitFqName)
proto.getExtension(KlibMetadataProtoBuf.className)
.map(c.strings::getQualifiedClassName)
.forEach(extension::visitClassName)
}
override fun readFunctionExtensions(v: KmFunctionVisitor, proto: ProtoBuf.Function, c: ReadContext) {
val extension = v.visitExtensions(KlibFunctionExtensionVisitor.TYPE) as? KlibFunctionExtensionVisitor ?: return
proto.getExtension(KlibMetadataProtoBuf.functionAnnotation).forEach { annotation ->
extension.visitAnnotation(annotation.readAnnotation(c.strings))
}
proto.getExtensionOrNull(KlibMetadataProtoBuf.functionUniqId)?.let { descriptorUniqId ->
extension.visitUniqId(descriptorUniqId.readUniqId())
}
proto.getExtensionOrNull(KlibMetadataProtoBuf.functionFile)?.let {
val file = c.getSourceFile(it)
extension.visitFile(file)
}
}
override fun readPropertyExtensions(v: KmPropertyVisitor, proto: ProtoBuf.Property, c: ReadContext) {
val extension = v.visitExtensions(KlibPropertyExtensionVisitor.TYPE) as? KlibPropertyExtensionVisitor ?: return
proto.getExtension(KlibMetadataProtoBuf.propertyAnnotation).forEach { annotation ->
extension.visitAnnotation(annotation.readAnnotation(c.strings))
}
proto.getExtension(KlibMetadataProtoBuf.propertyGetterAnnotation).forEach { annotation ->
extension.visitGetterAnnotation(annotation.readAnnotation(c.strings))
}
proto.getExtension(KlibMetadataProtoBuf.propertySetterAnnotation).forEach { annotation ->
extension.visitSetterAnnotation(annotation.readAnnotation(c.strings))
}
proto.getExtensionOrNull(KlibMetadataProtoBuf.propertyUniqId)?.let { descriptorUniqId ->
extension.visitUniqId(descriptorUniqId.readUniqId())
}
proto.getExtensionOrNull(KlibMetadataProtoBuf.propertyFile)?.let(extension::visitFile)
proto.getExtensionOrNull(KlibMetadataProtoBuf.compileTimeValue)?.let { value ->
value.readAnnotationArgument(c.strings)?.let { extension.visitCompileTimeValue(it) }
}
}
override fun readConstructorExtensions(v: KmConstructorVisitor, proto: ProtoBuf.Constructor, c: ReadContext) {
val extension = v.visitExtensions(KlibConstructorExtensionVisitor.TYPE) as? KlibConstructorExtensionVisitor ?: return
proto.getExtension(KlibMetadataProtoBuf.constructorAnnotation).forEach { annotation ->
extension.visitAnnotation(annotation.readAnnotation(c.strings))
}
proto.getExtensionOrNull(KlibMetadataProtoBuf.constructorUniqId)?.let { descriptorUniqId ->
extension.visitUniqId(descriptorUniqId.readUniqId())
}
}
override fun readTypeParameterExtensions(v: KmTypeParameterVisitor, proto: ProtoBuf.TypeParameter, c: ReadContext) {
val extension = v.visitExtensions(KlibTypeParameterExtensionVisitor.TYPE) as? KlibTypeParameterExtensionVisitor ?: return
proto.getExtension(KlibMetadataProtoBuf.typeParameterAnnotation).forEach { annotation ->
extension.visitAnnotation(annotation.readAnnotation(c.strings))
}
proto.getExtensionOrNull(KlibMetadataProtoBuf.typeParamUniqId)?.let { descriptorUniqId ->
extension.visitUniqId(descriptorUniqId.readUniqId())
}
}
override fun readTypeExtensions(v: KmTypeVisitor, proto: ProtoBuf.Type, c: ReadContext) {
val extension = v.visitExtensions(KlibTypeExtensionVisitor.TYPE) as? KlibTypeExtensionVisitor ?: return
proto.getExtension(KlibMetadataProtoBuf.typeAnnotation).forEach { annotation ->
extension.visitAnnotation(annotation.readAnnotation(c.strings))
}
}
override fun writeClassExtensions(type: KmExtensionType, proto: ProtoBuf.Class.Builder, c: WriteContext): KmClassExtensionVisitor? {
if (type != KlibClassExtensionVisitor.TYPE) return null
return object : KlibClassExtensionVisitor() {
override fun visitAnnotation(annotation: KmAnnotation) {
proto.addExtension(
KlibMetadataProtoBuf.classAnnotation,
annotation.writeAnnotation(c.strings).build()
)
}
override fun visitUniqId(uniqId: UniqId) {
proto.setExtension(
KlibMetadataProtoBuf.classUniqId,
uniqId.writeUniqId().build()
)
}
override fun visitFile(file: KlibSourceFile) {
val fileIdx = c.getIndexOf(file)
proto.setExtension(KlibMetadataProtoBuf.classFile, fileIdx)
}
}
}
override fun writePackageExtensions(
type: KmExtensionType,
proto: ProtoBuf.Package.Builder,
c: WriteContext
): KmPackageExtensionVisitor? {
if (type != KlibPackageExtensionVisitor.TYPE) return null
return object : KlibPackageExtensionVisitor() {
override fun visitFqName(name: String) {
val nameIdx = (c.strings as StringTableImpl).getPackageFqNameIndex(FqName(name))
proto.setExtension(KlibMetadataProtoBuf.packageFqName, nameIdx)
}
}
}
override fun writeModuleFragmentExtensions(
type: KmExtensionType,
proto: ProtoBuf.PackageFragment.Builder,
c: WriteContext
): KmModuleFragmentExtensionVisitor? {
if (type != KlibModuleFragmentExtensionVisitor.TYPE) return null
return object : KlibModuleFragmentExtensionVisitor() {
override fun visitFile(file: KlibSourceFile) {
val fileIdx = c.getIndexOf(file)
proto.addExtension(KlibMetadataProtoBuf.packageFragmentFiles, fileIdx)
}
override fun visitFqName(fqName: String) {
proto.setExtension(KlibMetadataProtoBuf.fqName, fqName)
}
override fun visitClassName(className: ClassName) {
val classNameIdx = (c.strings as StringTableImpl).getQualifiedClassNameIndex(ClassId.fromString(className))
proto.addExtension(KlibMetadataProtoBuf.className, classNameIdx)
}
}
}
override fun writeFunctionExtensions(
type: KmExtensionType,
proto: ProtoBuf.Function.Builder,
c: WriteContext
): KmFunctionExtensionVisitor? {
if (type != KlibFunctionExtensionVisitor.TYPE) return null
return object : KlibFunctionExtensionVisitor() {
override fun visitAnnotation(annotation: KmAnnotation) {
proto.addExtension(
KlibMetadataProtoBuf.functionAnnotation,
annotation.writeAnnotation(c.strings).build()
)
}
override fun visitUniqId(uniqId: UniqId) {
proto.setExtension(
KlibMetadataProtoBuf.functionUniqId,
uniqId.writeUniqId().build()
)
}
override fun visitFile(file: KlibSourceFile) {
val index = c.getIndexOf(file)
proto.setExtension(KlibMetadataProtoBuf.functionFile, index)
}
}
}
override fun writePropertyExtensions(
type: KmExtensionType,
proto: ProtoBuf.Property.Builder,
c: WriteContext
): KmPropertyExtensionVisitor? {
if (type != KlibPropertyExtensionVisitor.TYPE) return null
return object : KlibPropertyExtensionVisitor() {
override fun visitAnnotation(annotation: KmAnnotation) {
proto.addExtension(
KlibMetadataProtoBuf.propertyAnnotation,
annotation.writeAnnotation(c.strings).build()
)
}
override fun visitGetterAnnotation(annotation: KmAnnotation) {
proto.addExtension(
KlibMetadataProtoBuf.propertyGetterAnnotation,
annotation.writeAnnotation(c.strings).build()
)
}
override fun visitSetterAnnotation(annotation: KmAnnotation) {
proto.addExtension(
KlibMetadataProtoBuf.propertySetterAnnotation,
annotation.writeAnnotation(c.strings).build()
)
}
override fun visitUniqId(uniqId: UniqId) {
proto.setExtension(
KlibMetadataProtoBuf.propertyUniqId,
uniqId.writeUniqId().build()
)
}
override fun visitFile(file: Int) {
proto.setExtension(
KlibMetadataProtoBuf.propertyFile,
file
)
}
override fun visitCompileTimeValue(value: KmAnnotationArgument<*>) {
proto.setExtension(
KlibMetadataProtoBuf.compileTimeValue,
value.writeAnnotationArgument(c.strings).build()
)
}
}
}
override fun writeConstructorExtensions(
type: KmExtensionType,
proto: ProtoBuf.Constructor.Builder,
c: WriteContext
): KmConstructorExtensionVisitor? {
if (type != KlibConstructorExtensionVisitor.TYPE) return null
return object : KlibConstructorExtensionVisitor() {
override fun visitAnnotation(annotation: KmAnnotation) {
proto.addExtension(
KlibMetadataProtoBuf.constructorAnnotation,
annotation.writeAnnotation(c.strings).build()
)
}
override fun visitUniqId(uniqId: UniqId) {
proto.setExtension(
KlibMetadataProtoBuf.constructorUniqId,
uniqId.writeUniqId().build()
)
}
}
}
override fun writeTypeParameterExtensions(
type: KmExtensionType,
proto: ProtoBuf.TypeParameter.Builder,
c: WriteContext
): KmTypeParameterExtensionVisitor? {
if (type != KlibTypeParameterExtensionVisitor.TYPE) return null
return object : KlibTypeParameterExtensionVisitor() {
override fun visitAnnotation(annotation: KmAnnotation) {
proto.addExtension(
KlibMetadataProtoBuf.typeParameterAnnotation,
annotation.writeAnnotation(c.strings).build()
)
}
override fun visitUniqId(uniqId: UniqId) {
proto.setExtension(
KlibMetadataProtoBuf.typeParamUniqId,
uniqId.writeUniqId().build()
)
}
}
}
override fun writeTypeExtensions(type: KmExtensionType, proto: ProtoBuf.Type.Builder, c: WriteContext): KmTypeExtensionVisitor? {
if (type != KlibTypeExtensionVisitor.TYPE) return null
return object : KlibTypeExtensionVisitor() {
override fun visitAnnotation(annotation: KmAnnotation) {
proto.addExtension(
KlibMetadataProtoBuf.typeAnnotation,
annotation.writeAnnotation(c.strings).build()
)
}
}
}
override fun createClassExtension(): KmClassExtension =
KlibClassExtension()
override fun createPackageExtension(): KmPackageExtension =
KlibPackageExtension()
override fun createModuleFragmentExtensions(): KmModuleFragmentExtension =
KlibModuleFragmentExtension()
override fun createFunctionExtension(): KmFunctionExtension =
KlibFunctionExtension()
override fun createPropertyExtension(): KmPropertyExtension =
KlibPropertyExtension()
override fun createConstructorExtension(): KmConstructorExtension =
KlibConstructorExtension()
override fun createTypeParameterExtension(): KmTypeParameterExtension =
KlibTypeParameterExtension()
override fun createTypeExtension(): KmTypeExtension =
KlibTypeExtension()
}
@@ -0,0 +1,28 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package kotlinx.metadata.klib.impl
import kotlinx.metadata.impl.readAnnotation
import kotlinx.metadata.klib.KlibHeader
import kotlinx.metadata.klib.KlibSourceFile
import kotlinx.metadata.klib.UniqId
import org.jetbrains.kotlin.library.metadata.KlibMetadataProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.NameResolver
internal fun KlibMetadataProtoBuf.DescriptorUniqId.readUniqId(): UniqId =
UniqId(index)
internal fun KlibMetadataProtoBuf.Header.readHeader(strings: NameResolver): KlibHeader =
KlibHeader(
moduleName,
fileList.map(KlibMetadataProtoBuf.File::readFile),
packageFragmentNameList,
emptyPackageList,
annotationList.map { it.readAnnotation(strings) }
)
internal fun KlibMetadataProtoBuf.File.readFile(): KlibSourceFile =
KlibSourceFile(name)
@@ -0,0 +1,15 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package kotlinx.metadata.klib.impl
import kotlinx.metadata.impl.ReadContextExtension
import kotlinx.metadata.klib.KlibSourceFile
class SourceFileIndexReadExtension(
private val files: List<KlibSourceFile>
) : ReadContextExtension {
fun getSourceFile(index: Int): KlibSourceFile = files[index]
}
@@ -0,0 +1,36 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package kotlinx.metadata.klib.impl
import kotlinx.metadata.impl.WriteContext
import kotlinx.metadata.impl.writeAnnotation
import kotlinx.metadata.klib.KlibHeader
import kotlinx.metadata.klib.KlibSourceFile
import kotlinx.metadata.klib.UniqId
import org.jetbrains.kotlin.library.metadata.KlibMetadataProtoBuf
import org.jetbrains.kotlin.serialization.StringTableImpl
internal fun UniqId.writeUniqId(): KlibMetadataProtoBuf.DescriptorUniqId.Builder =
KlibMetadataProtoBuf.DescriptorUniqId.newBuilder().apply {
index = this@writeUniqId.index
}
internal fun KlibHeader.writeHeader(context: WriteContext): KlibMetadataProtoBuf.Header.Builder =
KlibMetadataProtoBuf.Header.newBuilder().also { proto ->
val (strings, qualifiedNames) = (context.strings as StringTableImpl).buildProto()
proto.moduleName = moduleName
proto.qualifiedNames = qualifiedNames
proto.strings = strings
proto.addAllPackageFragmentName(packageFragmentName)
proto.addAllFile(file.map { it.writeFile().build() })
proto.addAllAnnotation(annotation.map { it.writeAnnotation(context.strings).build() })
proto.addAllEmptyPackage(emptyPackage)
}
internal fun KlibSourceFile.writeFile(): KlibMetadataProtoBuf.File.Builder =
KlibMetadataProtoBuf.File.newBuilder().also { proto ->
proto.name = name
}
@@ -0,0 +1,45 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package kotlinx.metadata.klib.impl
import kotlinx.metadata.impl.*
import kotlinx.metadata.klib.KlibSourceFile
import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataStringTable
import org.jetbrains.kotlin.library.metadata.KlibMetadataProtoBuf
import org.jetbrains.kotlin.metadata.ProtoBuf
class ReverseSourceFileIndexWriteExtension : WriteContextExtension {
private val filesReverseIndex = mutableMapOf<KlibSourceFile, Int>()
val fileIndex: List<KlibSourceFile>
get() = filesReverseIndex
.map { (file, index) -> index to file }
.sortedBy { it.first }
.map { it.second }
fun getIndexOf(file: KlibSourceFile): Int = filesReverseIndex.getOrPut(file) {
filesReverseIndex.size
}
}
class KlibModuleFragmentWriter(
stringTable: KlibMetadataStringTable,
contextExtensions: List<WriteContextExtension> = emptyList()
) : ModuleFragmentWriter(stringTable, contextExtensions) {
fun write(): ProtoBuf.PackageFragment =
t.build()
override fun visitEnd() {
val isPackageEmpty = if (t.`package` == null) {
true
} else {
t.`package`.let { it.functionCount == 0 && it.propertyCount == 0 && it.typeAliasCount == 0 }
}
val isEmpty = t.class_Count == 0 && isPackageEmpty
t.setExtension(KlibMetadataProtoBuf.isEmpty, isEmpty)
}
}
@@ -0,0 +1,105 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package kotlinx.metadata.klib
import kotlinx.metadata.*
import kotlinx.metadata.klib.impl.klibExtensions
val KmFunction.annotations: MutableList<KmAnnotation>
get() = klibExtensions.annotations
var KmFunction.uniqId: UniqId?
get() = klibExtensions.uniqId
set(value) {
klibExtensions.uniqId = value
}
var KmFunction.file: KlibSourceFile?
get() = klibExtensions.file
set(value) {
klibExtensions.file = value
}
val KmClass.annotations: MutableList<KmAnnotation>
get() = klibExtensions.annotations
var KmClass.uniqId: UniqId?
get() = klibExtensions.uniqId
set(value) {
klibExtensions.uniqId = value
}
var KmClass.file: KlibSourceFile?
get() = klibExtensions.file
set(value) {
klibExtensions.file = value
}
val KmProperty.annotations: MutableList<KmAnnotation>
get() = klibExtensions.annotations
val KmProperty.setterAnnotations: MutableList<KmAnnotation>
get() = klibExtensions.setterAnnotations
val KmProperty.getterAnnotations: MutableList<KmAnnotation>
get() = klibExtensions.getterAnnotations
var KmProperty.uniqId: UniqId?
get() = klibExtensions.uniqId
set(value) {
klibExtensions.uniqId = value
}
var KmProperty.file: Int?
get() = klibExtensions.file
set(value) {
klibExtensions.file = value
}
var KmProperty.compileTimeValue: KmAnnotationArgument<*>?
get() = klibExtensions.compileTimeValue
set(value) {
klibExtensions.compileTimeValue = value
}
val KmType.annotations: MutableList<KmAnnotation>
get() = klibExtensions.annotations
val KmConstructor.annotations: MutableList<KmAnnotation>
get() = klibExtensions.annotations
var KmConstructor.uniqId: UniqId?
get() = klibExtensions.uniqId
set(value) {
klibExtensions.uniqId = value
}
var KmPackage.fqName: String?
get() = klibExtensions.fqName
set(value) {
klibExtensions.fqName = value
}
var KmModuleFragment.fqName: String?
get() = klibExtensions.fqName
set(value) {
klibExtensions.fqName = value
}
val KmModuleFragment.className: MutableList<ClassName>?
get() = klibExtensions.className
val KmModuleFragment.moduleFragmentFiles: MutableList<KlibSourceFile>?
get() = klibExtensions.moduleFragmentFiles
val KmTypeParameter.annotations: MutableList<KmAnnotation>
get() = klibExtensions.annotations
var KmTypeParameter.uniqId: UniqId?
get() = klibExtensions.uniqId
set(value) {
klibExtensions.uniqId = value
}
@@ -0,0 +1,130 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package kotlinx.metadata.klib
import kotlinx.metadata.*
abstract class KlibFunctionExtensionVisitor : KmFunctionExtensionVisitor {
abstract fun visitAnnotation(annotation: KmAnnotation)
abstract fun visitUniqId(uniqId: UniqId)
abstract fun visitFile(file: KlibSourceFile)
override val type: KmExtensionType
get() = TYPE
companion object {
val TYPE = KmExtensionType(KlibFunctionExtensionVisitor::class)
}
}
abstract class KlibClassExtensionVisitor : KmClassExtensionVisitor {
abstract fun visitAnnotation(annotation: KmAnnotation)
abstract fun visitUniqId(uniqId: UniqId)
abstract fun visitFile(file: KlibSourceFile)
override val type: KmExtensionType
get() = TYPE
companion object {
val TYPE = KmExtensionType(KlibClassExtensionVisitor::class)
}
}
abstract class KlibTypeExtensionVisitor : KmTypeExtensionVisitor {
abstract fun visitAnnotation(annotation: KmAnnotation)
override val type: KmExtensionType
get() = TYPE
companion object {
val TYPE = KmExtensionType(KlibTypeExtensionVisitor::class)
}
}
abstract class KlibPropertyExtensionVisitor : KmPropertyExtensionVisitor {
abstract fun visitAnnotation(annotation: KmAnnotation)
abstract fun visitGetterAnnotation(annotation: KmAnnotation)
abstract fun visitSetterAnnotation(annotation: KmAnnotation)
abstract fun visitFile(file: Int)
abstract fun visitUniqId(uniqId: UniqId)
abstract fun visitCompileTimeValue(value: KmAnnotationArgument<*>)
override val type: KmExtensionType
get() = TYPE
companion object {
val TYPE = KmExtensionType(KlibPropertyExtensionVisitor::class)
}
}
abstract class KlibConstructorExtensionVisitor : KmConstructorExtensionVisitor {
abstract fun visitAnnotation(annotation: KmAnnotation)
abstract fun visitUniqId(uniqId: UniqId)
override val type: KmExtensionType
get() = TYPE
companion object {
val TYPE = KmExtensionType(KlibConstructorExtensionVisitor::class)
}
}
abstract class KlibTypeParameterExtensionVisitor : KmTypeParameterExtensionVisitor {
abstract fun visitAnnotation(annotation: KmAnnotation)
abstract fun visitUniqId(uniqId: UniqId)
override val type: KmExtensionType
get() = TYPE
companion object {
val TYPE = KmExtensionType(KlibTypeParameterExtensionVisitor::class)
}
}
abstract class KlibPackageExtensionVisitor : KmPackageExtensionVisitor {
abstract fun visitFqName(name: String)
override val type: KmExtensionType
get() = TYPE
companion object {
val TYPE = KmExtensionType(KlibPackageExtensionVisitor::class)
}
}
abstract class KlibModuleFragmentExtensionVisitor : KmModuleFragmentExtensionVisitor {
abstract fun visitFile(file: KlibSourceFile)
abstract fun visitFqName(fqName: String)
abstract fun visitClassName(className: ClassName)
override val type: KmExtensionType
get() = TYPE
companion object {
val TYPE = KmExtensionType(KlibModuleFragmentExtensionVisitor::class)
}
}
@@ -64,6 +64,11 @@ interface KmClassExtensionVisitor : KmDeclarationContainerExtensionVisitor
*/
interface KmPackageExtensionVisitor : KmDeclarationContainerExtensionVisitor
/**
* A visitor to visit platform-specific extensions for a module fragment.
*/
interface KmModuleFragmentExtensionVisitor : KmExtensionVisitor
/**
* A visitor to visit platform-specific extensions for a function.
*/
@@ -16,6 +16,8 @@ interface MetadataExtensions {
fun readPackageExtensions(v: KmPackageVisitor, proto: ProtoBuf.Package, c: ReadContext)
fun readModuleFragmentExtensions(v: KmModuleFragmentVisitor, proto: ProtoBuf.PackageFragment, c: ReadContext)
fun readFunctionExtensions(v: KmFunctionVisitor, proto: ProtoBuf.Function, c: ReadContext)
fun readPropertyExtensions(v: KmPropertyVisitor, proto: ProtoBuf.Property, c: ReadContext)
@@ -30,6 +32,10 @@ interface MetadataExtensions {
fun writePackageExtensions(type: KmExtensionType, proto: ProtoBuf.Package.Builder, c: WriteContext): KmPackageExtensionVisitor?
fun writeModuleFragmentExtensions(
type: KmExtensionType, proto: ProtoBuf.PackageFragment.Builder, c: WriteContext
): KmModuleFragmentExtensionVisitor?
fun writeFunctionExtensions(type: KmExtensionType, proto: ProtoBuf.Function.Builder, c: WriteContext): KmFunctionExtensionVisitor?
fun writePropertyExtensions(type: KmExtensionType, proto: ProtoBuf.Property.Builder, c: WriteContext): KmPropertyExtensionVisitor?
@@ -48,6 +54,8 @@ interface MetadataExtensions {
fun createPackageExtension(): KmPackageExtension
fun createModuleFragmentExtensions(): KmModuleFragmentExtension
fun createFunctionExtension(): KmFunctionExtension
fun createPropertyExtension(): KmPropertyExtension
@@ -15,6 +15,8 @@ interface KmClassExtension : KmClassExtensionVisitor, KmExtension<KmClassExtensi
interface KmPackageExtension : KmPackageExtensionVisitor, KmExtension<KmPackageExtensionVisitor>
interface KmModuleFragmentExtension : KmModuleFragmentExtensionVisitor, KmExtension<KmModuleFragmentExtensionVisitor>
interface KmFunctionExtension : KmFunctionExtensionVisitor, KmExtension<KmFunctionExtensionVisitor>
interface KmPropertyExtension : KmPropertyExtensionVisitor, KmExtension<KmPropertyExtensionVisitor>
@@ -23,7 +23,7 @@ fun ProtoBuf.Annotation.readAnnotation(strings: NameResolver): KmAnnotation =
}.toMap()
)
private fun ProtoBuf.Annotation.Argument.Value.readAnnotationArgument(strings: NameResolver): KmAnnotationArgument<*>? {
fun ProtoBuf.Annotation.Argument.Value.readAnnotationArgument(strings: NameResolver): KmAnnotationArgument<*>? {
if (Flags.IS_UNSIGNED[flags]) {
return when (type) {
BYTE -> KmAnnotationArgument.UByteValue(intValue.toByte())
@@ -11,15 +11,23 @@ import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.*
import org.jetbrains.kotlin.metadata.deserialization.Flags as F
/**
* Allows to populate [BasicReadContext] with additional data
* that can be used when reading metadata in [MetadataExtensions].
*/
interface ReadContextExtension
class ReadContext(
val strings: NameResolver,
val types: TypeTable,
internal val versionRequirements: VersionRequirementTable,
private val parent: ReadContext? = null
private val parent: ReadContext? = null,
val contextExtensions: List<ReadContextExtension> = emptyList()
) {
internal val extensions = MetadataExtensions.INSTANCES
private val typeParameterNameToId = mutableMapOf<Int, Int>()
internal val extensions = MetadataExtensions.INSTANCES
operator fun get(index: Int): String =
strings.getString(index)
@@ -30,16 +38,24 @@ class ReadContext(
typeParameterNameToId[name] ?: parent?.getTypeParameterId(name)
fun withTypeParameters(typeParameters: List<ProtoBuf.TypeParameter>): ReadContext =
ReadContext(strings, types, versionRequirements, this).apply {
ReadContext(strings, types, versionRequirements, this, contextExtensions).apply {
for (typeParameter in typeParameters) {
typeParameterNameToId[typeParameter.name] = typeParameter.id
}
}
}
fun ProtoBuf.Class.accept(v: KmClassVisitor, strings: NameResolver) {
val c = ReadContext(strings, TypeTable(typeTable), VersionRequirementTable.create(versionRequirementTable))
.withTypeParameters(typeParameterList)
fun ProtoBuf.Class.accept(
v: KmClassVisitor,
strings: NameResolver,
contextExtensions: List<ReadContextExtension> = emptyList()
) {
val c = ReadContext(
strings,
TypeTable(typeTable),
VersionRequirementTable.create(versionRequirementTable),
contextExtensions = contextExtensions
).withTypeParameters(typeParameterList)
v.visit(flags, c.className(fqName))
@@ -87,8 +103,17 @@ fun ProtoBuf.Class.accept(v: KmClassVisitor, strings: NameResolver) {
v.visitEnd()
}
fun ProtoBuf.Package.accept(v: KmPackageVisitor, strings: NameResolver) {
val c = ReadContext(strings, TypeTable(typeTable), VersionRequirementTable.create(versionRequirementTable))
fun ProtoBuf.Package.accept(
v: KmPackageVisitor,
strings: NameResolver,
contextExtensions: List<ReadContextExtension> = emptyList()
) {
val c = ReadContext(
strings,
TypeTable(typeTable),
VersionRequirementTable.create(versionRequirementTable),
contextExtensions = contextExtensions
)
v.visitDeclarations(functionList, propertyList, typeAliasList, c)
@@ -99,6 +124,31 @@ fun ProtoBuf.Package.accept(v: KmPackageVisitor, strings: NameResolver) {
v.visitEnd()
}
fun ProtoBuf.PackageFragment.accept(
v: KmModuleFragmentVisitor,
strings: NameResolver,
contextExtensions: List<ReadContextExtension> = emptyList()
) {
val c = ReadContext(
strings,
TypeTable(ProtoBuf.TypeTable.newBuilder().build()),
VersionRequirementTable.EMPTY,
contextExtensions = contextExtensions
)
v.visitPackage()?.let { `package`.accept(it, strings, contextExtensions) }
class_List.forEach { clazz ->
v.visitClass()?.let { clazz.accept(it, strings, contextExtensions) }
}
for (extension in c.extensions) {
extension.readModuleFragmentExtensions(v, this, c)
}
v.visitEnd()
}
private fun KmDeclarationContainerVisitor.visitDeclarations(
functions: List<ProtoBuf.Function>,
properties: List<ProtoBuf.Property>,
@@ -24,7 +24,7 @@ fun KmAnnotation.writeAnnotation(strings: StringTable): ProtoBuf.Annotation.Buil
}
}
private fun KmAnnotationArgument<*>.writeAnnotationArgument(strings: StringTable): ProtoBuf.Annotation.Argument.Value.Builder =
fun KmAnnotationArgument<*>.writeAnnotationArgument(strings: StringTable): ProtoBuf.Annotation.Argument.Value.Builder =
ProtoBuf.Annotation.Argument.Value.newBuilder().apply {
when (this@writeAnnotationArgument) {
is KmAnnotationArgument.ByteValue -> {
@@ -6,13 +6,20 @@
package kotlinx.metadata.impl
import kotlinx.metadata.*
import kotlinx.metadata.impl.extensions.MetadataExtensions
import kotlinx.metadata.impl.extensions.applySingleExtension
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.VersionRequirement
import org.jetbrains.kotlin.metadata.serialization.MutableVersionRequirementTable
import org.jetbrains.kotlin.metadata.serialization.StringTable
class WriteContext(val strings: StringTable) {
/**
* Allows to populate [WriteContext] with additional data
* that can be used when writing metadata in [MetadataExtensions].
*/
interface WriteContextExtension
open class WriteContext(val strings: StringTable, val contextExtensions: List<WriteContextExtension> = emptyList()) {
val versionRequirements: MutableVersionRequirementTable = MutableVersionRequirementTable()
operator fun get(string: String): Int =
@@ -393,9 +400,9 @@ private fun writeEffectExpression(c: WriteContext, output: (ProtoBuf.Expression.
}
}
open class ClassWriter(stringTable: StringTable) : KmClassVisitor() {
open class ClassWriter(stringTable: StringTable, contextExtensions: List<WriteContextExtension> = emptyList()) : KmClassVisitor() {
protected val t = ProtoBuf.Class.newBuilder()!!
protected val c = WriteContext(stringTable)
protected val c: WriteContext = WriteContext(stringTable, contextExtensions)
override fun visit(flags: Flags, name: ClassName) {
if (flags != ProtoBuf.Class.getDefaultInstance().flags) {
@@ -455,9 +462,9 @@ open class ClassWriter(stringTable: StringTable) : KmClassVisitor() {
}
}
open class PackageWriter(stringTable: StringTable) : KmPackageVisitor() {
open class PackageWriter(stringTable: StringTable, contextExtensions: List<WriteContextExtension> = emptyList()) : KmPackageVisitor() {
protected val t = ProtoBuf.Package.newBuilder()!!
protected val c = WriteContext(stringTable)
protected val c: WriteContext = WriteContext(stringTable, contextExtensions)
override fun visitFunction(flags: Flags, name: String): KmFunctionVisitor? =
writeFunction(c, flags, name) { t.addFunction(it) }
@@ -480,6 +487,31 @@ open class PackageWriter(stringTable: StringTable) : KmPackageVisitor() {
}
}
open class ModuleFragmentWriter(stringTable: StringTable, contextExtensions: List<WriteContextExtension> = emptyList()) :
KmModuleFragmentVisitor() {
protected val t = ProtoBuf.PackageFragment.newBuilder()
protected val c: WriteContext = WriteContext(stringTable, contextExtensions)
override fun visitPackage(): KmPackageVisitor? = object : PackageWriter(c.strings, c.contextExtensions) {
override fun visitEnd() {
super.visitEnd()
this@ModuleFragmentWriter.t.setPackage(t)
}
}
override fun visitClass(): KmClassVisitor? = object : ClassWriter(c.strings, c.contextExtensions) {
override fun visitEnd() {
super.visitEnd()
this@ModuleFragmentWriter.t.addClass_(t)
}
}
override fun visitExtensions(type: KmExtensionType): KmModuleFragmentExtensionVisitor? =
applySingleExtension(type) {
writeModuleFragmentExtensions(type, t, c)
}
}
open class LambdaWriter(stringTable: StringTable) : KmLambdaVisitor() {
protected var t: ProtoBuf.Function.Builder? = null
protected val c = WriteContext(stringTable)
@@ -217,6 +217,46 @@ class KmPackage : KmPackageVisitor(), KmDeclarationContainer {
}
}
/**
* Represents a Kotlin module fragment. This is used to represent metadata of a part of a module on platforms other than JVM.
*/
class KmModuleFragment : KmModuleFragmentVisitor() {
/**
* Top-level functions, type aliases and properties in the module fragment.
*/
var pkg: KmPackage? = null
/**
* Classes in the module fragment.
*/
val classes: MutableList<KmClass> = ArrayList()
private val extensions: List<KmModuleFragmentExtension> =
MetadataExtensions.INSTANCES.map(MetadataExtensions::createModuleFragmentExtensions)
override fun visitPackage(): KmPackageVisitor? =
KmPackage().also { pkg = it }
override fun visitExtensions(type: KmExtensionType): KmModuleFragmentExtensionVisitor? =
extensions.singleOfType(type)
override fun visitClass(): KmClassVisitor? =
KmClass().addTo(classes)
/**
* Populates the given visitor with data in this module fragment.
*
* @param visitor the visitor which will visit data in the module fragment.
*/
fun accept(visitor: KmModuleFragmentVisitor) {
pkg?.let { visitor.visitPackage()?.let(it::accept) }
classes.forEach { visitor.visitClass()?.let(it::accept) }
extensions.forEach { visitor.visitExtensions(it.type)?.let(it::accept) }
visitor.visitEnd()
}
}
/**
* Represents a synthetic class generated for a Kotlin lambda.
*/
@@ -179,6 +179,42 @@ abstract class KmPackageVisitor @JvmOverloads constructor(delegate: KmPackageVis
}
}
/**
* A visitor to visit module fragments. The module fragment can have no more than one package, and any number of classes,
* and must have at least one declaration.
*
* When using this class, [visitEnd] must be called exactly once and after calls to all other visit* methods.
*/
abstract class KmModuleFragmentVisitor @JvmOverloads constructor(private val delegate: KmModuleFragmentVisitor? = null) {
/**
* Visits a package within the module fragment.
*/
open fun visitPackage(): KmPackageVisitor? =
delegate?.visitPackage()
/**
* Visits a class within the module fragment.
*/
open fun visitClass(): KmClassVisitor? =
delegate?.visitClass()
/**
* Visits the extensions of the given type on the module fragment.
*
* @param type the type of extension visitor to be returned.
*/
open fun visitExtensions(type: KmExtensionType): KmModuleFragmentExtensionVisitor? =
delegate?.visitExtensions(type)
/**
* Visits the end of the module fragment.
*/
open fun visitEnd() {
delegate?.visitEnd()
}
}
/**
* A visitor to visit the metadata of a synthetic class generated for a Kotlin lambda.
*
+2
View File
@@ -159,6 +159,7 @@ include ":kotlin-build-common",
":kotlin-source-map-loader",
":kotlinx-metadata",
":kotlinx-metadata-jvm",
":kotlinx-metadata-klib",
":prepare:build.version",
":kotlin-build-common",
":prepare:formatter",
@@ -324,6 +325,7 @@ project(':kotlin-reflect').projectDir = "$rootDir/libraries/reflect" as File
project(':kotlin-reflect-api').projectDir = "$rootDir/libraries/reflect/api" as File
project(':kotlinx-metadata').projectDir = "$rootDir/libraries/kotlinx-metadata" as File
project(':kotlinx-metadata-jvm').projectDir = "$rootDir/libraries/kotlinx-metadata/jvm" as File
project(':kotlinx-metadata-klib').projectDir = "$rootDir/libraries/kotlinx-metadata/klib" as File
project(':kotlin-compiler').projectDir = "$rootDir/prepare/compiler" as File
project(':kotlin-compiler-embeddable').projectDir = "$rootDir/prepare/compiler-embeddable" as File
project(':kotlin-compiler-client-embeddable').projectDir = "$rootDir/prepare/compiler-client-embeddable" as File