Use JvmName on kotlin.Metadata parameters to improve public API
#KT-26359 Fixed
This commit is contained in:
@@ -12,10 +12,8 @@ fun f() {}
|
|||||||
|
|
||||||
// FILE: bar.kt
|
// FILE: bar.kt
|
||||||
|
|
||||||
@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
|
|
||||||
|
|
||||||
fun getPackageName(classFqName: String): String =
|
fun getPackageName(classFqName: String): String =
|
||||||
Class.forName(classFqName).getAnnotation(Metadata::class.java).pn
|
Class.forName(classFqName).getAnnotation(Metadata::class.java).packageName
|
||||||
|
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
val bar = getPackageName("BarKt")
|
val bar = getPackageName("BarKt")
|
||||||
|
|||||||
+2
-2
@@ -1,9 +1,9 @@
|
|||||||
<!EXPLICIT_METADATA_IS_DISALLOWED!>@Metadata<!>
|
<!EXPLICIT_METADATA_IS_DISALLOWED!>@Metadata<!>
|
||||||
class A
|
class A
|
||||||
|
|
||||||
<!EXPLICIT_METADATA_IS_DISALLOWED!>@Metadata(xs = "_")<!>
|
<!EXPLICIT_METADATA_IS_DISALLOWED!>@Metadata(extraString = "_")<!>
|
||||||
annotation class B(val m: Metadata)
|
annotation class B(val m: Metadata)
|
||||||
|
|
||||||
<!WRONG_ANNOTATION_TARGET, EXPLICIT_METADATA_IS_DISALLOWED!>@Metadata(xi = 0)<!>
|
<!WRONG_ANNOTATION_TARGET, EXPLICIT_METADATA_IS_DISALLOWED!>@Metadata(extraInt = 0)<!>
|
||||||
@B(Metadata())
|
@B(Metadata())
|
||||||
fun f() {}
|
fun f() {}
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
package
|
package
|
||||||
|
|
||||||
@kotlin.Metadata(xi = 0) @B(m = kotlin.Metadata) public fun f(): kotlin.Unit
|
@kotlin.Metadata(extraInt = 0) @B(m = kotlin.Metadata) public fun f(): kotlin.Unit
|
||||||
|
|
||||||
@kotlin.Metadata public final class A {
|
@kotlin.Metadata public final class A {
|
||||||
public constructor A()
|
public constructor A()
|
||||||
@@ -9,7 +9,7 @@ package
|
|||||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
}
|
}
|
||||||
|
|
||||||
@kotlin.Metadata(xs = "_") public final annotation class B : kotlin.Annotation {
|
@kotlin.Metadata(extraString = "_") public final annotation class B : kotlin.Annotation {
|
||||||
public constructor B(/*0*/ m: kotlin.Metadata)
|
public constructor B(/*0*/ m: kotlin.Metadata)
|
||||||
public final val m: kotlin.Metadata
|
public final val m: kotlin.Metadata
|
||||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
|||||||
+1
-1
@@ -50,7 +50,7 @@ object JvmProtoBufUtil {
|
|||||||
JvmNameResolver(JvmProtoBuf.StringTableTypes.parseDelimitedFrom(this, EXTENSION_REGISTRY), strings)
|
JvmNameResolver(JvmProtoBuf.StringTableTypes.parseDelimitedFrom(this, EXTENSION_REGISTRY), strings)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Serializes [message] and [stringTable] into a string array which must be further written to [Metadata.d1]
|
* Serializes [message] and [stringTable] into a string array which must be further written to [Metadata.data1]
|
||||||
*/
|
*/
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun writeData(message: MessageLite, stringTable: JvmStringTable): Array<String> =
|
fun writeData(message: MessageLite, stringTable: JvmStringTable): Array<String> =
|
||||||
|
|||||||
@@ -14,8 +14,6 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
|
|
||||||
|
|
||||||
package kotlin.reflect.jvm
|
package kotlin.reflect.jvm
|
||||||
|
|
||||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
||||||
@@ -35,10 +33,12 @@ import kotlin.reflect.jvm.internal.deserializeToDescriptor
|
|||||||
*/
|
*/
|
||||||
fun <R> Function<R>.reflect(): KFunction<R>? {
|
fun <R> Function<R>.reflect(): KFunction<R>? {
|
||||||
val annotation = javaClass.getAnnotation(Metadata::class.java) ?: return null
|
val annotation = javaClass.getAnnotation(Metadata::class.java) ?: return null
|
||||||
val data = annotation.d1.takeUnless(Array<String>::isEmpty) ?: return null
|
val data = annotation.data1.takeUnless(Array<String>::isEmpty) ?: return null
|
||||||
val (nameResolver, proto) = JvmProtoBufUtil.readFunctionDataFrom(data, annotation.d2)
|
val (nameResolver, proto) = JvmProtoBufUtil.readFunctionDataFrom(data, annotation.data2)
|
||||||
val metadataVersion =
|
val metadataVersion = JvmMetadataVersion(
|
||||||
JvmMetadataVersion(annotation.mv, (annotation.xi and JvmAnnotationNames.METADATA_STRICT_VERSION_SEMANTICS_FLAG) != 0)
|
annotation.metadataVersion,
|
||||||
|
(annotation.extraInt and JvmAnnotationNames.METADATA_STRICT_VERSION_SEMANTICS_FLAG) != 0
|
||||||
|
)
|
||||||
|
|
||||||
val descriptor = deserializeToDescriptor(
|
val descriptor = deserializeToDescriptor(
|
||||||
javaClass, proto, nameResolver, TypeTable(proto.typeTable), metadataVersion, MemberDeserializer::loadFunction
|
javaClass, proto, nameResolver, TypeTable(proto.typeTable), metadataVersion, MemberDeserializer::loadFunction
|
||||||
|
|||||||
@@ -10,12 +10,7 @@ import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A mirror to the [Metadata] annotation on a JVM class file, containing the metadata of Kotlin declarations declared in the class file.
|
* 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
|
* Properties of this class correspond 1:1 to the properties of [Metadata].
|
||||||
* 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 kind see [kind]
|
||||||
* @param metadataVersion see [metadataVersion]
|
* @param metadataVersion see [metadataVersion]
|
||||||
@@ -39,7 +34,7 @@ class KotlinClassHeader(
|
|||||||
/**
|
/**
|
||||||
* A kind of the metadata this header encodes.
|
* A kind of the metadata this header encodes.
|
||||||
*
|
*
|
||||||
* @see Metadata.k
|
* @see Metadata.kind
|
||||||
* @see CLASS_KIND
|
* @see CLASS_KIND
|
||||||
* @see FILE_FACADE_KIND
|
* @see FILE_FACADE_KIND
|
||||||
* @see SYNTHETIC_CLASS_KIND
|
* @see SYNTHETIC_CLASS_KIND
|
||||||
@@ -51,7 +46,7 @@ class KotlinClassHeader(
|
|||||||
/**
|
/**
|
||||||
* The version of the metadata provided in other properties of this header.
|
* The version of the metadata provided in other properties of this header.
|
||||||
*
|
*
|
||||||
* @see Metadata.mv
|
* @see Metadata.metadataVersion
|
||||||
* @see COMPATIBLE_METADATA_VERSION
|
* @see COMPATIBLE_METADATA_VERSION
|
||||||
*/
|
*/
|
||||||
val metadataVersion: IntArray = metadataVersion ?: intArrayOf()
|
val metadataVersion: IntArray = metadataVersion ?: intArrayOf()
|
||||||
@@ -59,7 +54,7 @@ class KotlinClassHeader(
|
|||||||
/**
|
/**
|
||||||
* The version of the bytecode interface (naming conventions, signatures) of the corresponding class file.
|
* The version of the bytecode interface (naming conventions, signatures) of the corresponding class file.
|
||||||
*
|
*
|
||||||
* @see Metadata.bv
|
* @see Metadata.bytecodeVersion
|
||||||
* @see COMPATIBLE_BYTECODE_VERSION
|
* @see COMPATIBLE_BYTECODE_VERSION
|
||||||
*/
|
*/
|
||||||
val bytecodeVersion: IntArray = bytecodeVersion ?: intArrayOf()
|
val bytecodeVersion: IntArray = bytecodeVersion ?: intArrayOf()
|
||||||
@@ -67,35 +62,35 @@ class KotlinClassHeader(
|
|||||||
/**
|
/**
|
||||||
* The first array of strings used to encode the metadata.
|
* The first array of strings used to encode the metadata.
|
||||||
*
|
*
|
||||||
* @see Metadata.d1
|
* @see Metadata.data1
|
||||||
*/
|
*/
|
||||||
val data1: Array<String> = data1 ?: emptyArray()
|
val data1: Array<String> = data1 ?: emptyArray()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The second array of strings used to encode the metadata.
|
* The second array of strings used to encode the metadata.
|
||||||
*
|
*
|
||||||
* @see Metadata.d2
|
* @see Metadata.data2
|
||||||
*/
|
*/
|
||||||
val data2: Array<String> = data2 ?: emptyArray()
|
val data2: Array<String> = data2 ?: emptyArray()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An extra string field for the metadata.
|
* An extra string field for the metadata.
|
||||||
*
|
*
|
||||||
* @see Metadata.xs
|
* @see Metadata.extraString
|
||||||
*/
|
*/
|
||||||
val extraString: String = extraString ?: ""
|
val extraString: String = extraString ?: ""
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fully qualified name of the Kotlin package of the corresponding class, in case [JvmPackageName] was used.
|
* Fully qualified name of the Kotlin package of the corresponding class, in case [JvmPackageName] was used.
|
||||||
*
|
*
|
||||||
* @see Metadata.pn
|
* @see Metadata.packageName
|
||||||
*/
|
*/
|
||||||
val packageName: String = packageName ?: ""
|
val packageName: String = packageName ?: ""
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An extra int field for the metadata.
|
* An extra int field for the metadata.
|
||||||
*
|
*
|
||||||
* @see Metadata.xi
|
* @see Metadata.extraInt
|
||||||
*/
|
*/
|
||||||
val extraInt: Int = extraInt ?: 0
|
val extraInt: Int = extraInt ?: 0
|
||||||
|
|
||||||
|
|||||||
@@ -15,10 +15,9 @@ import java.net.URLClassLoader
|
|||||||
import kotlin.reflect.full.primaryConstructor
|
import kotlin.reflect.full.primaryConstructor
|
||||||
|
|
||||||
class MetadataSmokeTest {
|
class MetadataSmokeTest {
|
||||||
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
|
|
||||||
private fun Class<*>.readMetadata(): KotlinClassHeader {
|
private fun Class<*>.readMetadata(): KotlinClassHeader {
|
||||||
return getAnnotation(Metadata::class.java).run {
|
return getAnnotation(Metadata::class.java).run {
|
||||||
KotlinClassHeader(k, mv, bv, d1, d2, xs, pn, xi)
|
KotlinClassHeader(kind, metadataVersion, bytecodeVersion, data1, data2, extraString, packageName, extraInt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ package kotlin
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This annotation is present on any class file produced by the Kotlin compiler and is read by the compiler and reflection.
|
* This annotation is present on any class file produced by the Kotlin compiler and is read by the compiler and reflection.
|
||||||
* Parameters have very short names on purpose: these names appear in the generated class files, and we'd like to reduce their size.
|
* Parameters have very short JVM names on purpose: these names appear in all generated class files, and we'd like to reduce their size.
|
||||||
*/
|
*/
|
||||||
@Retention(AnnotationRetention.RUNTIME)
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
@Target(AnnotationTarget.CLASS)
|
@Target(AnnotationTarget.CLASS)
|
||||||
@@ -24,35 +24,42 @@ public annotation class Metadata(
|
|||||||
*
|
*
|
||||||
* The class file with a kind not listed here is treated as a non-Kotlin file.
|
* The class file with a kind not listed here is treated as a non-Kotlin file.
|
||||||
*/
|
*/
|
||||||
val k: Int = 1,
|
@get:JvmName("k")
|
||||||
|
val kind: Int = 1,
|
||||||
/**
|
/**
|
||||||
* The version of the metadata provided in the arguments of this annotation.
|
* The version of the metadata provided in the arguments of this annotation.
|
||||||
*/
|
*/
|
||||||
val mv: IntArray = [],
|
@get:JvmName("mv")
|
||||||
|
val metadataVersion: IntArray = [],
|
||||||
/**
|
/**
|
||||||
* The version of the bytecode interface (naming conventions, signatures) of the class file annotated with this annotation.
|
* The version of the bytecode interface (naming conventions, signatures) of the class file annotated with this annotation.
|
||||||
*/
|
*/
|
||||||
val bv: IntArray = [],
|
@get:JvmName("bv")
|
||||||
|
val bytecodeVersion: IntArray = [],
|
||||||
/**
|
/**
|
||||||
* Metadata in a custom format. The format may be different (or even absent) for different kinds.
|
* Metadata in a custom format. The format may be different (or even absent) for different kinds.
|
||||||
*/
|
*/
|
||||||
val d1: Array<String> = [],
|
@get:JvmName("d1")
|
||||||
|
val data1: Array<String> = [],
|
||||||
/**
|
/**
|
||||||
* An addition to [d1]: array of strings which occur in metadata, written in plain text so that strings already present
|
* An addition to [d1]: array of strings which occur in metadata, written in plain text so that strings already present
|
||||||
* in the constant pool are reused. These strings may be then indexed in the metadata by an integer index in this array.
|
* in the constant pool are reused. These strings may be then indexed in the metadata by an integer index in this array.
|
||||||
*/
|
*/
|
||||||
val d2: Array<String> = [],
|
@get:JvmName("d2")
|
||||||
|
val data2: Array<String> = [],
|
||||||
/**
|
/**
|
||||||
* An extra string. For a multi-file part class, internal name of the facade class.
|
* An extra string. For a multi-file part class, internal name of the facade class.
|
||||||
*/
|
*/
|
||||||
val xs: String = "",
|
@get:JvmName("xs")
|
||||||
|
val extraString: String = "",
|
||||||
/**
|
/**
|
||||||
* Fully qualified name of the package this class is located in, from Kotlin's point of view, or empty string if this name
|
* Fully qualified name of the package this class is located in, from Kotlin's point of view, or empty string if this name
|
||||||
* does not differ from the JVM's package FQ name. These names can be different in case the [JvmPackageName] annotation is used.
|
* does not differ from the JVM's package FQ name. These names can be different in case the [JvmPackageName] annotation is used.
|
||||||
* Note that this information is also stored in the corresponding module's `.kotlin_module` file.
|
* Note that this information is also stored in the corresponding module's `.kotlin_module` file.
|
||||||
*/
|
*/
|
||||||
@SinceKotlin("1.2")
|
@SinceKotlin("1.2")
|
||||||
val pn: String = "",
|
@get:JvmName("pn")
|
||||||
|
val packageName: String = "",
|
||||||
/**
|
/**
|
||||||
* An extra int. Bits of this number represent the following flags:
|
* An extra int. Bits of this number represent the following flags:
|
||||||
*
|
*
|
||||||
@@ -63,5 +70,6 @@ public annotation class Metadata(
|
|||||||
* the major.minor version of this metadata ([mv]).
|
* the major.minor version of this metadata ([mv]).
|
||||||
*/
|
*/
|
||||||
@SinceKotlin("1.1")
|
@SinceKotlin("1.1")
|
||||||
val xi: Int = 0
|
@get:JvmName("xi")
|
||||||
|
val extraInt: Int = 0
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -6,10 +6,7 @@
|
|||||||
package org.jetbrains.kotlin.kotlinp
|
package org.jetbrains.kotlin.kotlinp
|
||||||
|
|
||||||
import kotlinx.metadata.jvm.KotlinClassHeader
|
import kotlinx.metadata.jvm.KotlinClassHeader
|
||||||
import org.objectweb.asm.AnnotationVisitor
|
import org.objectweb.asm.*
|
||||||
import org.objectweb.asm.ClassReader
|
|
||||||
import org.objectweb.asm.ClassVisitor
|
|
||||||
import org.objectweb.asm.Opcodes
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileInputStream
|
import java.io.FileInputStream
|
||||||
|
|
||||||
@@ -17,9 +14,10 @@ internal fun File.readKotlinClassHeader(): KotlinClassHeader? {
|
|||||||
var header: KotlinClassHeader? = null
|
var header: KotlinClassHeader? = null
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
val metadataDesc = Type.getDescriptor(Metadata::class.java)
|
||||||
ClassReader(FileInputStream(this)).accept(object : ClassVisitor(Opcodes.ASM4) {
|
ClassReader(FileInputStream(this)).accept(object : ClassVisitor(Opcodes.ASM4) {
|
||||||
override fun visitAnnotation(desc: String, visible: Boolean): AnnotationVisitor? =
|
override fun visitAnnotation(desc: String, visible: Boolean): AnnotationVisitor? =
|
||||||
if (desc == "Lkotlin/Metadata;") readMetadataVisitor { header = it }
|
if (desc == metadataDesc) readMetadataVisitor { header = it }
|
||||||
else null
|
else null
|
||||||
}, ClassReader.SKIP_CODE or ClassReader.SKIP_DEBUG or ClassReader.SKIP_FRAMES)
|
}, ClassReader.SKIP_CODE or ClassReader.SKIP_DEBUG or ClassReader.SKIP_FRAMES)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
@@ -29,7 +27,6 @@ internal fun File.readKotlinClassHeader(): KotlinClassHeader? {
|
|||||||
return header
|
return header
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
|
|
||||||
private fun readMetadataVisitor(output: (KotlinClassHeader) -> Unit): AnnotationVisitor =
|
private fun readMetadataVisitor(output: (KotlinClassHeader) -> Unit): AnnotationVisitor =
|
||||||
object : AnnotationVisitor(Opcodes.ASM4) {
|
object : AnnotationVisitor(Opcodes.ASM4) {
|
||||||
var kind: Int? = null
|
var kind: Int? = null
|
||||||
@@ -43,19 +40,19 @@ private fun readMetadataVisitor(output: (KotlinClassHeader) -> Unit): Annotation
|
|||||||
|
|
||||||
override fun visit(name: String?, value: Any?) {
|
override fun visit(name: String?, value: Any?) {
|
||||||
when (name) {
|
when (name) {
|
||||||
Metadata::k.name -> kind = value as? Int
|
"k" -> kind = value as? Int
|
||||||
Metadata::mv.name -> metadataVersion = value as? IntArray
|
"mv" -> metadataVersion = value as? IntArray
|
||||||
Metadata::bv.name -> bytecodeVersion = value as? IntArray
|
"bv" -> bytecodeVersion = value as? IntArray
|
||||||
Metadata::xs.name -> extraString = value as? String
|
"xs" -> extraString = value as? String
|
||||||
Metadata::xi.name -> extraInt = value as? Int
|
"xi" -> extraInt = value as? Int
|
||||||
Metadata::pn.name -> packageName = value as? String
|
"pn" -> packageName = value as? String
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitArray(name: String?): AnnotationVisitor? =
|
override fun visitArray(name: String?): AnnotationVisitor? =
|
||||||
when (name) {
|
when (name) {
|
||||||
Metadata::d1.name -> stringArrayVisitor { data1 = it }
|
"d1" -> stringArrayVisitor { data1 = it }
|
||||||
Metadata::d2.name -> stringArrayVisitor { data2 = it }
|
"d2" -> stringArrayVisitor { data2 = it }
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user