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:
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user