Don't fail on requesting members of Java collection classes

RuntimeTypeMapper assumed that JavaPropertyDescriptor was necessarily backed by
JavaField, which has changed when we started to load Java method (or a pair of
methods) overriding a Kotlin property as a property, not as a method. Another
example of this situation is special built-in properties which are mapped to
Java methods, e.g. java.util.Collection#size() <-> kotlin.Collection#size. This
change adds support for the case of a property backed by a JavaMethod.

Note that callable references or usage of any reflection API related to
built-in members is not supported anyway and will currently fail with errors

 #KT-11258 Fixed
This commit is contained in:
Alexander Udalov
2016-03-02 13:47:47 +03:00
parent 6429dd4b04
commit 14b1a3a048
5 changed files with 65 additions and 14 deletions
@@ -0,0 +1,21 @@
// FULL_JDK
// See KT-11258 Incorrect resolution sequence for Java field
import java.util.*
fun box(): String {
listOf(
ArrayList::class,
LinkedList::class,
AbstractList::class,
HashSet::class,
TreeSet::class,
HashMap::class,
TreeMap::class,
AbstractMap::class,
AbstractMap.SimpleEntry::class
).map {
it.members.map(Any::toString)
}
return "OK"
}
@@ -4428,6 +4428,21 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode
}
}
}
@TestMetadata("compiler/testData/codegen/boxWithStdlib/reflection/specialBuiltIns")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class SpecialBuiltIns extends AbstractBlackBoxCodegenTest {
public void testAllFilesPresentInSpecialBuiltIns() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxWithStdlib/reflection/specialBuiltIns"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("getMembersOfStandardJavaClasses.kt")
public void testGetMembersOfStandardJavaClasses() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/specialBuiltIns/getMembersOfStandardJavaClasses.kt");
doTestWithStdlib(fileName);
}
}
}
@TestMetadata("compiler/testData/codegen/boxWithStdlib/regressions")
@@ -21,8 +21,7 @@ import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBufUtil
import java.lang.reflect.Field
import kotlin.reflect.jvm.internal.JvmPropertySignature.JavaField
import kotlin.reflect.jvm.internal.JvmPropertySignature.KotlinProperty
import kotlin.reflect.jvm.internal.JvmPropertySignature.*
internal abstract class DescriptorBasedProperty<out R> protected constructor(
override val container: KDeclarationContainerImpl,
@@ -70,6 +69,7 @@ internal abstract class DescriptorBasedProperty<out R> protected constructor(
}
}
is JavaField -> jvmSignature.field
is JavaMethodProperty -> null
}
}
@@ -25,6 +25,7 @@ import java.lang.reflect.Field
import java.lang.reflect.Modifier
import kotlin.reflect.KMutableProperty
import kotlin.reflect.KProperty
import kotlin.reflect.KotlinReflectionInternalError
internal interface KPropertyImpl<out R> : KProperty<R>, KCallableImpl<R> {
val javaField: Field?
@@ -98,10 +99,10 @@ private fun KPropertyImpl.Accessor<*>.computeCallerForAccessor(isGetter: Boolean
}
return false
}
fun isJvmStaticProperty() =
property.descriptor.annotations.findAnnotation(JVM_STATIC) != null
fun isNotNullProperty() =
!TypeUtils.isNullableType(property.descriptor.type)
@@ -150,5 +151,9 @@ private fun KPropertyImpl.Accessor<*>.computeCallerForAccessor(isGetter: Boolean
is JvmPropertySignature.JavaField -> {
computeFieldCaller(jvmSignature.field)
}
is JvmPropertySignature.JavaMethodProperty -> {
if (!isGetter) throw KotlinReflectionInternalError("Setter requested for special built-in $this")
FunctionCaller.InstanceMethod(jvmSignature.method)
}
}
}
@@ -63,10 +63,7 @@ internal sealed class JvmFunctionSignature {
}
class JavaMethod(val method: Method) : JvmFunctionSignature() {
override fun asString(): String =
method.name +
method.parameterTypes.joinToString(separator = "", prefix = "(", postfix = ")") { it.desc } +
method.returnType.desc
override fun asString(): String = method.signature
}
class JavaConstructor(val constructor: Constructor<*>) : JvmFunctionSignature() {
@@ -132,6 +129,10 @@ internal sealed class JvmPropertySignature {
override fun asString(): String = string
}
class JavaMethodProperty(val method: Method) : JvmPropertySignature() {
override fun asString(): String = method.signature
}
class JavaField(val field: Field) : JvmPropertySignature() {
override fun asString(): String =
JvmAbi.getterName(field.name) +
@@ -140,6 +141,11 @@ internal sealed class JvmPropertySignature {
}
}
private val Method.signature: String
get() = name +
parameterTypes.joinToString(separator = "", prefix = "(", postfix = ")") { it.desc } +
returnType.desc
internal object RuntimeTypeMapper {
fun mapSignature(possiblySubstitutedFunction: FunctionDescriptor): JvmFunctionSignature {
// Fake overrides don't have a source element, so we need to take a declaration.
@@ -165,7 +171,7 @@ internal object RuntimeTypeMapper {
}
// 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")
"No metadata found for $function")
}
is JavaMethodDescriptor -> {
val method = ((function.source as? JavaSourceElement)?.javaElement as? ReflectJavaMethod)?.member ?:
@@ -184,21 +190,25 @@ internal object RuntimeTypeMapper {
}
fun mapPropertySignature(possiblyOverriddenProperty: PropertyDescriptor): JvmPropertySignature {
val property = DescriptorUtils.unwrapFakeOverride(possiblyOverriddenProperty)
val property = DescriptorUtils.unwrapFakeOverride(possiblyOverriddenProperty).original
if (property is DeserializedPropertyDescriptor) {
val proto = property.proto
if (!proto.hasExtension(JvmProtoBuf.propertySignature)) {
throw KotlinReflectionInternalError("No metadata found for $property")
// 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")
}
return JvmPropertySignature.KotlinProperty(
property, proto, proto.getExtension(JvmProtoBuf.propertySignature), property.nameResolver, property.typeTable
)
}
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 JvmPropertySignature.JavaField(field)
val element = (property.source as? JavaSourceElement)?.javaElement
when (element) {
is ReflectJavaField -> return JvmPropertySignature.JavaField(element.member)
is ReflectJavaMethod -> return JvmPropertySignature.JavaMethodProperty(element.member)
else -> throw KotlinReflectionInternalError("Incorrect resolution sequence for Java field $property (source = $element)")
}
}
else throw KotlinReflectionInternalError("Unknown origin of $property (${property.javaClass})")
}