Use manual type mapping in reflection for members from built-ins

There are cases when members deserialized from JVM classes have no JVM
signature in the proto. For example, if a member is inherited from a
built-in class (such as Map.getOrDefault in some Map implementations),
or if a member is synthesized in the compiler front-end and back-end
separately (such as enum values/valueOf). In these cases, we'll use the
naive type mapping to try to recover the signature.

 #KT-16616 Fixed
 #KT-17542 Fixed
This commit is contained in:
Alexander Udalov
2018-01-05 15:23:49 +01:00
parent a7c80f2df1
commit 4266e50be8
15 changed files with 347 additions and 161 deletions
@@ -75,6 +75,7 @@ internal abstract class KPropertyImpl<out R> private constructor(
}
is JavaField -> jvmSignature.field
is JavaMethodProperty -> null
is MappedKotlinProperty -> null
}
}
@@ -268,5 +269,19 @@ private fun KPropertyImpl.Accessor<*, *>.computeCallerForAccessor(isGetter: Bool
if (isBound) FunctionCaller.BoundInstanceMethod(method, property.boundReceiver)
else FunctionCaller.InstanceMethod(method)
}
is MappedKotlinProperty -> {
val signature =
if (isGetter) jvmSignature.getterSignature
else (jvmSignature.setterSignature
?: throw KotlinReflectionInternalError("No setter found for property $property"))
val accessor = property.container.findMethodBySignature(
signature.methodName, signature.methodDesc, descriptor.isPublicInBytecode
) ?: throw KotlinReflectionInternalError("No accessor found for property $property")
assert(!Modifier.isStatic(accessor.modifiers)) { "Mapped property cannot have a static accessor: $property" }
return if (isBound) FunctionCaller.BoundInstanceMethod(accessor, property.boundReceiver)
else FunctionCaller.InstanceMethod(accessor)
}
}
}
@@ -18,16 +18,15 @@ package kotlin.reflect.jvm.internal
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.PrimitiveType
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.load.java.descriptors.JavaClassConstructorDescriptor
import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor
import org.jetbrains.kotlin.load.java.descriptors.JavaPropertyDescriptor
import org.jetbrains.kotlin.load.java.getJvmMethodNameIfSpecial
import org.jetbrains.kotlin.load.java.sources.JavaSourceElement
import org.jetbrains.kotlin.load.kotlin.JvmPackagePartSource
import org.jetbrains.kotlin.load.kotlin.computeJvmDescriptor
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.NameResolver
import org.jetbrains.kotlin.metadata.deserialization.TypeTable
@@ -39,7 +38,9 @@ import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.NameUtils
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
import org.jetbrains.kotlin.resolve.DescriptorFactory
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.propertyIfAccessor
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor
@@ -150,6 +151,13 @@ internal sealed class JvmPropertySignature {
override fun asString(): String =
JvmAbi.getterName(field.name) + "()" + field.type.desc
}
class MappedKotlinProperty(
val getterSignature: JvmFunctionSignature.KotlinFunction,
val setterSignature: JvmFunctionSignature.KotlinFunction?
) : JvmPropertySignature() {
override fun asString(): String = getterSignature.asString()
}
}
private val Method.signature: String
@@ -182,10 +190,7 @@ internal object RuntimeTypeMapper {
return JvmFunctionSignature.KotlinConstructor(signature)
}
}
// If it's a deserialized function but has no JVM signature, it must be from built-ins
throw KotlinReflectionInternalError(
"Reflection on built-in Kotlin types is not yet fully supported. No metadata found for $function"
)
return mapJvmFunctionSignature(function)
}
is JavaMethodDescriptor -> {
val method = ((function.source as? JavaSourceElement)?.javaElement as? ReflectJavaMethod)?.member
@@ -203,25 +208,28 @@ internal object RuntimeTypeMapper {
else -> throw KotlinReflectionInternalError("Incorrect resolution sequence for Java constructor $function ($element)")
}
}
else -> throw KotlinReflectionInternalError("Unknown origin of $function (${function.javaClass})")
}
if (DescriptorFactory.isEnumValueOfMethod(function) || DescriptorFactory.isEnumValuesMethod(function)) {
return mapJvmFunctionSignature(function)
}
throw KotlinReflectionInternalError("Unknown origin of $function (${function.javaClass})")
}
fun mapPropertySignature(possiblyOverriddenProperty: PropertyDescriptor): JvmPropertySignature {
val property = DescriptorUtils.unwrapFakeOverride(possiblyOverriddenProperty).original
return when (property) {
when (property) {
is DeserializedPropertyDescriptor -> {
val proto = property.proto
val signature = proto.getExtensionOrNull(JvmProtoBuf.propertySignature)
?: // If this property has no JVM signature, it must be from built-ins
throw KotlinReflectionInternalError(
"Reflection on built-in Kotlin types is not yet fully supported. No metadata found for $property"
)
JvmPropertySignature.KotlinProperty(property, proto, signature, property.nameResolver, property.typeTable)
if (signature != null) {
return JvmPropertySignature.KotlinProperty(property, proto, signature, property.nameResolver, property.typeTable)
}
}
is JavaPropertyDescriptor -> {
val element = (property.source as? JavaSourceElement)?.javaElement
when (element) {
return when (element) {
is ReflectJavaField -> JvmPropertySignature.JavaField(element.member)
is ReflectJavaMethod -> JvmPropertySignature.JavaMethodProperty(
element.member,
@@ -230,12 +238,26 @@ internal object RuntimeTypeMapper {
else -> throw KotlinReflectionInternalError("Incorrect resolution sequence for Java field $property (source = $element)")
}
}
else -> {
throw KotlinReflectionInternalError("Unknown origin of $property (${property.javaClass})")
}
}
return JvmPropertySignature.MappedKotlinProperty(
property.getter!!.let(this::mapJvmFunctionSignature),
property.setter?.let(this::mapJvmFunctionSignature)
)
}
private fun mapJvmFunctionSignature(descriptor: FunctionDescriptor): JvmFunctionSignature.KotlinFunction =
JvmFunctionSignature.KotlinFunction(
JvmMemberSignature.Method(mapName(descriptor), descriptor.computeJvmDescriptor(withName = false))
)
private fun mapName(descriptor: CallableMemberDescriptor): String =
getJvmMethodNameIfSpecial(descriptor) ?: when (descriptor) {
is PropertyGetterDescriptor -> JvmAbi.getterName(descriptor.propertyIfAccessor.name.asString())
is PropertySetterDescriptor -> JvmAbi.setterName(descriptor.propertyIfAccessor.name.asString())
else -> descriptor.name.asString()
}
private fun mapIntrinsicFunctionSignature(function: FunctionDescriptor): JvmFunctionSignature? {
val parameters = function.valueParameters