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
@@ -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)
}
}