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:
+21
@@ -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"
|
||||
}
|
||||
+15
@@ -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})")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user