Refactor KClassValue to store ClassLiteralValue internally

Only invariant array projections and non-null element types will be
supported soon (see KT-26568), so it makes no sense to store the
complete type in KClassValue. What we need is only the ClassId of the
class, and the number of times it's wrapped into kotlin/Array, which is
exactly what ClassLiteralValue represents.

This change helps in decoupling annotation values from
descriptors/types. The only constant value that depends on descriptors
is now AnnotationValue.

 #KT-26582 Fixed
This commit is contained in:
Alexander Udalov
2018-09-05 13:22:28 +03:00
parent bad30a4b99
commit c1ab08c8ce
23 changed files with 131 additions and 124 deletions
@@ -28,9 +28,9 @@ import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.*
import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.protobuf.MessageLite
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.constants.*
import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
@@ -63,16 +63,19 @@ internal fun ClassDescriptor.toJavaClass(): Class<*>? {
else -> {
// If this is neither a Kotlin class nor a Java class, it's likely either a built-in or some fake class descriptor like the one
// that's created for java.io.Serializable in JvmBuiltInsSettings
val classId = JavaToKotlinClassMap.mapKotlinToJava(DescriptorUtils.getFqName(this)) ?: classId ?: return null
val packageName = classId.packageFqName.asString()
val className = classId.relativeClassName.asString()
// All pseudo-classes like kotlin.String.Companion must be accessible from the current class loader
loadClass(javaClass.safeClassLoader, packageName, className)
val classId = classId ?: return null
loadClass(javaClass.safeClassLoader, classId, 0)
}
}
}
internal fun loadClass(classLoader: ClassLoader, packageName: String, className: String): Class<*>? {
private fun loadClass(classLoader: ClassLoader, kotlinClassId: ClassId, arrayDimensions: Int = 0): Class<*>? {
val javaClassId = JavaToKotlinClassMap.mapKotlinToJava(kotlinClassId.asSingleFqName().toUnsafe()) ?: kotlinClassId
// All pseudo-classes like kotlin.String.Companion must be accessible from the current class loader
return loadClass(classLoader, javaClassId.packageFqName.asString(), javaClassId.relativeClassName.asString(), arrayDimensions)
}
private fun loadClass(classLoader: ClassLoader, packageName: String, className: String, arrayDimensions: Int): Class<*>? {
if (packageName == "kotlin") {
// See mapBuiltInType() in typeSignatureMapping.kt
when (className) {
@@ -88,7 +91,12 @@ internal fun loadClass(classLoader: ClassLoader, packageName: String, className:
}
}
return classLoader.tryLoadClass("$packageName.${className.replace('.', '$')}")
var fqName = "$packageName.${className.replace('.', '$')}"
repeat(arrayDimensions) {
fqName = "[$fqName"
}
return classLoader.tryLoadClass(fqName)
}
internal fun Visibility.toKVisibility(): KVisibility? =
@@ -128,12 +136,15 @@ private fun ConstantValue<*>.toRuntimeValue(classLoader: ClassLoader): Any? = wh
is ArrayValue -> value.map { it.toRuntimeValue(classLoader) }.toTypedArray()
is EnumValue -> {
val (enumClassId, entryName) = value
loadClass(classLoader, enumClassId.packageFqName.asString(), enumClassId.relativeClassName.asString())?.let { enumClass ->
loadClass(classLoader, enumClassId)?.let { enumClass ->
@Suppress("UNCHECKED_CAST")
Util.getEnumConstantByName(enumClass as Class<out Enum<*>>, entryName.asString())
}
}
is KClassValue -> (value.constructor.declarationDescriptor as? ClassDescriptor)?.toJavaClass()
is KClassValue -> {
val (classId, arrayDimensions) = value
loadClass(classLoader, classId, arrayDimensions)
}
is ErrorValue, is NullValue -> null
else -> value // Primitives and strings
}