Refactor RuntimeTypeMapper, introduce JVM signature classes

Currently only used to obtain the string identical to the one which would be
produced by JetTypeMapper.mapSignature, but soon will be used to obtain
corresponding reflection objects from classes
This commit is contained in:
Alexander Udalov
2015-07-22 22:37:11 +03:00
parent e079b8f425
commit 4c0caad79a
4 changed files with 105 additions and 63 deletions
@@ -38,8 +38,8 @@ abstract class DescriptorBasedProperty<out R> protected constructor(
constructor(container: KCallableContainerImpl, descriptor: PropertyDescriptor) : this( constructor(container: KCallableContainerImpl, descriptor: PropertyDescriptor) : this(
container, container,
descriptor.getName().asString(), descriptor.name.asString(),
RuntimeTypeMapper.mapPropertySignature(descriptor), RuntimeTypeMapper.mapPropertySignature(descriptor).asString(),
descriptor descriptor
) )
@@ -110,7 +110,7 @@ abstract class KCallableContainerImpl : KDeclarationContainer {
.getProperties(Name.guess(name)) .getProperties(Name.guess(name))
.filter { descriptor -> .filter { descriptor ->
descriptor is PropertyDescriptor && descriptor is PropertyDescriptor &&
RuntimeTypeMapper.mapPropertySignature(descriptor) == signature RuntimeTypeMapper.mapPropertySignature(descriptor).asString() == signature
} }
if (properties.size() != 1) { if (properties.size() != 1) {
@@ -127,7 +127,7 @@ abstract class KCallableContainerImpl : KDeclarationContainer {
fun findFunctionDescriptor(name: String, signature: String): FunctionDescriptor { fun findFunctionDescriptor(name: String, signature: String): FunctionDescriptor {
val functions = (if (name == "<init>") constructorDescriptors.toList() else scope.getFunctions(Name.guess(name))) val functions = (if (name == "<init>") constructorDescriptors.toList() else scope.getFunctions(Name.guess(name)))
.filter { descriptor -> .filter { descriptor ->
RuntimeTypeMapper.mapSignature(descriptor) == signature RuntimeTypeMapper.mapSignature(descriptor).asString() == signature
} }
if (functions.size() != 1) { if (functions.size() != 1) {
@@ -44,7 +44,7 @@ open class KFunctionImpl protected constructor(
constructor(container: KCallableContainerImpl, name: String, signature: String) : this(container, name, signature, null) constructor(container: KCallableContainerImpl, name: String, signature: String) : this(container, name, signature, null)
constructor(container: KCallableContainerImpl, descriptor: FunctionDescriptor) : this( constructor(container: KCallableContainerImpl, descriptor: FunctionDescriptor) : this(
container, descriptor.getName().asString(), RuntimeTypeMapper.mapSignature(descriptor), descriptor container, descriptor.name.asString(), RuntimeTypeMapper.mapSignature(descriptor).asString(), descriptor
) )
private data class FunctionProtoData( private data class FunctionProtoData(
@@ -31,103 +31,145 @@ import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
import org.jetbrains.kotlin.resolve.descriptorUtil.classId import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
import org.jetbrains.kotlin.serialization.deserialization.NameResolver
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf
import java.lang.reflect.Constructor
import java.lang.reflect.Field
import java.lang.reflect.Method
import kotlin.reflect.KotlinReflectionInternalError import kotlin.reflect.KotlinReflectionInternalError
object RuntimeTypeMapper { interface JvmFunctionSignature {
fun mapSignature(possiblySubstitutedFunction: FunctionDescriptor): String { fun asString(): String
val function = possiblySubstitutedFunction.getOriginal()
if (function is DeserializedCallableMemberDescriptor) { class KotlinFunction(
val proto = function.proto private val signature: JvmProtoBuf.JvmMethodSignature,
if (!proto.hasExtension(JvmProtoBuf.methodSignature)) { private val nameResolver: NameResolver
) : JvmFunctionSignature {
override fun asString(): String =
SignatureDeserializer(nameResolver).methodSignatureString(signature)
}
class JavaMethod(private val method: Method) : JvmFunctionSignature {
override fun asString(): String =
method.name +
method.parameterTypes.joinToString(separator = "", prefix = "(", postfix = ")") { it.desc } +
method.returnType.desc
}
class JavaConstructor(private val constructor: Constructor<*>) : JvmFunctionSignature {
override fun asString(): String =
"<init>" +
constructor.parameterTypes.joinToString(separator = "", prefix = "(", postfix = ")") { it.desc } +
"V"
}
class BuiltInFunction(private val signature: String) : JvmFunctionSignature {
override fun asString(): String = signature
}
}
interface JvmPropertySignature {
/**
* Returns the JVM signature of the getter of this property. In case the property doesn't have a getter,
* constructs the signature of its imaginary default getter. See CallableReference#getSignature for more information
*/
fun asString(): String
class KotlinProperty(
private val signature: JvmProtoBuf.JvmPropertySignature,
private val nameResolver: NameResolver
) : JvmPropertySignature {
private val string: String
init {
if (signature.hasGetter()) {
string = JvmFunctionSignature.KotlinFunction(signature.getter, nameResolver).asString()
}
else {
string = JvmAbi.getterName(nameResolver.getString(signature.field.name)) +
"()" +
SignatureDeserializer(nameResolver).typeDescriptor(signature.field.type)
}
}
override fun asString(): String = string
}
class JavaImaginaryFieldGetter(private val field: Field) : JvmPropertySignature {
override fun asString(): String =
JvmAbi.getterName(field.name) +
"()" +
field.type.desc
}
}
object RuntimeTypeMapper {
fun mapSignature(possiblySubstitutedFunction: FunctionDescriptor): JvmFunctionSignature {
val function = possiblySubstitutedFunction.original
when (function) {
is DeserializedCallableMemberDescriptor -> {
val proto = function.proto
if (proto.hasExtension(JvmProtoBuf.methodSignature)) {
val signature = proto.getExtension(JvmProtoBuf.methodSignature)
return JvmFunctionSignature.KotlinFunction(signature, function.nameResolver)
}
// If it's a deserialized function but has no JVM signature, it must be from built-ins // If it's a deserialized function but has no JVM signature, it must be from built-ins
return mapIntrinsicFunctionSignature(function) ?: return mapIntrinsicFunctionSignature(function) ?:
throw KotlinReflectionInternalError("No metadata found for $function") throw KotlinReflectionInternalError("No metadata found for $function")
} }
val signature = proto.getExtension(JvmProtoBuf.methodSignature) is JavaMethodDescriptor -> {
return SignatureDeserializer(function.nameResolver).methodSignatureString(signature) val method = ((function.source as? JavaSourceElement)?.javaElement as? ReflectJavaMethod)?.member ?:
} throw KotlinReflectionInternalError("Incorrect resolution sequence for Java method $function")
else if (function is JavaMethodDescriptor) {
val method = ((function.source as? JavaSourceElement)?.javaElement as? ReflectJavaMethod)?.member ?:
throw KotlinReflectionInternalError("Incorrect resolution sequence for Java method $function")
return StringBuilder { return JvmFunctionSignature.JavaMethod(method)
append(method.name) }
append("(") is JavaConstructorDescriptor -> {
method.parameterTypes.forEach { append(it.desc) } val constructor = ((function.source as? JavaSourceElement)?.javaElement as? ReflectJavaConstructor)?.member ?:
append(")") throw KotlinReflectionInternalError("Incorrect resolution sequence for Java constructor $function")
append(method.returnType.desc)
}.toString()
}
else if (function is JavaConstructorDescriptor) {
val constructor = ((function.source as? JavaSourceElement)?.javaElement as? ReflectJavaConstructor)?.member ?:
throw KotlinReflectionInternalError("Incorrect resolution sequence for Java constructor $function")
return StringBuilder { return JvmFunctionSignature.JavaConstructor(constructor)
append("<init>(") }
constructor.parameterTypes.forEach { append(it.desc) } else -> throw KotlinReflectionInternalError("Unknown origin of $function (${function.javaClass})")
append(")V")
}.toString()
} }
else throw KotlinReflectionInternalError("Unknown origin of $function (${function.javaClass})")
} }
fun mapPropertySignature(property: PropertyDescriptor): String { fun mapPropertySignature(property: PropertyDescriptor): JvmPropertySignature {
if (property is DeserializedPropertyDescriptor) { if (property is DeserializedPropertyDescriptor) {
val proto = property.proto val proto = property.proto
val nameResolver = property.nameResolver
if (!proto.hasExtension(JvmProtoBuf.propertySignature)) { if (!proto.hasExtension(JvmProtoBuf.propertySignature)) {
throw KotlinReflectionInternalError("No metadata found for $property") throw KotlinReflectionInternalError("No metadata found for $property")
} }
val signature = proto.getExtension(JvmProtoBuf.propertySignature) return JvmPropertySignature.KotlinProperty(proto.getExtension(JvmProtoBuf.propertySignature), property.nameResolver)
val deserializer = SignatureDeserializer(nameResolver)
if (signature.hasGetter()) {
return deserializer.methodSignatureString(signature.getGetter())
}
// In case the property doesn't have a getter, construct the signature of its imaginary default getter.
// See PropertyReference#getSignature
val field = signature.getField()
// TODO: some kind of test on the Java Bean convention?
return JvmAbi.getterName(nameResolver.getString(field.getName())) +
"()" +
deserializer.typeDescriptor(field.getType())
} }
else if (property is JavaPropertyDescriptor) { else if (property is JavaPropertyDescriptor) {
val field = ((property.source as? JavaSourceElement)?.javaElement as? ReflectJavaField)?.member ?: val field = ((property.source as? JavaSourceElement)?.javaElement as? ReflectJavaField)?.member ?:
throw KotlinReflectionInternalError("Incorrect resolution sequence for Java field $property") throw KotlinReflectionInternalError("Incorrect resolution sequence for Java field $property")
return StringBuilder { return JvmPropertySignature.JavaImaginaryFieldGetter(field)
append(JvmAbi.getterName(field.name))
append("()")
append(field.type.desc)
}.toString()
} }
else throw KotlinReflectionInternalError("Unknown origin of $property (${property.javaClass})") else throw KotlinReflectionInternalError("Unknown origin of $property (${property.javaClass})")
} }
private fun mapIntrinsicFunctionSignature(function: FunctionDescriptor): String? { private fun mapIntrinsicFunctionSignature(function: FunctionDescriptor): JvmFunctionSignature? {
val parameters = function.getValueParameters() val parameters = function.valueParameters
when (function.getName().asString()) { when (function.name.asString()) {
"equals" -> { "equals" -> {
if (parameters.size() == 1 && KotlinBuiltIns.isNullableAny(parameters.single().getType())) { if (parameters.size() == 1 && KotlinBuiltIns.isNullableAny(parameters.single().type)) {
return "equals(Ljava/lang/Object;)Z" return JvmFunctionSignature.BuiltInFunction("equals(Ljava/lang/Object;)Z")
} }
} }
"hashCode" -> { "hashCode" -> {
if (parameters.isEmpty()) { if (parameters.isEmpty()) {
return "hashCode()I" return JvmFunctionSignature.BuiltInFunction("hashCode()I")
} }
} }
"toString" -> { "toString" -> {
if (parameters.isEmpty()) { if (parameters.isEmpty()) {
return "toString()Ljava/lang/String;" return JvmFunctionSignature.BuiltInFunction("toString()Ljava/lang/String;")
} }
} }
// TODO: generalize and support other functions from built-ins // TODO: generalize and support other functions from built-ins