Add kotlinx-metadata library for handling Kotlin metadata

#KT-23198
This commit is contained in:
Alexander Udalov
2018-03-05 19:05:01 +01:00
parent 8ab49a70e9
commit e4062f6447
21 changed files with 2715 additions and 2 deletions
@@ -238,8 +238,8 @@ public class Flags {
return new BooleanFlagField(offset);
}
protected final int offset;
protected final int bitWidth;
public final int offset;
public final int bitWidth;
private FlagField(int offset, int bitWidth) {
this.offset = offset;
@@ -0,0 +1,16 @@
description = "Kotlin metadata manipulation library"
plugins {
kotlin("jvm")
}
sourceSets {
"main" { projectDefault() }
"test" { }
}
dependencies {
compile(project(":kotlin-stdlib"))
compileOnly(project(":core:metadata"))
compileOnly(protobufLite())
}
@@ -0,0 +1,63 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
description = "Kotlin JVM metadata manipulation library"
plugins {
kotlin("jvm")
}
sourceSets {
"main" { projectDefault() }
"test" { projectDefault() }
}
val shadows by configurations.creating {
isTransitive = false
}
configurations.getByName("compileOnly").extendsFrom(shadows)
configurations.getByName("testCompile").extendsFrom(shadows)
dependencies {
compile(project(":kotlin-stdlib"))
shadows(project(":kotlinx-metadata"))
shadows(project(":core:metadata"))
shadows(project(":core:metadata.jvm"))
shadows(protobufLite())
testCompile(commonDep("junit:junit"))
}
noDefaultJar()
val shadowJar = task<ShadowJar>("shadowJar") {
callGroovy("manifestAttributes", manifest, project)
manifest.attributes["Implementation-Version"] = version
from(the<JavaPluginConvention>().sourceSets["main"].output)
exclude("**/*.proto")
configurations = listOf(shadows)
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()
// Change this version before publishing
version = "0.1-SNAPSHOT"
// publish()
projectTest {
workingDir = rootDir
}
@@ -0,0 +1 @@
kotlinx.metadata.jvm.impl.JvmMetadataExtensions
@@ -0,0 +1,155 @@
/*
* Copyright 2000-2018 JetBrains s.r.o. 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.jvm
/**
* A mirror to the [Metadata] annotation on a JVM class file, containing the metadata of Kotlin declarations declared in the class file.
* Properties of this class correspond to the properties of [Metadata], but the names are not shortened because there's no restriction
* on the bytecode size here.
*
* Note that [Metadata] is not yet public (see https://youtrack.jetbrains.com/issue/KT-23602). In order to create an instance of
* [KotlinClassHeader] from the [Metadata] annotation instance obtained reflectively, one could use Java code to workaround
* the internal visibility error.
*
* @param kind see [kind]
* @param metadataVersion see [metadataVersion]
* @param bytecodeVersion see [bytecodeVersion]
* @param data1 see [data1]
* @param data2 see [data2]
* @param extraString see [extraString]
* @param packageName see [packageName]
* @param extraInt see [extraInt]
*/
class KotlinClassHeader(
kind: Int?,
metadataVersion: IntArray?,
bytecodeVersion: IntArray?,
data1: Array<String>?,
data2: Array<String>?,
extraString: String?,
packageName: String?,
extraInt: Int?
) {
/**
* A kind of the metadata this header encodes.
*
* @see Metadata.k
* @see CLASS_KIND
* @see FILE_FACADE_KIND
* @see SYNTHETIC_CLASS_KIND
* @see MULTI_FILE_CLASS_FACADE_KIND
* @see MULTI_FILE_CLASS_PART_KIND
*/
val kind: Int = kind ?: 1
/**
* The version of the metadata provided in other properties of this header.
*
* @see Metadata.mv
* @see COMPATIBLE_METADATA_VERSION
*/
val metadataVersion: IntArray = metadataVersion ?: intArrayOf()
/**
* The version of the bytecode interface (naming conventions, signatures) of the corresponding class file.
*
* @see Metadata.bv
* @see COMPATIBLE_BYTECODE_VERSION
*/
val bytecodeVersion: IntArray = bytecodeVersion ?: intArrayOf()
/**
* The first array of strings used to encode the metadata.
*
* @see Metadata.d1
*/
val data1: Array<String> = data1 ?: emptyArray()
/**
* The second array of strings used to encode the metadata.
*
* @see Metadata.d2
*/
val data2: Array<String> = data2 ?: emptyArray()
/**
* An extra string field for the metadata.
*
* @see Metadata.xs
*/
val extraString: String = extraString ?: ""
/**
* Fully qualified name of the Kotlin package of the corresponding class, in case [JvmPackageName] was used.
*
* @see Metadata.pn
*/
val packageName: String = packageName ?: ""
/**
* An extra int field for the metadata.
*
* @see Metadata.xi
*/
val extraInt: Int = extraInt ?: 0
companion object {
/**
* A class file kind signifying that the corresponding class file contains a declaration of a Kotlin class.
*
* @see kind
*/
const val CLASS_KIND = 1
/**
* A class file kind signifying that the corresponding class file is a compiled Kotlin file facade.
*
* @see kind
*/
const val FILE_FACADE_KIND = 2
/**
* A class file kind signifying that the corresponding class file is synthetic, e.g. it's a class for lambda, `$DefaultImpls` class
* for interface method implementations, `$WhenMappings` class for optimized `when` over enums, etc.
*
* @see kind
*/
const val SYNTHETIC_CLASS_KIND = 3
/**
* A class file kind signifying that the corresponding class file is a compiled multi-file class facade.
*
* @see kind
* @see JvmMultifileClass
*/
const val MULTI_FILE_CLASS_FACADE_KIND = 4
/**
* A class file kind signifying that the corresponding class file is a compiled multi-file class part, i.e. an internal class
* with method bodies and their metadata, accessed only from the corresponding facade.
*
* @see kind
* @see JvmMultifileClass
*/
const val MULTI_FILE_CLASS_PART_KIND = 5
/**
* The latest metadata version supported by this version of the library.
*
* @see metadataVersion
*/
@JvmField
val COMPATIBLE_METADATA_VERSION = intArrayOf(1, 1, 10)
/**
* The latest bytecode version supported by this version of the library.
*
* @see bytecodeVersion
*/
@JvmField
val COMPATIBLE_BYTECODE_VERSION = intArrayOf(1, 0, 2)
}
}
@@ -0,0 +1,180 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. 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.jvm
import kotlinx.metadata.InconsistentKotlinMetadataException
import kotlinx.metadata.KmClassVisitor
import kotlinx.metadata.KmLambdaVisitor
import kotlinx.metadata.KmPackageVisitor
import kotlinx.metadata.impl.accept
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
import kotlin.LazyThreadSafetyMode.PUBLICATION
/**
* Represents the parsed metadata of a Kotlin JVM class file.
*
* To create an instance of [KotlinClassMetadata], first obtain a [KotlinClassHeader] instance by loading the contents
* of the [Metadata] annotation on a class file, and then call [KotlinClassMetadata.read].
*/
sealed class KotlinClassMetadata(val header: KotlinClassHeader) {
/**
* Represents metadata of a class file containing a declaration of a Kotlin class.
*/
class Class internal constructor(header: KotlinClassHeader) : KotlinClassMetadata(header) {
private val classData by lazy(PUBLICATION) {
val data1 = (header.data1.takeIf(Array<*>::isNotEmpty)
?: throw InconsistentKotlinMetadataException("data1 must not be empty"))
JvmProtoBufUtil.readClassDataFrom(data1, header.data2)
}
/**
* Makes the given visitor visit metadata of this class.
*
* @param v the visitor that must visit this class
*/
fun accept(v: KmClassVisitor) {
val (strings, proto) = classData
proto.accept(v, strings)
}
}
/**
* Represents metadata of a class file containing a compiled Kotlin file facade.
*/
class FileFacade internal constructor(header: KotlinClassHeader) : KotlinClassMetadata(header) {
private val packageData by lazy(PUBLICATION) {
val data1 = (header.data1.takeIf(Array<*>::isNotEmpty)
?: throw InconsistentKotlinMetadataException("data1 must not be empty"))
JvmProtoBufUtil.readPackageDataFrom(data1, header.data2)
}
/**
* Makes the given visitor visit metadata of this file facade.
*
* @param v the visitor that must visit this file facade
*/
fun accept(v: KmPackageVisitor) {
val (strings, proto) = packageData
proto.accept(v, strings)
}
}
/**
* Represents metadata of a class file containing a synthetic class, e.g. a class for lambda, `$DefaultImpls` class for interface
* method implementations, `$WhenMappings` class for optimized `when` over enums, etc.
*/
class SyntheticClass internal constructor(header: KotlinClassHeader) : KotlinClassMetadata(header) {
private val functionData by lazy(PUBLICATION) {
header.data1.takeIf(Array<*>::isNotEmpty)?.let { data1 ->
JvmProtoBufUtil.readFunctionDataFrom(data1, header.data2)
}
}
/**
* Returns `true` if this synthetic class is a class file compiled for a Kotlin lambda.
*/
val isLambda: Boolean
get() = header.data1.isNotEmpty()
/**
* Makes the given visitor visit metadata of this file facade, if this synthetic class represents a Kotlin lambda
* (`isLambda` == true).
*
* Throws [IllegalStateException] if this synthetic class does not represent a Kotlin lambda.
*
* @param v the visitor that must visit this lambda
*/
fun accept(v: KmLambdaVisitor) {
if (!isLambda) throw IllegalStateException(
"accept(KmLambdaVisitor) is only possible for synthetic classes which are lambdas (isLambda = true)"
)
val (strings, proto) = functionData!!
proto.accept(v, strings)
}
}
/**
* Represents metadata of a class file containing a compiled multi-file class facade.
*
* @see JvmMultifileClass
*/
class MultiFileClassFacade internal constructor(header: KotlinClassHeader) : KotlinClassMetadata(header) {
/**
* JVM internal names of the part classes which this multi-file class combines.
*/
val partClassNames: List<String> = header.data1.asList()
}
/**
* Represents metadata of a class file containing a compiled multi-file class part, i.e. an internal class with method bodies
* and their metadata, accessed only from the corresponding facade.
*
* @see JvmMultifileClass
*/
class MultiFileClassPart internal constructor(header: KotlinClassHeader) : KotlinClassMetadata(header) {
private val packageData by lazy(PUBLICATION) {
val data1 = (header.data1.takeIf(Array<*>::isNotEmpty)
?: throw InconsistentKotlinMetadataException("data1 must not be empty"))
JvmProtoBufUtil.readPackageDataFrom(data1, header.data2)
}
/**
* JVM internal name of the corresponding multi-file class facade.
*/
val facadeClassName: String
get() = header.extraString
/**
* Makes the given visitor visit metadata of this multi-file class part.
*
* @param v the visitor that must visit this multi-file class part
*/
fun accept(v: KmPackageVisitor) {
val (strings, proto) = packageData
proto.accept(v, strings)
}
}
/**
* Represents metadata of an unknown class file. This class is used if an old version of this library is used against a new kind
* of class files generated by the Kotlin compiler, unsupported by this library.
*/
class Unknown internal constructor(header: KotlinClassHeader) : KotlinClassMetadata(header)
companion object {
/**
* Reads and parses the given header of a Kotlin JVM class file and returns the correct type of [KotlinClassMetadata] encoded by
* this header, or `null` if this header encodes an unsupported kind of Kotlin classes or has an unsupported metadata version.
*
* Throws [InconsistentKotlinMetadataException] if the metadata has inconsistencies which signal that it may have been
* modified by a separate tool.
*
* @param header the header of a Kotlin JVM class file to be parsed
*/
@JvmStatic
fun read(header: KotlinClassHeader): KotlinClassMetadata? {
// We only support metadata of version 1.1.* (this is Kotlin from 1.0 until today)
val version = header.metadataVersion
if (version.getOrNull(0) != 1 || version.getOrNull(1) != 1) return null
return try {
when (header.kind) {
KotlinClassHeader.CLASS_KIND -> KotlinClassMetadata.Class(header)
KotlinClassHeader.FILE_FACADE_KIND -> KotlinClassMetadata.FileFacade(header)
KotlinClassHeader.SYNTHETIC_CLASS_KIND -> KotlinClassMetadata.SyntheticClass(header)
KotlinClassHeader.MULTI_FILE_CLASS_FACADE_KIND -> KotlinClassMetadata.MultiFileClassFacade(header)
KotlinClassHeader.MULTI_FILE_CLASS_PART_KIND -> KotlinClassMetadata.MultiFileClassPart(header)
else -> KotlinClassMetadata.Unknown(header)
}
} catch (e: InconsistentKotlinMetadataException) {
throw e
} catch (e: Throwable) {
throw InconsistentKotlinMetadataException("Exception occurred when reading Kotlin metadata", e)
}
}
}
}
@@ -0,0 +1,68 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. 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.jvm.impl
import kotlinx.metadata.*
import kotlinx.metadata.impl.extensions.MetadataExtensions
import kotlinx.metadata.impl.readAnnotation
import kotlinx.metadata.jvm.*
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.NameResolver
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
internal class JvmMetadataExtensions : MetadataExtensions {
override fun readFunctionExtensions(v: KmFunctionVisitor, proto: ProtoBuf.Function, strings: NameResolver, types: TypeTable) {
val ext = v.visitExtensions(JvmFunctionExtensionVisitor.TYPE) as? JvmFunctionExtensionVisitor ?: return
ext.visit(JvmProtoBufUtil.getJvmMethodSignature(proto, strings, types))
}
override fun readPropertyExtensions(v: KmPropertyVisitor, proto: ProtoBuf.Property, strings: NameResolver, types: TypeTable) {
val ext = v.visitExtensions(JvmPropertyExtensionVisitor.TYPE) as? JvmPropertyExtensionVisitor ?: return
val fieldSignature = JvmProtoBufUtil.getJvmFieldSignature(proto, strings, types)
val propertySignature = proto.getExtensionOrNull(JvmProtoBuf.propertySignature)
val getterSignature =
if (propertySignature != null && propertySignature.hasGetter()) propertySignature.getter else null
val setterSignature =
if (propertySignature != null && propertySignature.hasSetter()) propertySignature.setter else null
ext.visit(
fieldSignature?.name,
fieldSignature?.desc,
getterSignature?.run { strings.getString(name) + strings.getString(desc) },
setterSignature?.run { strings.getString(name) + strings.getString(desc) }
)
val syntheticMethod =
if (propertySignature != null && propertySignature.hasSyntheticMethod()) propertySignature.syntheticMethod else null
ext.visitSyntheticMethodForAnnotations(syntheticMethod?.run { strings.getString(name) + strings.getString(desc) })
ext.visitEnd()
}
override fun readConstructorExtensions(v: KmConstructorVisitor, proto: ProtoBuf.Constructor, strings: NameResolver, types: TypeTable) {
val ext = v.visitExtensions(JvmConstructorExtensionVisitor.TYPE) as? JvmConstructorExtensionVisitor ?: return
ext.visit(JvmProtoBufUtil.getJvmConstructorSignature(proto, strings, types))
}
override fun readTypeParameterExtensions(v: KmTypeParameterVisitor, proto: ProtoBuf.TypeParameter, strings: NameResolver) {
val ext = v.visitExtensions(JvmTypeParameterExtensionVisitor.TYPE) as? JvmTypeParameterExtensionVisitor ?: return
for (annotation in proto.getExtension(JvmProtoBuf.typeParameterAnnotation)) {
ext.visitAnnotation(annotation.readAnnotation(strings))
}
ext.visitEnd()
}
override fun readTypeExtensions(v: KmTypeVisitor, proto: ProtoBuf.Type, strings: NameResolver) {
val ext = v.visitExtensions(JvmTypeExtensionVisitor.TYPE) as? JvmTypeExtensionVisitor ?: return
ext.visit(proto.getExtension(JvmProtoBuf.isRaw))
for (annotation in proto.getExtension(JvmProtoBuf.typeAnnotation)) {
ext.visitAnnotation(annotation.readAnnotation(strings))
}
ext.visitEnd()
}
}
@@ -0,0 +1,193 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. 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.jvm
import kotlinx.metadata.*
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
/**
* A visitor to visit JVM extensions for a function.
*/
open class JvmFunctionExtensionVisitor @JvmOverloads constructor(
private val delegate: JvmFunctionExtensionVisitor? = null
) : KmFunctionExtensionVisitor {
/**
* Visits the JVM signature of the function, in the JVM-based format: `"equals(Ljava/lang/Object;)Z"`,
* or null if the JVM signature of this function is unknown.
*
* @param desc the signature of the function
*/
open fun visit(desc: String?) {
delegate?.visit(desc)
}
companion object {
/**
* The type of this extension visitor.
*
* @see KmExtensionType
*/
@JvmField
val TYPE: KmExtensionType = KmExtensionType(JvmFunctionExtensionVisitor::class)
}
}
/**
* A visitor to visit JVM extensions for a property.
*/
open class JvmPropertyExtensionVisitor @JvmOverloads constructor(
private val delegate: JvmPropertyExtensionVisitor? = null
) : KmPropertyExtensionVisitor {
/**
* Visits JVM signatures of field and accessors generated for the property.
*
* @param fieldName the name of the field, or `null` if this property has no field
* @param fieldTypeDesc the type of the field in the JVM-based format (`"Ljava/lang/Object;"`), or `null` if this property has no field
* @param getterDesc the signature of the property getter in the JVM-based format: `"getX()Ljava/lang/Object;"`,
* or `null` if this property has no getter or its signature is unknown
* @param setterDesc the signature of the property setter in the JVM-based format: `"setX(Ljava/lang/Object;)V"`,
* or `null` if this property has no setter or its signature is unknown
*/
open fun visit(fieldName: String?, fieldTypeDesc: String?, getterDesc: String?, setterDesc: String?) {
delegate?.visit(fieldName, fieldTypeDesc, getterDesc, setterDesc)
}
/**
* Visits the JVM signature of a synthetic method which is generated to store annotations on a property in the bytecode,
* in the JVM-based format: `"getX$annotations()V"`
*
* @param desc the signature of the synthetic method
*/
open fun visitSyntheticMethodForAnnotations(desc: String?) {
delegate?.visitSyntheticMethodForAnnotations(desc)
}
/**
* Visits the end of JVM extensions for the property.
*/
open fun visitEnd() {
delegate?.visitEnd()
}
companion object {
/**
* The type of this extension visitor.
*
* @see KmExtensionType
*/
@JvmField
val TYPE: KmExtensionType = KmExtensionType(JvmPropertyExtensionVisitor::class)
}
}
/**
* A visitor to visit JVM extensions for a constructor.
*/
open class JvmConstructorExtensionVisitor @JvmOverloads constructor(
private val delegate: JvmConstructorExtensionVisitor? = null
) : KmConstructorExtensionVisitor {
/**
* Visits the JVM signature of the constructor, in the JVM-based format: `"<init>(Ljava/lang/Object;)V"`,
* or null if the JVM signature of this constructor is unknown.
*
* @param desc the signature of the constructor
*/
open fun visit(desc: String?) {
delegate?.visit(desc)
}
companion object {
/**
* The type of this extension visitor.
*
* @see KmExtensionType
*/
@JvmField
val TYPE: KmExtensionType = KmExtensionType(JvmConstructorExtensionVisitor::class)
}
}
/**
* A visitor to visit JVM extensions for a type parameter.
*/
open class JvmTypeParameterExtensionVisitor @JvmOverloads constructor(
private val delegate: JvmTypeParameterExtensionVisitor? = null
) : KmTypeParameterExtensionVisitor {
/**
* Visits an annotation on the type parameter.
*
* @param annotation the annotation on the type parameter
*/
open fun visitAnnotation(annotation: KmAnnotation) {
delegate?.visitAnnotation(annotation)
}
/**
* Visits the end of JVM extensions for the type parameter.
*/
open fun visitEnd() {
delegate?.visitEnd()
}
companion object {
/**
* The type of this extension visitor.
*
* @see KmExtensionType
*/
@JvmField
val TYPE: KmExtensionType = KmExtensionType(JvmTypeParameterExtensionVisitor::class)
}
}
/**
* A visitor to visit JVM extensions for a type.
*/
open class JvmTypeExtensionVisitor @JvmOverloads constructor(
private val delegate: JvmTypeExtensionVisitor? = null
) : KmTypeExtensionVisitor {
/**
* Visits the JVM-specific flags of a type.
*
* @param isRaw whether the type is seen as a raw type in Java
*/
open fun visit(isRaw: Boolean) {
delegate?.visit(isRaw)
}
/**
* Visits an annotation on the type.
*
* @param annotation the annotation on the type
*/
open fun visitAnnotation(annotation: KmAnnotation) {
delegate?.visitAnnotation(annotation)
}
/**
* Visits the end of JVM extensions for the type parameter.
*/
open fun visitEnd() {
delegate?.visitEnd()
}
companion object {
/**
* The type of this extension visitor.
*
* @see KmExtensionType
*/
@JvmField
val TYPE: KmExtensionType = KmExtensionType(JvmTypeExtensionVisitor::class)
/**
* The type flexibility id, signifying that the visited type is a JVM platform type.
*
* @see KmTypeVisitor.visitFlexibleTypeUpperBound
*/
const val PLATFORM_TYPE_ID = JvmProtoBufUtil.PLATFORM_TYPE_ID
}
}
@@ -0,0 +1,18 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. 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.jvm
import kotlinx.metadata.ClassName
import kotlinx.metadata.isLocal
/**
* JVM internal name of the class, where package names are separated by '/', and class names are separated by '$',
* for example: `"org/foo/bar/Baz$Nested"`
*/
val ClassName.jvmInternalName: String
get() =
if (this.isLocal) substring(1)
else replace('/', '$')
@@ -0,0 +1,58 @@
/*
* Copyright 2000-2018 JetBrains s.r.o. 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.test
import kotlinx.metadata.*
import kotlinx.metadata.jvm.JvmFunctionExtensionVisitor
import kotlinx.metadata.jvm.KotlinClassHeader
import kotlinx.metadata.jvm.KotlinClassMetadata
import org.junit.Assert.assertEquals
import org.junit.Test
class MetadataSmokeTest {
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
private fun Class<*>.readMetadata(): KotlinClassHeader {
return getAnnotation(Metadata::class.java).run {
KotlinClassHeader(k, mv, bv, d1, d2, xs, pn, xi)
}
}
@Test
fun listInlineFunctions() {
@Suppress("unused")
class L {
val x: Int inline get() = 42
inline fun foo(f: () -> String) = f()
fun bar() {}
}
val inlineFunctions = mutableListOf<String>()
val klass = KotlinClassMetadata.read(L::class.java.readMetadata()) as KotlinClassMetadata.Class
klass.accept(object : KmClassVisitor() {
override fun visitFunction(flags: Int, name: String): KmFunctionVisitor? {
return object : KmFunctionVisitor() {
override fun visitExtensions(type: KmExtensionType): KmFunctionExtensionVisitor? {
if (type != JvmFunctionExtensionVisitor.TYPE) return null
return object : JvmFunctionExtensionVisitor() {
override fun visit(desc: String?) {
if (Flags.Function.IS_INLINE(flags) && desc != null) {
inlineFunctions += desc
}
}
}
}
}
}
})
assertEquals(
listOf("foo(Lkotlin/jvm/functions/Function0;)Ljava/lang/String;"),
inlineFunctions
)
}
}
@@ -0,0 +1,21 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. 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
/**
* A fully qualified name of a classifier from the Kotlin's point of view. May differ from the JVM name of the class
* which is the runtime representation of this Kotlin classifier (for example, Kotlin class "kotlin/Int" -> JVM class "java/lang/Integer")
*
* Package names in this name are separated by '/', and class names are separated by '.', for example: `"org/foo/bar/Baz.Nested"`.
*
* If this name starts with '.', it represents a local class or an anonymous object. This is used by the Kotlin compiler
* to prevent lookup of this name in the resolution.
*/
// TODO: use inline class in 1.3
typealias ClassName = String
val ClassName.isLocal: Boolean
get() = this.startsWith(".")
@@ -0,0 +1,481 @@
/*
* Copyright 2000-2018 JetBrains s.r.o. 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
import org.jetbrains.kotlin.metadata.ProtoBuf.*
import org.jetbrains.kotlin.metadata.deserialization.Flags as F
import org.jetbrains.kotlin.metadata.ProtoBuf.Class.Kind as ClassKind
/**
* A container of all flags applicable to all Kotlin declarations. A "flag" is a boolean trait that is either present or not
* in a declaration. To check whether the flag is present in the bitmask, call [MetadataFlag.invoke] on the flag, passing the bitmask
* as the argument:
*
* override fun visitFunction(flags: Int, name: String): KmFunctionVisitor? {
* if (Flags.Function.IS_INLINE(flags)) {
* ...
* }
* }
*
* To construct a bitmask out of several flags, call [Flags.invoke] on the needed flags:
*
* v.visitFunction(Flags(Flags.Function.IS_DECLARATION, Flags.Function.IS_INLINE), "foo")
*
* Flags common to multiple kinds of Kotlin declarations ("common flags") are declared directly in the [Flags] object.
* Flags applicable to specific kinds of declarations ("declaration-specific flags") are declared in nested objects of the [Flags] object.
*
* Some flags are mutually exclusive, i.e. there are "flag groups" such that no more than one flag from each group can be present
* in the same bitmask. Among common flags, there are the following flag groups:
* * visibility flags: [IS_INTERNAL], [IS_PRIVATE], [IS_PROTECTED], [IS_PUBLIC], [IS_PRIVATE_TO_THIS], [IS_LOCAL]
* * modality flags: [IS_FINAL], [IS_OPEN], [IS_ABSTRACT], [IS_SEALED]
*
* Some declaration-specific flags form other flag groups, see the documentation of the corresponding containers for more information.
*/
object Flags {
/**
* Combines several flags into an integer bitmask. Note that in case several mutually exclusive flags are passed (for example,
* several visibility flags), the resulting bitmask will hold the value of the latest flag.
*
* For example, `Flags(Flags.IS_PRIVATE, Flags.IS_PUBLIC, Flags.IS_INTERNAL)` is the same as `Flags(Flags.IS_INTERNAL)`
*/
operator fun invoke(vararg flags: MetadataFlag): Int =
flags.fold(0) { acc, flag -> flag + acc }
/**
* Signifies that the corresponding declaration has at least one annotation.
*
* This flag is useful for reading Kotlin metadata on JVM efficiently. On JVM, most of the annotations are written not to the Kotlin
* metadata, but directly on the corresponding declarations in the class file. This flag can be used as an optimization to avoid
* reading annotations from the class file (which can be slow) in case when a declaration has no annotations.
*/
@JvmField
val HAS_ANNOTATIONS = MetadataFlag(F.HAS_ANNOTATIONS)
/**
* A visibility flag, signifying that the corresponding declaration is `internal`.
*/
@JvmField
val IS_INTERNAL = MetadataFlag(F.VISIBILITY, Visibility.INTERNAL_VALUE)
/**
* A visibility flag, signifying that the corresponding declaration is `private`.
*/
@JvmField
val IS_PRIVATE = MetadataFlag(F.VISIBILITY, Visibility.PRIVATE_VALUE)
/**
* A visibility flag, signifying that the corresponding declaration is `protected`.
*/
@JvmField
val IS_PROTECTED = MetadataFlag(F.VISIBILITY, Visibility.PROTECTED_VALUE)
/**
* A visibility flag, signifying that the corresponding declaration is `public`.
*/
@JvmField
val IS_PUBLIC = MetadataFlag(F.VISIBILITY, Visibility.PUBLIC_VALUE)
/**
* A visibility flag, signifying that the corresponding declaration is "private-to-this", which is a non-denotable visibility of
* private members in Kotlin which are callable only on the same instance of the declaring class.
*/
@JvmField
val IS_PRIVATE_TO_THIS = MetadataFlag(F.VISIBILITY, Visibility.PRIVATE_TO_THIS_VALUE)
/**
* A visibility flag, signifying that the corresponding declaration is local, i.e. declared inside a code block
* and not visible from the outside.
*/
@JvmField
val IS_LOCAL = MetadataFlag(F.VISIBILITY, Visibility.LOCAL_VALUE)
/**
* A modality flag, signifying that the corresponding declaration is `final`.
*/
@JvmField
val IS_FINAL = MetadataFlag(F.MODALITY, Modality.FINAL_VALUE)
/**
* A modality flag, signifying that the corresponding declaration is `open`.
*/
@JvmField
val IS_OPEN = MetadataFlag(F.MODALITY, Modality.OPEN_VALUE)
/**
* A modality flag, signifying that the corresponding declaration is `abstract`.
*/
@JvmField
val IS_ABSTRACT = MetadataFlag(F.MODALITY, Modality.ABSTRACT_VALUE)
/**
* A modality flag, signifying that the corresponding declaration is `sealed`.
*/
@JvmField
val IS_SEALED = MetadataFlag(F.MODALITY, Modality.SEALED_VALUE)
/**
* A container of flags applicable to Kotlin classes, including interfaces, objects, enum classes and annotation classes.
*
* In addition to the common flag groups, the following flag groups exist for class flags:
* * class kind flags: [IS_CLASS], [IS_INTERFACE], [IS_ENUM_CLASS], [IS_ENUM_ENTRY], [IS_ANNOTATION_CLASS], [IS_OBJECT],
* [IS_COMPANION_OBJECT]
*/
object Class {
/**
* A class kind flag, signifying that the corresponding class is a usual `class`.
*/
@JvmField
val IS_CLASS = MetadataFlag(F.CLASS_KIND, ClassKind.CLASS_VALUE)
/**
* A class kind flag, signifying that the corresponding class is an `interface`.
*/
@JvmField
val IS_INTERFACE = MetadataFlag(F.CLASS_KIND, ClassKind.INTERFACE_VALUE)
/**
* A class kind flag, signifying that the corresponding class is an `enum class`.
*/
@JvmField
val IS_ENUM_CLASS = MetadataFlag(F.CLASS_KIND, ClassKind.ENUM_CLASS_VALUE)
/**
* A class kind flag, signifying that the corresponding class is an enum entry.
*/
@JvmField
val IS_ENUM_ENTRY = MetadataFlag(F.CLASS_KIND, ClassKind.ENUM_ENTRY_VALUE)
/**
* A class kind flag, signifying that the corresponding class is an `annotation class`.
*/
@JvmField
val IS_ANNOTATION_CLASS = MetadataFlag(F.CLASS_KIND, ClassKind.ANNOTATION_CLASS_VALUE)
/**
* A class kind flag, signifying that the corresponding class is a non-companion `object`.
*/
@JvmField
val IS_OBJECT = MetadataFlag(F.CLASS_KIND, ClassKind.OBJECT_VALUE)
/**
* A class kind flag, signifying that the corresponding class is a `companion object`.
*/
@JvmField
val IS_COMPANION_OBJECT = MetadataFlag(F.CLASS_KIND, ClassKind.COMPANION_OBJECT_VALUE)
/**
* Signifies that the corresponding class is `inner`.
*/
@JvmField
val IS_INNER = MetadataFlag(F.IS_INNER)
/**
* Signifies that the corresponding class is `data`.
*/
@JvmField
val IS_DATA = MetadataFlag(F.IS_DATA)
/**
* Signifies that the corresponding class is `external`.
*/
@JvmField
val IS_EXTERNAL = MetadataFlag(F.IS_EXTERNAL_CLASS)
/**
* Signifies that the corresponding class is `expect`.
*/
@JvmField
val IS_EXPECT = MetadataFlag(F.IS_EXPECT_CLASS)
/**
* Signifies that the corresponding class is `inline`.
*/
@JvmField
val IS_INLINE = MetadataFlag(F.IS_INLINE_CLASS)
}
/**
* A container of flags applicable to Kotlin constructors.
*/
object Constructor {
/**
* Signifies that the corresponding constructor is primary, i.e. declared in the class header, not in the class body.
*/
@JvmField
val IS_PRIMARY = MetadataFlag(F.IS_SECONDARY, 0)
}
/**
* A container of flags applicable to Kotlin functions.
*
* In addition to the common flag groups, the following flag groups exist for function flags:
* * member kind flags: [IS_DECLARATION], [IS_FAKE_OVERRIDE], [IS_DELEGATION], [IS_SYNTHESIZED]
*/
object Function {
/**
* A member kind flag, signifying that the corresponding function is explicitly declared in the containing class.
*/
@JvmField
val IS_DECLARATION = MetadataFlag(F.MEMBER_KIND, MemberKind.DECLARATION_VALUE)
/**
* A member kind flag, signifying that the corresponding function exists in the containing class because a function with a suitable
* signature exists in a supertype. This flag is not written by the Kotlin compiler and its effects are unspecified.
*/
@JvmField
val IS_FAKE_OVERRIDE = MetadataFlag(F.MEMBER_KIND, MemberKind.FAKE_OVERRIDE_VALUE)
/**
* A member kind flag, signifying that the corresponding function exists in the containing class because it has been produced
* by interface delegation (delegation "by").
*/
@JvmField
val IS_DELEGATION = MetadataFlag(F.MEMBER_KIND, MemberKind.DELEGATION_VALUE)
/**
* A member kind flag, signifying that the corresponding function exists in the containing class because it has been synthesized
* by the compiler and has no declaration in the source code.
*/
@JvmField
val IS_SYNTHESIZED = MetadataFlag(F.MEMBER_KIND, MemberKind.SYNTHESIZED_VALUE)
/**
* Signifies that the corresponding function is `operator`.
*/
@JvmField
val IS_OPERATOR = MetadataFlag(F.IS_OPERATOR)
/**
* Signifies that the corresponding function is `infix`.
*/
@JvmField
val IS_INFIX = MetadataFlag(F.IS_INFIX)
/**
* Signifies that the corresponding function is `inline`.
*/
@JvmField
val IS_INLINE = MetadataFlag(F.IS_INLINE)
/**
* Signifies that the corresponding function is `tailrec`.
*/
@JvmField
val IS_TAILREC = MetadataFlag(F.IS_TAILREC)
/**
* Signifies that the corresponding function is `external`.
*/
@JvmField
val IS_EXTERNAL = MetadataFlag(F.IS_EXTERNAL_FUNCTION)
/**
* Signifies that the corresponding function is `suspend`.
*/
@JvmField
val IS_SUSPEND = MetadataFlag(F.IS_SUSPEND)
/**
* Signifies that the corresponding function is `expect`.
*/
@JvmField
val IS_EXPECT = MetadataFlag(F.IS_EXPECT_FUNCTION)
}
/**
* A container of flags applicable to Kotlin properties.
*
* In addition to the common flag groups, the following flag groups exist for property flags:
* * member kind flags: [IS_DECLARATION], [IS_FAKE_OVERRIDE], [IS_DELEGATION], [IS_SYNTHESIZED]
*/
object Property {
/**
* A member kind flag, signifying that the corresponding property is explicitly declared in the containing class.
*/
@JvmField
val IS_DECLARATION = MetadataFlag(F.MEMBER_KIND, MemberKind.DECLARATION_VALUE)
/**
* A member kind flag, signifying that the corresponding property exists in the containing class because a property with a suitable
* signature exists in a supertype. This flag is not written by the Kotlin compiler and its effects are unspecified.
*/
@JvmField
val IS_FAKE_OVERRIDE = MetadataFlag(F.MEMBER_KIND, MemberKind.FAKE_OVERRIDE_VALUE)
/**
* A member kind flag, signifying that the corresponding property exists in the containing class because it has been produced
* by interface delegation (delegation "by").
*/
@JvmField
val IS_DELEGATION = MetadataFlag(F.MEMBER_KIND, MemberKind.DELEGATION_VALUE)
/**
* A member kind flag, signifying that the corresponding property exists in the containing class because it has been synthesized
* by the compiler and has no declaration in the source code.
*/
@JvmField
val IS_SYNTHESIZED = MetadataFlag(F.MEMBER_KIND, MemberKind.SYNTHESIZED_VALUE)
/**
* Signifies that the corresponding property is `var`.
*/
@JvmField
val IS_VAR = MetadataFlag(F.IS_VAR)
/**
* Signifies that the corresponding property has a getter.
*/
@JvmField
val HAS_GETTER = MetadataFlag(F.HAS_GETTER)
/**
* Signifies that the corresponding property has a setter.
*/
@JvmField
val HAS_SETTER = MetadataFlag(F.HAS_SETTER)
/**
* Signifies that the corresponding property is `const`.
*/
@JvmField
val IS_CONST = MetadataFlag(F.IS_CONST)
/**
* Signifies that the corresponding property is `lateinit`.
*/
@JvmField
val IS_LATEINIT = MetadataFlag(F.IS_LATEINIT)
/**
* Signifies that the corresponding property has a constant value. On JVM, this flag allows an optimization similarly to
* [F.HAS_ANNOTATIONS]: constant values of properties are written to the bytecode directly, and this flag can be used to avoid
* reading the value from the bytecode in case there isn't one.
*/
@JvmField
val HAS_CONSTANT = MetadataFlag(F.HAS_CONSTANT)
/**
* Signifies that the corresponding property is `external`.
*/
@JvmField
val IS_EXTERNAL = MetadataFlag(F.IS_EXTERNAL_PROPERTY)
/**
* Signifies that the corresponding property is a delegated property.
*/
@JvmField
val IS_DELEGATED = MetadataFlag(F.IS_DELEGATED)
/**
* Signifies that the corresponding property is `expect`.
*/
@JvmField
val IS_EXPECT = MetadataFlag(F.IS_EXPECT_PROPERTY)
}
/**
* A container of flags applicable to Kotlin property getters and setters.
*/
object PropertyAccessor {
/**
* Signifies that the corresponding property accessor is not default, i.e. it has a body and/or annotations in the source code.
*/
@JvmField
val IS_NOT_DEFAULT = MetadataFlag(F.IS_NOT_DEFAULT)
/**
* Signifies that the corresponding property accessor is `external`.
*/
@JvmField
val IS_EXTERNAL = MetadataFlag(F.IS_EXTERNAL_ACCESSOR)
/**
* Signifies that the corresponding property accessor is `inline`.
*/
@JvmField
val IS_INLINE = MetadataFlag(F.IS_INLINE_ACCESSOR)
}
/**
* A container of flags applicable to Kotlin types.
*/
object Type {
/**
* Signifies that the corresponding type is marked as nullable, i.e. has a question mark at the end of its notation.
*/
@JvmField
val IS_NULLABLE = MetadataFlag(0, 1, 1)
/**
* Signifies that the corresponding type is `suspend`.
*/
@JvmField
val IS_SUSPEND = MetadataFlag(F.SUSPEND_TYPE.offset + 1, F.SUSPEND_TYPE.bitWidth, 1)
}
/**
* A container of flags applicable to Kotlin type parameters.
*/
object TypeParameter {
/**
* Signifies that the corresponding type parameter is `reified`.
*/
@JvmField
val IS_REIFIED = MetadataFlag(0, 1, 1)
}
/**
* A container of flags applicable to Kotlin value parameters.
*/
object ValueParameter {
/**
* Signifies that the corresponding value parameter declares a default value. Note that the default value itself can be a complex
* expression and is not available via metadata. Also note that in case of an override of a parameter with default value, the
* parameter in the derived method does _not_ declare the default value ([DECLARES_DEFAULT_VALUE] == false), but the parameter is
* still optional at the call site because the default value from the base method is used.
*/
@JvmField
val DECLARES_DEFAULT_VALUE = MetadataFlag(F.DECLARES_DEFAULT_VALUE)
/**
* Signifies that the corresponding value parameter is `crossinline`.
*/
@JvmField
val IS_CROSSINLINE = MetadataFlag(F.IS_CROSSINLINE)
/**
* Signifies that the corresponding value parameter is `noinline`.
*/
@JvmField
val IS_NOINLINE = MetadataFlag(F.IS_NOINLINE)
}
/**
* A container of flags applicable to Kotlin effect expressions.
*
* Contracts are an internal feature of the standard Kotlin library, and their behavior and/or binary format
* may change in a subsequent release.
*/
object EffectExpression {
/**
* Signifies that the corresponding effect expression should be negated to compute the proposition or the conclusion of an effect.
*/
@JvmField
val IS_NEGATED = MetadataFlag(F.IS_NEGATED)
/**
* Signifies that the corresponding effect expression checks whether a value of some variable is `null`.
*/
@JvmField
val IS_NULL_CHECK_PREDICATE = MetadataFlag(F.IS_NULL_CHECK_PREDICATE)
}
}
@@ -0,0 +1,8 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. 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
class InconsistentKotlinMetadataException(message: String, cause: Throwable? = null) : RuntimeException(message, cause)
@@ -0,0 +1,33 @@
/*
* Copyright 2000-2018 JetBrains s.r.o. 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
import org.jetbrains.kotlin.metadata.deserialization.Flags.BooleanFlagField
import org.jetbrains.kotlin.metadata.deserialization.Flags.FlagField
/**
* Represents a boolean flag that is either present or not in a Kotlin declaration.
*
* @see Flags
*/
class MetadataFlag internal constructor(
private val offset: Int,
private val bitWidth: Int,
private val value: Int
) {
internal constructor(field: FlagField<*>, value: Int) : this(field.offset, field.bitWidth, value)
internal constructor(field: BooleanFlagField) : this(field, 1)
internal operator fun plus(flags: Int): Int =
(flags and (((1 shl bitWidth) - 1) shl offset).inv()) + (value shl offset)
/**
* Checks whether the flag is present in the given bitmask.
*/
operator fun invoke(flags: Int): Boolean =
(flags ushr offset) and ((1 shl bitWidth) - 1) == value
}
@@ -0,0 +1,48 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. 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
/**
* Represents an annotation, written to the Kotlin metadata. Note that not all annotations are written to metadata on all platforms.
* For example, on JVM most of the annotations are written directly on the corresponding declarations in the class file,
* and entries in the metadata only have a flag ([Flags.HAS_ANNOTATIONS]) to signal if they do have annotations in the bytecode.
* On JVM, only annotations on type parameters and types are serialized to the Kotlin metadata.
*
* @param className the fully qualified name of the annotation class
* @param arguments explicitly specified arguments to the annotation; does not include default values for annotation parameters
* (specified in the annotation class declaration)
*/
data class KmAnnotation(val className: ClassName, val arguments: Map<String, KmAnnotationArgument<*>>)
/**
* Represents an argument to the annotation.
*
* @param T the type of the value of this argument
*/
sealed class KmAnnotationArgument<out T : Any> {
/**
* The value of this argument.
*/
abstract val value: T
data class ByteValue(override val value: Byte) : KmAnnotationArgument<Byte>()
data class CharValue(override val value: Char) : KmAnnotationArgument<Char>()
data class ShortValue(override val value: Short) : KmAnnotationArgument<Short>()
data class IntValue(override val value: Int) : KmAnnotationArgument<Int>()
data class LongValue(override val value: Long) : KmAnnotationArgument<Long>()
data class FloatValue(override val value: Float) : KmAnnotationArgument<Float>()
data class DoubleValue(override val value: Double) : KmAnnotationArgument<Double>()
data class BooleanValue(override val value: Boolean) : KmAnnotationArgument<Boolean>()
data class StringValue(override val value: String) : KmAnnotationArgument<String>()
data class KClassValue(override val value: ClassName) : KmAnnotationArgument<ClassName>()
data class EnumValue(val enumClassName: ClassName, val enumEntryName: String) : KmAnnotationArgument<String>() {
override val value: String = "$enumClassName.$enumEntryName"
}
data class AnnotationValue(override val value: KmAnnotation) : KmAnnotationArgument<KmAnnotation>()
data class ArrayValue(override val value: List<KmAnnotationArgument<*>>) : KmAnnotationArgument<List<KmAnnotationArgument<*>>>()
}
@@ -0,0 +1,61 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. 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
import kotlin.reflect.KClass
/**
* A type of the extension visitor expected by the code that uses the visitor API.
*
* Each declaration which can have platform-specific extensions in the metadata has a method `visitExtensions` in its visitor, e.g.:
*
* open fun visitExtensions(type: KmExtensionType): KmFunctionExtensionVisitor?
*
* The client code is supposed to return the extension visitor corresponding to the given type, or to return `null` if the type is
* of no interest to that code. Each platform-specific extension visitor has a [KmExtensionType] instance declared in the `TYPE` property
* its companion object. For example, to load JVM extensions on a function, one could do:
*
* override fun visitExtensions(type: KmExtensionType): KmFunctionExtensionVisitor? {
* if (type != JvmFunctionExtensionVisitor.TYPE) return null
*
* return object : JvmFunctionExtensionVisitor() {
* ...
* }
* }
*
* In case an extension visitor of an unrelated type is returned, the code using the visitor API must ignore that visitor.
*/
data class KmExtensionType(val klass: KClass<out KmExtensionVisitor>)
/**
* A base interface for all extension visitors.
*/
interface KmExtensionVisitor
/**
* A visitor to visit platform-specific extensions for a function.
*/
interface KmFunctionExtensionVisitor : KmExtensionVisitor
/**
* A visitor to visit platform-specific extensions for a property.
*/
interface KmPropertyExtensionVisitor : KmExtensionVisitor
/**
* A visitor to visit platform-specific extensions for a constructor.
*/
interface KmConstructorExtensionVisitor : KmExtensionVisitor
/**
* A visitor to visit platform-specific extensions for a type parameter.
*/
interface KmTypeParameterExtensionVisitor : KmExtensionVisitor
/**
* A visitor to visit platform-specific extensions for a type.
*/
interface KmTypeExtensionVisitor : KmExtensionVisitor
@@ -0,0 +1,35 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. 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.impl.extensions
import kotlinx.metadata.*
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.NameResolver
import org.jetbrains.kotlin.metadata.deserialization.TypeTable
import java.util.*
interface MetadataExtensions {
fun readFunctionExtensions(v: KmFunctionVisitor, proto: ProtoBuf.Function, strings: NameResolver, types: TypeTable)
fun readPropertyExtensions(v: KmPropertyVisitor, proto: ProtoBuf.Property, strings: NameResolver, types: TypeTable)
fun readConstructorExtensions(v: KmConstructorVisitor, proto: ProtoBuf.Constructor, strings: NameResolver, types: TypeTable)
fun readTypeParameterExtensions(v: KmTypeParameterVisitor, proto: ProtoBuf.TypeParameter, strings: NameResolver)
fun readTypeExtensions(v: KmTypeVisitor, proto: ProtoBuf.Type, strings: NameResolver)
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"
)
}
}
}
@@ -0,0 +1,46 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. 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.impl
import kotlinx.metadata.ClassName
import kotlinx.metadata.KmAnnotation
import kotlinx.metadata.KmAnnotationArgument
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.ProtoBuf.Annotation.Argument.Value.Type.*
import org.jetbrains.kotlin.metadata.deserialization.NameResolver
fun ProtoBuf.Annotation.readAnnotation(strings: NameResolver): KmAnnotation =
KmAnnotation(
strings.getClassName(id),
argumentList.mapNotNull { argument ->
argument.value.readAnnotationArgument(strings)?.let { value ->
strings.getString(argument.nameId) to value
}
}.toMap()
)
private fun ProtoBuf.Annotation.Argument.Value.readAnnotationArgument(strings: NameResolver): KmAnnotationArgument<*>? =
when (type) {
BYTE -> KmAnnotationArgument.ByteValue(intValue.toByte())
CHAR -> KmAnnotationArgument.CharValue(intValue.toChar())
SHORT -> KmAnnotationArgument.ShortValue(intValue.toShort())
INT -> KmAnnotationArgument.IntValue(intValue.toInt())
LONG -> KmAnnotationArgument.LongValue(intValue)
FLOAT -> KmAnnotationArgument.FloatValue(floatValue)
DOUBLE -> KmAnnotationArgument.DoubleValue(doubleValue)
BOOLEAN -> KmAnnotationArgument.BooleanValue(intValue != 0L)
STRING -> KmAnnotationArgument.StringValue(strings.getString(stringValue))
CLASS -> KmAnnotationArgument.KClassValue(strings.getClassName(classId))
ENUM -> KmAnnotationArgument.EnumValue(strings.getClassName(classId), strings.getString(enumValueId))
ANNOTATION -> KmAnnotationArgument.AnnotationValue(annotation.readAnnotation(strings))
ARRAY -> KmAnnotationArgument.ArrayValue(arrayElementList.mapNotNull { it.readAnnotationArgument(strings) })
null -> null
}
internal fun NameResolver.getClassName(index: Int): ClassName {
val name = getQualifiedClassName(index)
return if (isLocalClassName(index)) ".$name" else name
}
@@ -0,0 +1,413 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. 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.impl
import kotlinx.metadata.*
import kotlinx.metadata.impl.extensions.MetadataExtensions
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.*
import org.jetbrains.kotlin.metadata.deserialization.Flags
import org.jetbrains.kotlin.protobuf.MessageLite
class ReadContext(
internal val strings: NameResolver,
internal val types: TypeTable,
internal val versionRequirements: VersionRequirementTable,
private val parent: ReadContext? = null
) {
internal val extensions = MetadataExtensions.INSTANCE
private val typeParameterNameToId = mutableMapOf<Int, Int>()
operator fun get(index: Int): String =
strings.getString(index)
fun className(index: Int): ClassName =
strings.getClassName(index)
fun getTypeParameterId(name: Int): Int? =
typeParameterNameToId[name] ?: parent?.getTypeParameterId(name)
fun withTypeParameters(typeParameters: List<ProtoBuf.TypeParameter>): ReadContext =
ReadContext(strings, types, versionRequirements, this).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)
v.visit(flags, c.className(fqName))
for (typeParameter in typeParameterList) {
typeParameter.accept(v::visitTypeParameter, c)
}
for (supertype in supertypes(c.types)) {
v.visitSupertype(supertype.typeFlags)?.let { supertype.accept(it, c) }
}
for (constructor in constructorList) {
v.visitConstructor(constructor.flags)?.let { constructor.accept(it, c) }
}
v.visitDeclarations(functionList, propertyList, typeAliasList, c)
if (hasCompanionObjectName()) {
v.visitCompanionObject(c[companionObjectName])
}
for (nestedClassName in nestedClassNameList) {
v.visitNestedClass(c[nestedClassName])
}
for (enumEntry in enumEntryList) {
if (!enumEntry.hasName()) {
throw InconsistentKotlinMetadataException("No name for EnumEntry")
}
v.visitEnumEntry(c[enumEntry.name])
}
for (sealedSubclassFqName in sealedSubclassFqNameList) {
v.visitSealedSubclass(c.className(sealedSubclassFqName))
}
if (hasVersionRequirement()) {
v.visitVersionRequirement()?.let { acceptVersionRequirementVisitor(it, c) }
}
v.visitEnd()
}
fun ProtoBuf.Package.accept(v: KmPackageVisitor, strings: NameResolver) {
val c = ReadContext(strings, TypeTable(typeTable), VersionRequirementTable.create(versionRequirementTable))
v.visitDeclarations(functionList, propertyList, typeAliasList, c)
v.visitEnd()
}
private fun KmDeclarationContainerVisitor.visitDeclarations(
functions: List<ProtoBuf.Function>,
properties: List<ProtoBuf.Property>,
typeAliases: List<ProtoBuf.TypeAlias>,
c: ReadContext
) {
for (function in functions) {
visitFunction(function.flags, c[function.name])?.let { function.accept(it, c) }
}
for (property in properties) {
val flags = property.flags
val defaultAccessorFlags = Flags.getAccessorFlags(
Flags.HAS_ANNOTATIONS.get(flags), Flags.VISIBILITY.get(flags), Flags.MODALITY.get(flags), false, false, false
)
visitProperty(
flags,
c[property.name],
if (property.hasGetterFlags()) property.getterFlags else defaultAccessorFlags,
if (property.hasSetterFlags()) property.setterFlags else defaultAccessorFlags
)?.let { property.accept(it, c) }
}
for (typeAlias in typeAliases) {
visitTypeAlias(typeAlias.flags, c[typeAlias.name])?.let { typeAlias.accept(it, c) }
}
}
fun ProtoBuf.Function.accept(v: KmLambdaVisitor, strings: NameResolver) {
val c = ReadContext(strings, TypeTable(typeTable), VersionRequirementTable.EMPTY)
v.visitFunction(flags, c[name])?.let { accept(it, c) }
v.visitEnd()
}
private fun ProtoBuf.Constructor.accept(v: KmConstructorVisitor, c: ReadContext) {
for (parameter in valueParameterList) {
v.visitValueParameter(parameter.flags, c[parameter.name])?.let { parameter.accept(it, c) }
}
if (hasVersionRequirement()) {
v.visitVersionRequirement()?.let { acceptVersionRequirementVisitor(it, c) }
}
c.extensions.readConstructorExtensions(v, this, c.strings, c.types)
v.visitEnd()
}
private fun ProtoBuf.Function.accept(v: KmFunctionVisitor, outer: ReadContext) {
val c = outer.withTypeParameters(typeParameterList)
for (typeParameter in typeParameterList) {
typeParameter.accept(v::visitTypeParameter, c)
}
receiverType(c.types)?.let { receiverType ->
v.visitReceiverParameterType(receiverType.typeFlags)?.let { receiverType.accept(it, c) }
}
for (parameter in valueParameterList) {
v.visitValueParameter(parameter.flags, c[parameter.name])?.let { parameter.accept(it, c) }
}
returnType(c.types).let { returnType ->
v.visitReturnType(returnType.typeFlags)?.let { returnType.accept(it, c) }
}
if (hasContract()) {
v.visitContract()?.let { contract.accept(it, c) }
}
if (hasVersionRequirement()) {
v.visitVersionRequirement()?.let { acceptVersionRequirementVisitor(it, c) }
}
c.extensions.readFunctionExtensions(v, this, c.strings, c.types)
v.visitEnd()
}
private fun ProtoBuf.Property.accept(v: KmPropertyVisitor, outer: ReadContext) {
val c = outer.withTypeParameters(typeParameterList)
for (typeParameter in typeParameterList) {
typeParameter.accept(v::visitTypeParameter, c)
}
receiverType(c.types)?.let { receiverType ->
v.visitReceiverParameterType(receiverType.typeFlags)?.let { receiverType.accept(it, c) }
}
if (hasSetterValueParameter()) {
val parameter = setterValueParameter
v.visitSetterParameter(parameter.flags, c[parameter.name])?.let { parameter.accept(it, c) }
}
returnType(c.types).let { returnType ->
v.visitReturnType(returnType.typeFlags)?.let { returnType.accept(it, c) }
}
if (hasVersionRequirement()) {
v.visitVersionRequirement()?.let { acceptVersionRequirementVisitor(it, c) }
}
c.extensions.readPropertyExtensions(v, this, c.strings, c.types)
v.visitEnd()
}
private fun ProtoBuf.TypeAlias.accept(v: KmTypeAliasVisitor, outer: ReadContext) {
val c = outer.withTypeParameters(typeParameterList)
for (typeParameter in typeParameterList) {
typeParameter.accept(v::visitTypeParameter, c)
}
underlyingType(c.types).let { underlyingType ->
v.visitUnderlyingType(underlyingType.typeFlags)?.let { underlyingType.accept(it, c) }
}
expandedType(c.types).let { expandedType ->
v.visitExpandedType(expandedType.typeFlags)?.let { expandedType.accept(it, c) }
}
for (annotation in annotationList) {
v.visitAnnotation(annotation.readAnnotation(c.strings))
}
if (hasVersionRequirement()) {
v.visitVersionRequirement()?.let { acceptVersionRequirementVisitor(it, c) }
}
v.visitEnd()
}
private fun ProtoBuf.ValueParameter.accept(v: KmValueParameterVisitor, c: ReadContext) {
type(c.types).let { type ->
v.visitType(type.typeFlags)?.let { type.accept(it, c) }
}
varargElementType(c.types)?.let { varargElementType ->
v.visitVarargElementType(varargElementType.typeFlags)?.let { varargElementType.accept(it, c) }
}
v.visitEnd()
}
private inline fun ProtoBuf.TypeParameter.accept(
visit: (flags: Int, name: String, id: Int, variance: KmVariance) -> KmTypeParameterVisitor?,
c: ReadContext
) {
val variance = when (variance!!) {
ProtoBuf.TypeParameter.Variance.IN -> KmVariance.IN
ProtoBuf.TypeParameter.Variance.OUT -> KmVariance.OUT
ProtoBuf.TypeParameter.Variance.INV -> KmVariance.INVARIANT
}
visit(typeParameterFlags, c[name], id, variance)?.let { accept(it, c) }
}
private fun ProtoBuf.TypeParameter.accept(v: KmTypeParameterVisitor, c: ReadContext) {
for (upperBound in upperBounds(c.types)) {
v.visitUpperBound(upperBound.typeFlags)?.let { upperBound.accept(it, c) }
}
c.extensions.readTypeParameterExtensions(v, this, c.strings)
v.visitEnd()
}
private fun ProtoBuf.Type.accept(v: KmTypeVisitor, c: ReadContext) {
when {
hasClassName() -> v.visitClass(c.className(className))
hasTypeAliasName() -> v.visitTypeAlias(c.className(typeAliasName))
hasTypeParameter() -> v.visitTypeParameter(typeParameter)
hasTypeParameterName() -> {
val id = c.getTypeParameterId(typeParameterName)
?: throw InconsistentKotlinMetadataException("No type parameter id for ${c[typeParameterName]}")
v.visitTypeParameter(id)
}
else -> {
throw InconsistentKotlinMetadataException("No classifier (class, type alias or type parameter) recorded for Type")
}
}
for (argument in argumentList) {
val variance = when (argument.projection!!) {
ProtoBuf.Type.Argument.Projection.IN -> KmVariance.IN
ProtoBuf.Type.Argument.Projection.OUT -> KmVariance.OUT
ProtoBuf.Type.Argument.Projection.INV -> KmVariance.INVARIANT
ProtoBuf.Type.Argument.Projection.STAR -> null
}
if (variance != null) {
val argumentType = argument.type(c.types)
?: throw InconsistentKotlinMetadataException("No type argument for non-STAR projection in Type")
v.visitArgument(argumentType.typeFlags, variance)?.let { argumentType.accept(it, c) }
} else {
v.visitStarProjection()
}
}
abbreviatedType(c.types)?.let { abbreviatedType ->
v.visitAbbreviatedType(abbreviatedType.typeFlags)?.let { abbreviatedType.accept(it, c) }
}
outerType(c.types)?.let { outerType ->
v.visitOuterType(outerType.typeFlags)?.let { outerType.accept(it, c) }
}
flexibleUpperBound(c.types)?.let { upperBound ->
v.visitFlexibleTypeUpperBound(
upperBound.typeFlags,
if (hasFlexibleTypeCapabilitiesId()) c[flexibleTypeCapabilitiesId] else null
)?.let { upperBound.accept(it, c) }
}
c.extensions.readTypeExtensions(v, this, c.strings)
v.visitEnd()
}
private fun MessageLite.acceptVersionRequirementVisitor(v: KmVersionRequirementVisitor, c: ReadContext) {
val message = VersionRequirement.create(this, c.strings, c.versionRequirements)
?: throw InconsistentKotlinMetadataException("No VersionRequirement with the given id in the table")
val kind = when (message.kind) {
ProtoBuf.VersionRequirement.VersionKind.LANGUAGE_VERSION -> KmVersionRequirementVersionKind.LANGUAGE_VERSION
ProtoBuf.VersionRequirement.VersionKind.COMPILER_VERSION -> KmVersionRequirementVersionKind.COMPILER_VERSION
ProtoBuf.VersionRequirement.VersionKind.API_VERSION -> KmVersionRequirementVersionKind.API_VERSION
}
val level = when (message.level) {
DeprecationLevel.WARNING -> KmVersionRequirementLevel.WARNING
DeprecationLevel.ERROR -> KmVersionRequirementLevel.ERROR
DeprecationLevel.HIDDEN -> KmVersionRequirementLevel.HIDDEN
}
v.visit(kind, level, message.errorCode, message.message)
val (major, minor, patch) = message.version
v.visitVersion(major, minor, patch)
v.visitEnd()
}
private fun ProtoBuf.Contract.accept(v: KmContractVisitor, c: ReadContext) {
for (effect in effectList) {
if (!effect.hasEffectType()) continue
val effectType = when (effect.effectType!!) {
ProtoBuf.Effect.EffectType.RETURNS_CONSTANT -> KmEffectType.RETURNS_CONSTANT
ProtoBuf.Effect.EffectType.CALLS -> KmEffectType.CALLS
ProtoBuf.Effect.EffectType.RETURNS_NOT_NULL -> KmEffectType.RETURNS_NOT_NULL
}
val effectKind = if (!effect.hasKind()) null else when (effect.kind!!) {
ProtoBuf.Effect.InvocationKind.AT_MOST_ONCE -> KmEffectInvocationKind.AT_MOST_ONCE
ProtoBuf.Effect.InvocationKind.EXACTLY_ONCE -> KmEffectInvocationKind.EXACTLY_ONCE
ProtoBuf.Effect.InvocationKind.AT_LEAST_ONCE -> KmEffectInvocationKind.AT_LEAST_ONCE
}
v.visitEffect(effectType, effectKind)?.let { effect.accept(it, c) }
}
v.visitEnd()
}
private fun ProtoBuf.Effect.accept(v: KmEffectVisitor, c: ReadContext) {
for (constructorArgument in effectConstructorArgumentList) {
v.visitConstructorArgument()?.let { constructorArgument.accept(it, c) }
}
if (hasConclusionOfConditionalEffect()) {
v.visitConclusionOfConditionalEffect()?.let { conclusionOfConditionalEffect.accept(it, c) }
}
v.visitEnd()
}
private fun ProtoBuf.Expression.accept(v: KmEffectExpressionVisitor, c: ReadContext) {
v.visit(
flags,
if (hasValueParameterReference()) valueParameterReference else null
)
if (hasConstantValue()) {
v.visitConstantValue(
when (constantValue!!) {
ProtoBuf.Expression.ConstantValue.TRUE -> true
ProtoBuf.Expression.ConstantValue.FALSE -> false
ProtoBuf.Expression.ConstantValue.NULL -> null
}
)
}
isInstanceType(c.types)?.let { type ->
v.visitIsInstanceType(type.typeFlags)?.let { type.accept(it, c) }
}
for (andArgument in andArgumentList) {
v.visitAndArgument()?.let { andArgument.accept(it, c) }
}
for (orArgument in orArgumentList) {
v.visitOrArgument()?.let { orArgument.accept(it, c) }
}
v.visitEnd()
}
private val ProtoBuf.Type.typeFlags: Int
get() = (if (nullable) 1 shl 0 else 0) +
(flags shl 1)
private val ProtoBuf.TypeParameter.typeParameterFlags: Int
get() = if (reified) 1 else 0
@@ -0,0 +1,811 @@
/*
* Copyright 2000-2018 JetBrains s.r.o. 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
/**
* A visitor to visit Kotlin declarations, which are containers of other declarations: functions, properties and type aliases.
*/
abstract class KmDeclarationContainerVisitor @JvmOverloads constructor(protected open val delegate: KmDeclarationContainerVisitor? = null) {
/**
* Visits a function in the container.
*
* @param flags function flags, consisting of [Flags.HAS_ANNOTATIONS], visibility flag, modality flag and [Flags.Function] flags
* @param name the name of the function
*/
open fun visitFunction(flags: Int, name: String): KmFunctionVisitor? =
delegate?.visitFunction(flags, name)
/**
* Visits a property in the container.
*
* @param flags property flags, consisting of [Flags.HAS_ANNOTATIONS], visibility flag, modality flag and [Flags.Property] flags
* @param name the name of the property
* @param getterFlags property accessor flags, consisting of [Flags.HAS_ANNOTATIONS], visibility flag, modality flag
* and [Flags.PropertyAccessor] flags
* @param setterFlags property accessor flags, consisting of [Flags.HAS_ANNOTATIONS], visibility flag, modality flag
* and [Flags.PropertyAccessor] flags
*/
open fun visitProperty(flags: Int, name: String, getterFlags: Int, setterFlags: Int): KmPropertyVisitor? =
delegate?.visitProperty(flags, name, getterFlags, setterFlags)
/**
* Visits a type alias in the container.
*
* @param flags type alias flags, consisting of [Flags.HAS_ANNOTATIONS] and visibility flag
* @param name the name of the type alias
*/
open fun visitTypeAlias(flags: Int, name: String): KmTypeAliasVisitor? =
delegate?.visitTypeAlias(flags, name)
}
/**
* A visitor to visit Kotlin classes, including interfaces, objects, enum classes and annotation classes.
*
* When using this class, [visit] must be called first, followed by zero or more [visitTypeParameter] calls, followed by zero or more calls
* to other visit* methods, followed by [visitEnd].
*/
abstract class KmClassVisitor @JvmOverloads constructor(delegate: KmClassVisitor? = null) : KmDeclarationContainerVisitor(delegate) {
override val delegate: KmClassVisitor?
get() = super.delegate as KmClassVisitor?
/**
* Visits the basic information about the class.
*
* @param flags class flags, consisting of [Flags.HAS_ANNOTATIONS], visibility flag, modality flag and [Flags.Class] flags
* @param name the name of the class
*/
open fun visit(flags: Int, name: ClassName) {
delegate?.visit(flags, name)
}
/**
* Visits a type parameter of the class.
*
* @param flags type parameter flags, consisting of [Flags.TypeParameter] flags
* @param name the name of the type parameter
* @param id the id of the type parameter, useful to be able to uniquely identify the type parameter in different contexts where
* the name isn't enough (e.g. `class A<T> { fun <T> foo(t: T) }`)
* @param variance the declaration-site variance of the type parameter
*/
open fun visitTypeParameter(flags: Int, name: String, id: Int, variance: KmVariance): KmTypeParameterVisitor? =
delegate?.visitTypeParameter(flags, name, id, variance)
/**
* Visits a supertype of the class.
*
* @param flags type flags, consisting of [Flags.Type] flags
*/
open fun visitSupertype(flags: Int): KmTypeVisitor? =
delegate?.visitSupertype(flags)
/**
* Visits a constructor of the class.
*
* @param flags constructor flags, consisting of [Flags.HAS_ANNOTATIONS], visibility flag and [Flags.Constructor] flags
*/
open fun visitConstructor(flags: Int): KmConstructorVisitor? =
delegate?.visitConstructor(flags)
/**
* Visits the name of the companion object of this class, if it has one.
*
* @param name the name of the companion object
*/
open fun visitCompanionObject(name: String) {
delegate?.visitCompanionObject(name)
}
/**
* Visits the name of a nested class of this class.
*
* @param name the name of a nested class
*/
open fun visitNestedClass(name: String) {
delegate?.visitNestedClass(name)
}
/**
* Visits the name of an enum entry, if this class is an enum class.
*
* @param name the name of an enum entry
*/
open fun visitEnumEntry(name: String) {
delegate?.visitEnumEntry(name)
}
/**
* Visits the name of a direct subclass of this class, if this class is `sealed`.
*
* @param name the name of a direct subclass
*/
open fun visitSealedSubclass(name: ClassName) {
delegate?.visitSealedSubclass(name)
}
/**
* Visits the version requirement on this class.
*/
open fun visitVersionRequirement(): KmVersionRequirementVisitor? =
delegate?.visitVersionRequirement()
/**
* Visits the end of the class.
*/
open fun visitEnd() {
delegate?.visitEnd()
}
}
/**
* A visitor to visit Kotlin package fragments, including single file facades and multi-file class parts.
*
* When using this class, [visitEnd] must be called exactly once and after calls to all other visit* methods.
*/
abstract class KmPackageVisitor @JvmOverloads constructor(delegate: KmPackageVisitor? = null) : KmDeclarationContainerVisitor(delegate) {
override val delegate: KmPackageVisitor?
get() = super.delegate as KmPackageVisitor?
/**
* Visits the end of the package fragment.
*/
open fun visitEnd() {
delegate?.visitEnd()
}
}
/**
* A visitor to visit the metadata of a synthetic class generated for a Kotlin lambda.
*
* When using this class, [visitFunction] must be called first, followed by [visitEnd].
*/
abstract class KmLambdaVisitor @JvmOverloads constructor(private val delegate: KmLambdaVisitor? = null) {
/**
* Visits the signature of a synthetic anonymous function, representing the lambda.
*
* @param flags function flags, consisting of [Flags.HAS_ANNOTATIONS], visibility flag, modality flag and [Flags.Function] flags
* @param name the name of the function (usually `"<anonymous>"` or `"<no name provided>"` for lambdas emitted by the Kotlin compiler)
*/
open fun visitFunction(flags: Int, name: String): KmFunctionVisitor? =
delegate?.visitFunction(flags, name)
/**
* Visits the end of the lambda.
*/
open fun visitEnd() {
delegate?.visitEnd()
}
}
/**
* A visitor to visit a constructor of a Kotlin class.
*
* When using this class, [visitEnd] must be called exactly once and after calls to all other visit* methods.
*/
abstract class KmConstructorVisitor @JvmOverloads constructor(private val delegate: KmConstructorVisitor? = null) {
/**
* Visits a value parameter of the constructor.
*
* @param flags value parameter flags, consisting of [Flags.ValueParameter] flags
* @param name the name of the value parameter
*/
open fun visitValueParameter(flags: Int, name: String): KmValueParameterVisitor? =
delegate?.visitValueParameter(flags, name)
/**
* Visits the version requirement on this constructor.
*/
open fun visitVersionRequirement(): KmVersionRequirementVisitor? =
delegate?.visitVersionRequirement()
/**
* Visits the extensions of the given type on the constructor.
*
* @param type the type of extension visitor to be returned
*/
open fun visitExtensions(type: KmExtensionType): KmConstructorExtensionVisitor? =
delegate?.visitExtensions(type)
/**
* Visits the end of the constructor.
*/
open fun visitEnd() {
delegate?.visitEnd()
}
}
/**
* A visitor to visit a Kotlin function declaration.
*
* When using this class, zero or more calls to [visitTypeParameter] must be done first, followed by zero or more calls
* to other visit* methods, followed by [visitEnd].
*/
abstract class KmFunctionVisitor @JvmOverloads constructor(private val delegate: KmFunctionVisitor? = null) {
/**
* Visits a type parameter of the function.
*
* @param flags type parameter flags, consisting of [Flags.TypeParameter] flags
* @param name the name of the type parameter
* @param id the id of the type parameter, useful to be able to uniquely identify the type parameter in different contexts where
* the name isn't enough (e.g. `class A<T> { fun <T> foo(t: T) }`)
* @param variance the declaration-site variance of the type parameter
*/
open fun visitTypeParameter(flags: Int, name: String, id: Int, variance: KmVariance): KmTypeParameterVisitor? =
delegate?.visitTypeParameter(flags, name, id, variance)
/**
* Visits the type of the receiver of the function, if this is an extension function.
*
* @param flags type flags, consisting of [Flags.Type] flags
*/
open fun visitReceiverParameterType(flags: Int): KmTypeVisitor? =
delegate?.visitReceiverParameterType(flags)
/**
* Visits a value parameter of the function.
*
* @param flags value parameter flags, consisting of [Flags.ValueParameter] flags
* @param name the name of the value parameter
*/
open fun visitValueParameter(flags: Int, name: String): KmValueParameterVisitor? =
delegate?.visitValueParameter(flags, name)
/**
* Visits the return type of the function.
*
* @param flags type flags, consisting of [Flags.Type] flags
*/
open fun visitReturnType(flags: Int): KmTypeVisitor? =
delegate?.visitReturnType(flags)
/**
* Visits the version requirement on this function.
*/
open fun visitVersionRequirement(): KmVersionRequirementVisitor? =
delegate?.visitVersionRequirement()
/**
* Visits the contract of the function.
*/
open fun visitContract(): KmContractVisitor? =
delegate?.visitContract()
/**
* Visits the extensions of the given type on the function.
*
* @param type the type of extension visitor to be returned
*/
open fun visitExtensions(type: KmExtensionType): KmFunctionExtensionVisitor? =
delegate?.visitExtensions(type)
/**
* Visits the end of the function.
*/
open fun visitEnd() {
delegate?.visitEnd()
}
}
/**
* A visitor to visit a Kotlin property declaration.
*
* When using this class, zero or more calls to [visitTypeParameter] must be done first, followed by zero or more calls
* to other visit* methods, followed by [visitEnd].
*/
abstract class KmPropertyVisitor @JvmOverloads constructor(private val delegate: KmPropertyVisitor? = null) {
/**
* Visits a type parameter of the property.
*
* @param flags type parameter flags, consisting of [Flags.TypeParameter] flags
* @param name the name of the type parameter
* @param id the id of the type parameter, useful to be able to uniquely identify the type parameter in different contexts where
* the name isn't enough (e.g. `class A<T> { fun <T> foo(t: T) }`)
* @param variance the declaration-site variance of the type parameter
*/
open fun visitTypeParameter(flags: Int, name: String, id: Int, variance: KmVariance): KmTypeParameterVisitor? =
delegate?.visitTypeParameter(flags, name, id, variance)
/**
* Visits the type of the receiver of the property, if this is an extension property.
*
* @param flags type flags, consisting of [Flags.Type] flags
*/
open fun visitReceiverParameterType(flags: Int): KmTypeVisitor? =
delegate?.visitReceiverParameterType(flags)
/**
* Visits a value parameter of the setter of this property, if this is a `var` property.
*
* @param flags value parameter flags, consisting of [Flags.ValueParameter] flags
* @param name the name of the value parameter (`"<set-?>"` for properties emitted by the Kotlin compiler)
*/
open fun visitSetterParameter(flags: Int, name: String): KmValueParameterVisitor? =
delegate?.visitSetterParameter(flags, name)
/**
* Visits the type of the property.
*
* @param flags type flags, consisting of [Flags.Type] flags
*/
open fun visitReturnType(flags: Int): KmTypeVisitor? =
delegate?.visitReturnType(flags)
/**
* Visits the version requirement on this property.
*/
open fun visitVersionRequirement(): KmVersionRequirementVisitor? =
delegate?.visitVersionRequirement()
/**
* Visits the extensions of the given type on the property.
*
* @param type the type of extension visitor to be returned
*/
open fun visitExtensions(type: KmExtensionType): KmPropertyExtensionVisitor? =
delegate?.visitExtensions(type)
/**
* Visits the end of the property.
*/
open fun visitEnd() {
delegate?.visitEnd()
}
}
/**
* A visitor to visit a Kotlin type alias declaration.
*
* When using this class, zero or more calls to [visitTypeParameter] must be done first, followed by zero or more calls
* to other visit* methods, followed by [visitEnd].
*/
abstract class KmTypeAliasVisitor @JvmOverloads constructor(private val delegate: KmTypeAliasVisitor? = null) {
/**
* Visits a type parameter of the type alias.
*
* @param flags type parameter flags, consisting of [Flags.TypeParameter] flags
* @param name the name of the type parameter
* @param id the id of the type parameter, useful to be able to uniquely identify the type parameter in different contexts where
* the name isn't enough (e.g. `class A<T> { fun <T> foo(t: T) }`)
* @param variance the declaration-site variance of the type parameter
*/
open fun visitTypeParameter(flags: Int, name: String, id: Int, variance: KmVariance): KmTypeParameterVisitor? =
delegate?.visitTypeParameter(flags, name, id, variance)
/**
* Visits the underlying type of the type alias, i.e. the type in the right-hand side of the type alias declaration.
*
* @param flags type flags, consisting of [Flags.Type] flags
*/
open fun visitUnderlyingType(flags: Int): KmTypeVisitor? =
delegate?.visitUnderlyingType(flags)
/**
* Visits the expanded type of the type alias, i.e. the full expansion of the underlying type, where all type aliases are substituted
* with their expanded types. If not type aliases are used in the underlying type, expanded type is equal to the underlying type.
*
* @param flags type flags, consisting of [Flags.Type] flags
*/
open fun visitExpandedType(flags: Int): KmTypeVisitor? =
delegate?.visitExpandedType(flags)
/**
* Visits the annotation on the type alias.
*
* @param annotation annotation on the type alias
*/
open fun visitAnnotation(annotation: KmAnnotation) {
delegate?.visitAnnotation(annotation)
}
/**
* Visits the version requirement on this type alias.
*/
open fun visitVersionRequirement(): KmVersionRequirementVisitor? =
delegate?.visitVersionRequirement()
/**
* Visits the end of the type alias.
*/
open fun visitEnd() {
delegate?.visitEnd()
}
}
/**
* A visitor to visit a value parameter of a Kotlin constructor, function or property setter.
*
* When using this class, either [visitType] or [visitVarargElementType] must be called first (depending on whether the value parameter
* is `vararg` or not), followed by [visitEnd].
*/
abstract class KmValueParameterVisitor @JvmOverloads constructor(private val delegate: KmValueParameterVisitor? = null) {
/**
* Visits the type of the value parameter, if this is **not** a `vararg` parameter.
*
* @param flags type flags, consisting of [Flags.Type] flags
*/
open fun visitType(flags: Int): KmTypeVisitor? =
delegate?.visitType(flags)
/**
* Visits the type of the value parameter, if this is a `vararg` parameter.
*
* @param flags type flags, consisting of [Flags.Type] flags
*/
open fun visitVarargElementType(flags: Int): KmTypeVisitor? =
delegate?.visitVarargElementType(flags)
/**
* Visits the end of the value parameter.
*/
open fun visitEnd() {
delegate?.visitEnd()
}
}
/**
* A visitor to visit a type parameter of a Kotlin class, function or property.
*
* When using this class, zero or more [visitUpperBound] calls must be done first, followed by [visitEnd].
*/
abstract class KmTypeParameterVisitor @JvmOverloads constructor(private val delegate: KmTypeParameterVisitor? = null) {
/**
* Visits the upper bound of the type parameter.
*
* @param flags type flags, consisting of [Flags.Type] flags
*/
open fun visitUpperBound(flags: Int): KmTypeVisitor? =
delegate?.visitUpperBound(flags)
/**
* Visits the extensions of the given type on the type parameter.
*
* @param type the type of extension visitor to be returned
*/
open fun visitExtensions(type: KmExtensionType): KmTypeParameterExtensionVisitor? =
delegate?.visitExtensions(type)
/**
* Visits the end of the type parameter.
*/
open fun visitEnd() {
delegate?.visitEnd()
}
}
/**
* A visitor to visit a type. The type must have a classifier which is one of: a class [visitClass], type parameter [visitTypeParameter]
* or type alias [visitTypeAlias]. If the type's classifier is a class or a type alias, it can have type arguments ([visitArgument] and
* [visitStarProjection]). If the type's classifier is an inner class, it can have the outer type ([visitOuterType]), which captures
* the generic type arguments of the outer class. Also, each type can have an abbreviation ([visitAbbreviatedType]) in case a type alias
* was used originally at this site in the declaration (all types are expanded by default for metadata produced by the Kotlin compiler).
* If [visitFlexibleTypeUpperBound] is called, this type is regarded as a flexible type, and its contents represent the lower bound,
* and the result of the call represents the upper bound.
*
* When using this class, [visitEnd] must be called exactly once and after calls to all other visit* methods.
*/
abstract class KmTypeVisitor @JvmOverloads constructor(private val delegate: KmTypeVisitor? = null) {
/**
* Visits the name of the class, if this type's classifier is a class.
*
* @param name the name of the class
*/
open fun visitClass(name: ClassName) {
delegate?.visitClass(name)
}
/**
* Visits the name of the type alias, if this type's classifier is a type alias. Note that all types are expanded for metadata produced
* by the Kotlin compiler, so the the type with a type alias classifier may only appear in a call to [visitAbbreviatedType].
*
* @param name the name of the type alias
*/
open fun visitTypeAlias(name: ClassName) {
delegate?.visitTypeAlias(name)
}
/**
* Visits the id of the type parameter, if this type's classifier is a type parameter.
*
* @param id id of the type parameter
*/
open fun visitTypeParameter(id: Int) {
delegate?.visitTypeParameter(id)
}
/**
* Visits the type projection used in a type argument of the type based on a class or on a type alias.
* For example, in `MutableMap<in String?, *>`, `in String?` is the type projection which is the first type argument of the type.
*
* @param flags type flags, consisting of [Flags.Type] flags
* @param variance the variance of the type projection
*/
open fun visitArgument(flags: Int, variance: KmVariance): KmTypeVisitor? =
delegate?.visitArgument(flags, variance)
/**
* Visits the star (`*`) projection used in a type argument of the type based on a class or on a type alias.
* For example, in `MutableMap<in String?, *>`, `*` is the star projection which is the second type argument of the type.
*/
open fun visitStarProjection() {
delegate?.visitStarProjection()
}
/**
* Visits the abbreviation of this type. Note that all types are expanded for metadata produced by the Kotlin compiler. For example:
*
* typealias A<T> = MutableList<T>
*
* fun foo(a: A<Any>) {}
*
* The type of the `foo`'s parameter in the metadata is actually `MutableList<Any>`, and its abbreviation is `A<Any>`.
*
* @param flags type flags, consisting of [Flags.Type] flags
*/
open fun visitAbbreviatedType(flags: Int): KmTypeVisitor? =
delegate?.visitAbbreviatedType(flags)
/**
* Visits the outer type, if this type's classifier is an inner class. For example:
*
* class A<T> { inner class B<U> }
*
* fun foo(a: A<*>.B<Byte?>) {}
*
* The type of the `foo`'s parameter in the metadata is `B<Byte>` (a type whose classifier is class `B`, and it has one type argument,
* type `Byte?`), and its outer type is `A<*>` (a type whose classifier is class `A`, and it has one type argument, star projection).
*
* @param flags type flags, consisting of [Flags.Type] flags
*/
open fun visitOuterType(flags: Int): KmTypeVisitor? =
delegate?.visitOuterType(flags)
/**
* Visits the upper bound of the type, marking it as flexible and its contents as the lower bound. Flexible types in Kotlin include
* platform types in Kotlin/JVM and `dynamic` type in Kotlin/JS.
*
* @param flags type flags, consisting of [Flags.Type] flags
* @param typeFlexibilityId id of the kind of flexibility this type has. For example, "kotlin.jvm.PlatformType" for JVM platform types,
* or "kotlin.DynamicType" for JS dynamic type
*/
open fun visitFlexibleTypeUpperBound(flags: Int, typeFlexibilityId: String?): KmTypeVisitor? =
delegate?.visitFlexibleTypeUpperBound(flags, typeFlexibilityId)
/**
* Visits the extensions of the given type on the type.
*
* @param type the type of extension visitor to be returned
*/
open fun visitExtensions(type: KmExtensionType): KmTypeExtensionVisitor? =
delegate?.visitExtensions(type)
/**
* Visits the end of the type.
*/
open fun visitEnd() {
delegate?.visitEnd()
}
}
/**
* A visitor to visit the contents of a version requirement on a Kotlin declaration.
*
* Version requirement is an internal feature of the Kotlin compiler and the standard Kotlin library,
* enabled for example with the internal [kotlin.internal.RequireKotlin] annotation.
*
* When using this class, [visit] must be called first, followed by [visitVersion], followed by [visitEnd].
*/
abstract class KmVersionRequirementVisitor @JvmOverloads constructor(private val delegate: KmVersionRequirementVisitor? = null) {
/**
* Visits the description of this version requirement.
*
* @param kind the kind of the version that this declaration requires: compiler, language or API version
* @param level the level of the diagnostic that must be reported on the usages of the declaration in case
* the version requirement is not satisfied
* @param errorCode optional error code to be displayed in the diagnostic
* @param message optional message to be displayed in the diagnostic
*/
open fun visit(kind: KmVersionRequirementVersionKind, level: KmVersionRequirementLevel, errorCode: Int?, message: String?) {
delegate?.visit(kind, level, errorCode, message)
}
/**
* Visits the version required by this requirement.
*
* @param major the major component of the version (e.g. "1" in "1.2.3")
* @param minor the minor component of the version (e.g. "2" in "1.2.3")
* @param patch the patch component of the version (e.g. "3" in "1.2.3")
*/
open fun visitVersion(major: Int, minor: Int, patch: Int) {
delegate?.visitVersion(major, minor, patch)
}
/**
* Visits the end of the version requirement.
*/
open fun visitEnd() {
delegate?.visitEnd()
}
}
/**
* A visitor to visit the contents of the contract of a Kotlin function.
*
* Contracts are an internal feature of the standard Kotlin library, and their behavior and/or binary format
* may change in a subsequent release.
*
* When using this class, zero or more calls to [visitEffect] must be done first, followed by [visitEnd].
*/
abstract class KmContractVisitor @JvmOverloads constructor(private val delegate: KmContractVisitor? = null) {
/**
* Visits an effect of this contract.
*
* @param type type of the effect
* @param invocationKind optional number of invocations of the lambda parameter of this function,
* specified further in the effect expression
*/
open fun visitEffect(type: KmEffectType, invocationKind: KmEffectInvocationKind?): KmEffectVisitor? =
delegate?.visitEffect(type, invocationKind)
/**
* Visits the end of the contract.
*/
open fun visitEnd() {
delegate?.visitEnd()
}
}
/**
* A visitor to visit an effect (a part of the contract of a Kotlin function).
*
* Contracts are an internal feature of the standard Kotlin library, and their behavior and/or binary format
* may change in a subsequent release.
*
* When using this class, zero or more calls to [visitConstructorArgument] or [visitConclusionOfConditionalEffect] must be done first,
* followed by [visitEnd].
*/
abstract class KmEffectVisitor @JvmOverloads constructor(private val delegate: KmEffectVisitor? = null) {
/**
* Visits the optional argument of the effect constructor, i.e. the constant value for the [KmEffectType.RETURNS_CONSTANT] effect,
* or the parameter reference for the [KmEffectType.CALLS] effect.
*/
open fun visitConstructorArgument(): KmEffectExpressionVisitor? =
delegate?.visitConstructorArgument()
/**
* Visits the optional conclusion of the effect. If this method is called, the effect represents an implication with the
* right-hand side handled by the returned visitor.
*/
open fun visitConclusionOfConditionalEffect(): KmEffectExpressionVisitor? =
delegate?.visitConclusionOfConditionalEffect()
/**
* Visits the end of the effect.
*/
open fun visitEnd() {
delegate?.visitEnd()
}
}
/**
* A visitor to visit the effect expression, the contents of an effect (a part of the contract of a Kotlin function).
*
* Contracts are an internal feature of the standard Kotlin library, and their behavior and/or binary format
* may change in a subsequent release.
*
* When using this class, [visit] must be called first, followed by zero or more calls to other visit* methods, followed by [visitEnd].
*/
abstract class KmEffectExpressionVisitor @JvmOverloads constructor(private val delegate: KmEffectExpressionVisitor? = null) {
/**
* Visits the basic information of the effect expression.
*
* @param flags effect expression flags, consisting of [Flags.EffectExpression] flags
* @param parameterIndex optional 1-based index of the value parameter of the function, for effects which assert something about
* the function parameters. The index 0 means the extension receiver parameter
*/
open fun visit(flags: Int, parameterIndex: Int?) {
delegate?.visit(flags, parameterIndex)
}
/**
* Visits the constant value used in the effect expression. May be `true`, `false` or `null`.
*
* @param value the constant value
*/
open fun visitConstantValue(value: Any?) {
delegate?.visitConstantValue(value)
}
/**
* Visits the type used as the target of an `is`-expression in the effect expression.
*
* @param flags type flags, consisting of [Flags.Type] flags
*/
open fun visitIsInstanceType(flags: Int): KmTypeVisitor? =
delegate?.visitIsInstanceType(flags)
/**
* Visits the argument of an `&&`-expression. If this method is called, the expression represents the left-hand side and
* the returned visitor handles the right-hand side.
*/
open fun visitAndArgument(): KmEffectExpressionVisitor? =
delegate?.visitAndArgument()
/**
* Visits the argument of an `||`-expression. If this method is called, the expression represents the left-hand side and
* the returned visitor handles the right-hand side.
*/
open fun visitOrArgument(): KmEffectExpressionVisitor? =
delegate?.visitOrArgument()
/**
* Visits the end of the effect expression.
*/
open fun visitEnd() {
delegate?.visitEnd()
}
}
/**
* Variance applied to a type parameter on the declaration site (*declaration-site variance*),
* or to a type in a projection (*use-site variance*).
*/
enum class KmVariance {
/**
* The affected type parameter or type is *invariant*, which means it has no variance applied to it.
*/
INVARIANT,
/**
* The affected type parameter or type is *contravariant*. Denoted by the `in` modifier in the source code.
*/
IN,
/**
* The affected type parameter or type is *covariant*. Denoted by the `out` modifier in the source code.
*/
OUT,
}
/**
* Type of an effect (a part of the contract of a Kotlin function).
*
* Contracts are an internal feature of the standard Kotlin library, and their behavior and/or binary format
* may change in a subsequent release.
*/
enum class KmEffectType {
RETURNS_CONSTANT,
CALLS,
RETURNS_NOT_NULL,
}
/**
* Number of invocations of a lambda parameter specified by an effect (a part of the contract of a Kotlin function).
*
* Contracts are an internal feature of the standard Kotlin library, and their behavior and/or binary format
* may change in a subsequent release.
*/
enum class KmEffectInvocationKind {
AT_MOST_ONCE,
EXACTLY_ONCE,
AT_LEAST_ONCE,
}
/**
* Severity of the diagnostic reported by the compiler when a version requirement is not satisfied.
*/
enum class KmVersionRequirementLevel {
WARNING,
ERROR,
HIDDEN,
}
/**
* The kind of the version that is required by a version requirement.
*/
enum class KmVersionRequirementVersionKind {
LANGUAGE_VERSION,
COMPILER_VERSION,
API_VERSION,
}
+4
View File
@@ -113,6 +113,8 @@ include ":kotlin-build-common",
":kotlin-stdlib-jdk8",
":kotlin-stdlib:samples",
":kotlin-stdlib:jvm-minimal-for-test",
":kotlinx-metadata",
":kotlinx-metadata-jvm",
":prepare:build.version",
":kotlin-build-common",
":prepare:formatter",
@@ -204,6 +206,8 @@ project(':kotlin-stdlib:samples').projectDir = "$rootDir/libraries/stdlib/sample
project(":kotlin-stdlib:jvm-minimal-for-test").projectDir = "$rootDir/libraries/stdlib/jvm-minimal-for-test" as File
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(':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