From 4c0caad79af907c9ebee3cd4552ea937a47e6e21 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Wed, 22 Jul 2015 22:37:11 +0300 Subject: [PATCH] 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 --- .../jvm/internal/DescriptorBasedProperty.kt | 4 +- .../jvm/internal/KCallableContainerImpl.kt | 4 +- .../reflect/jvm/internal/KFunctionImpl.kt | 2 +- .../reflect/jvm/internal/RuntimeTypeMapper.kt | 158 +++++++++++------- 4 files changed, 105 insertions(+), 63 deletions(-) diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/DescriptorBasedProperty.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/DescriptorBasedProperty.kt index a3872938acd..73d2f6713aa 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/DescriptorBasedProperty.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/DescriptorBasedProperty.kt @@ -38,8 +38,8 @@ abstract class DescriptorBasedProperty protected constructor( constructor(container: KCallableContainerImpl, descriptor: PropertyDescriptor) : this( container, - descriptor.getName().asString(), - RuntimeTypeMapper.mapPropertySignature(descriptor), + descriptor.name.asString(), + RuntimeTypeMapper.mapPropertySignature(descriptor).asString(), descriptor ) diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KCallableContainerImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KCallableContainerImpl.kt index 72fc2c4e479..628b09a9623 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KCallableContainerImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KCallableContainerImpl.kt @@ -110,7 +110,7 @@ abstract class KCallableContainerImpl : KDeclarationContainer { .getProperties(Name.guess(name)) .filter { descriptor -> descriptor is PropertyDescriptor && - RuntimeTypeMapper.mapPropertySignature(descriptor) == signature + RuntimeTypeMapper.mapPropertySignature(descriptor).asString() == signature } if (properties.size() != 1) { @@ -127,7 +127,7 @@ abstract class KCallableContainerImpl : KDeclarationContainer { fun findFunctionDescriptor(name: String, signature: String): FunctionDescriptor { val functions = (if (name == "") constructorDescriptors.toList() else scope.getFunctions(Name.guess(name))) .filter { descriptor -> - RuntimeTypeMapper.mapSignature(descriptor) == signature + RuntimeTypeMapper.mapSignature(descriptor).asString() == signature } if (functions.size() != 1) { diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KFunctionImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KFunctionImpl.kt index bec263df0a3..77abb1ee8a4 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KFunctionImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KFunctionImpl.kt @@ -44,7 +44,7 @@ open class KFunctionImpl protected constructor( constructor(container: KCallableContainerImpl, name: String, signature: String) : this(container, name, signature, null) 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( diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/RuntimeTypeMapper.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/RuntimeTypeMapper.kt index e941413f3c9..545c08a4c39 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/RuntimeTypeMapper.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/RuntimeTypeMapper.kt @@ -31,103 +31,145 @@ import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.platform.JavaToKotlinClassMap import org.jetbrains.kotlin.resolve.descriptorUtil.classId 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.DeserializedPropertyDescriptor 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 -object RuntimeTypeMapper { - fun mapSignature(possiblySubstitutedFunction: FunctionDescriptor): String { - val function = possiblySubstitutedFunction.getOriginal() +interface JvmFunctionSignature { + fun asString(): String - if (function is DeserializedCallableMemberDescriptor) { - val proto = function.proto - if (!proto.hasExtension(JvmProtoBuf.methodSignature)) { + class KotlinFunction( + private val signature: JvmProtoBuf.JvmMethodSignature, + 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 = + "" + + 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 return mapIntrinsicFunctionSignature(function) ?: throw KotlinReflectionInternalError("No metadata found for $function") } - val signature = proto.getExtension(JvmProtoBuf.methodSignature) - return SignatureDeserializer(function.nameResolver).methodSignatureString(signature) - } - else if (function is JavaMethodDescriptor) { - val method = ((function.source as? JavaSourceElement)?.javaElement as? ReflectJavaMethod)?.member ?: - throw KotlinReflectionInternalError("Incorrect resolution sequence for Java method $function") + is JavaMethodDescriptor -> { + val method = ((function.source as? JavaSourceElement)?.javaElement as? ReflectJavaMethod)?.member ?: + throw KotlinReflectionInternalError("Incorrect resolution sequence for Java method $function") - return StringBuilder { - append(method.name) - append("(") - method.parameterTypes.forEach { append(it.desc) } - append(")") - 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 JvmFunctionSignature.JavaMethod(method) + } + is JavaConstructorDescriptor -> { + val constructor = ((function.source as? JavaSourceElement)?.javaElement as? ReflectJavaConstructor)?.member ?: + throw KotlinReflectionInternalError("Incorrect resolution sequence for Java constructor $function") - return StringBuilder { - append("(") - constructor.parameterTypes.forEach { append(it.desc) } - append(")V") - }.toString() + return JvmFunctionSignature.JavaConstructor(constructor) + } + else -> throw KotlinReflectionInternalError("Unknown origin of $function (${function.javaClass})") } - else throw KotlinReflectionInternalError("Unknown origin of $function (${function.javaClass})") } - fun mapPropertySignature(property: PropertyDescriptor): String { + fun mapPropertySignature(property: PropertyDescriptor): JvmPropertySignature { if (property is DeserializedPropertyDescriptor) { val proto = property.proto - val nameResolver = property.nameResolver if (!proto.hasExtension(JvmProtoBuf.propertySignature)) { throw KotlinReflectionInternalError("No metadata found for $property") } - val signature = proto.getExtension(JvmProtoBuf.propertySignature) - 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()) + return JvmPropertySignature.KotlinProperty(proto.getExtension(JvmProtoBuf.propertySignature), property.nameResolver) } else if (property is JavaPropertyDescriptor) { val field = ((property.source as? JavaSourceElement)?.javaElement as? ReflectJavaField)?.member ?: throw KotlinReflectionInternalError("Incorrect resolution sequence for Java field $property") - return StringBuilder { - append(JvmAbi.getterName(field.name)) - append("()") - append(field.type.desc) - }.toString() + return JvmPropertySignature.JavaImaginaryFieldGetter(field) } else throw KotlinReflectionInternalError("Unknown origin of $property (${property.javaClass})") } - private fun mapIntrinsicFunctionSignature(function: FunctionDescriptor): String? { - val parameters = function.getValueParameters() + private fun mapIntrinsicFunctionSignature(function: FunctionDescriptor): JvmFunctionSignature? { + val parameters = function.valueParameters - when (function.getName().asString()) { + when (function.name.asString()) { "equals" -> { - if (parameters.size() == 1 && KotlinBuiltIns.isNullableAny(parameters.single().getType())) { - return "equals(Ljava/lang/Object;)Z" + if (parameters.size() == 1 && KotlinBuiltIns.isNullableAny(parameters.single().type)) { + return JvmFunctionSignature.BuiltInFunction("equals(Ljava/lang/Object;)Z") } } "hashCode" -> { if (parameters.isEmpty()) { - return "hashCode()I" + return JvmFunctionSignature.BuiltInFunction("hashCode()I") } } "toString" -> { if (parameters.isEmpty()) { - return "toString()Ljava/lang/String;" + return JvmFunctionSignature.BuiltInFunction("toString()Ljava/lang/String;") } } // TODO: generalize and support other functions from built-ins