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")
|
@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.load.java.JvmAbi
|
||||||
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBufUtil
|
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBufUtil
|
||||||
import java.lang.reflect.Field
|
import java.lang.reflect.Field
|
||||||
import kotlin.reflect.jvm.internal.JvmPropertySignature.JavaField
|
import kotlin.reflect.jvm.internal.JvmPropertySignature.*
|
||||||
import kotlin.reflect.jvm.internal.JvmPropertySignature.KotlinProperty
|
|
||||||
|
|
||||||
internal abstract class DescriptorBasedProperty<out R> protected constructor(
|
internal abstract class DescriptorBasedProperty<out R> protected constructor(
|
||||||
override val container: KDeclarationContainerImpl,
|
override val container: KDeclarationContainerImpl,
|
||||||
@@ -70,6 +69,7 @@ internal abstract class DescriptorBasedProperty<out R> protected constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
is JavaField -> jvmSignature.field
|
is JavaField -> jvmSignature.field
|
||||||
|
is JavaMethodProperty -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import java.lang.reflect.Field
|
|||||||
import java.lang.reflect.Modifier
|
import java.lang.reflect.Modifier
|
||||||
import kotlin.reflect.KMutableProperty
|
import kotlin.reflect.KMutableProperty
|
||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
|
import kotlin.reflect.KotlinReflectionInternalError
|
||||||
|
|
||||||
internal interface KPropertyImpl<out R> : KProperty<R>, KCallableImpl<R> {
|
internal interface KPropertyImpl<out R> : KProperty<R>, KCallableImpl<R> {
|
||||||
val javaField: Field?
|
val javaField: Field?
|
||||||
@@ -98,10 +99,10 @@ private fun KPropertyImpl.Accessor<*>.computeCallerForAccessor(isGetter: Boolean
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isJvmStaticProperty() =
|
fun isJvmStaticProperty() =
|
||||||
property.descriptor.annotations.findAnnotation(JVM_STATIC) != null
|
property.descriptor.annotations.findAnnotation(JVM_STATIC) != null
|
||||||
|
|
||||||
|
|
||||||
fun isNotNullProperty() =
|
fun isNotNullProperty() =
|
||||||
!TypeUtils.isNullableType(property.descriptor.type)
|
!TypeUtils.isNullableType(property.descriptor.type)
|
||||||
|
|
||||||
@@ -150,5 +151,9 @@ private fun KPropertyImpl.Accessor<*>.computeCallerForAccessor(isGetter: Boolean
|
|||||||
is JvmPropertySignature.JavaField -> {
|
is JvmPropertySignature.JavaField -> {
|
||||||
computeFieldCaller(jvmSignature.field)
|
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() {
|
class JavaMethod(val method: Method) : JvmFunctionSignature() {
|
||||||
override fun asString(): String =
|
override fun asString(): String = method.signature
|
||||||
method.name +
|
|
||||||
method.parameterTypes.joinToString(separator = "", prefix = "(", postfix = ")") { it.desc } +
|
|
||||||
method.returnType.desc
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class JavaConstructor(val constructor: Constructor<*>) : JvmFunctionSignature() {
|
class JavaConstructor(val constructor: Constructor<*>) : JvmFunctionSignature() {
|
||||||
@@ -132,6 +129,10 @@ internal sealed class JvmPropertySignature {
|
|||||||
override fun asString(): String = string
|
override fun asString(): String = string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class JavaMethodProperty(val method: Method) : JvmPropertySignature() {
|
||||||
|
override fun asString(): String = method.signature
|
||||||
|
}
|
||||||
|
|
||||||
class JavaField(val field: Field) : JvmPropertySignature() {
|
class JavaField(val field: Field) : JvmPropertySignature() {
|
||||||
override fun asString(): String =
|
override fun asString(): String =
|
||||||
JvmAbi.getterName(field.name) +
|
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 {
|
internal object RuntimeTypeMapper {
|
||||||
fun mapSignature(possiblySubstitutedFunction: FunctionDescriptor): JvmFunctionSignature {
|
fun mapSignature(possiblySubstitutedFunction: FunctionDescriptor): JvmFunctionSignature {
|
||||||
// Fake overrides don't have a source element, so we need to take a declaration.
|
// 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
|
// 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. " +
|
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 -> {
|
is JavaMethodDescriptor -> {
|
||||||
val method = ((function.source as? JavaSourceElement)?.javaElement as? ReflectJavaMethod)?.member ?:
|
val method = ((function.source as? JavaSourceElement)?.javaElement as? ReflectJavaMethod)?.member ?:
|
||||||
@@ -184,21 +190,25 @@ internal object RuntimeTypeMapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun mapPropertySignature(possiblyOverriddenProperty: PropertyDescriptor): JvmPropertySignature {
|
fun mapPropertySignature(possiblyOverriddenProperty: PropertyDescriptor): JvmPropertySignature {
|
||||||
val property = DescriptorUtils.unwrapFakeOverride(possiblyOverriddenProperty)
|
val property = DescriptorUtils.unwrapFakeOverride(possiblyOverriddenProperty).original
|
||||||
if (property is DeserializedPropertyDescriptor) {
|
if (property is DeserializedPropertyDescriptor) {
|
||||||
val proto = property.proto
|
val proto = property.proto
|
||||||
if (!proto.hasExtension(JvmProtoBuf.propertySignature)) {
|
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(
|
return JvmPropertySignature.KotlinProperty(
|
||||||
property, proto, proto.getExtension(JvmProtoBuf.propertySignature), property.nameResolver, property.typeTable
|
property, proto, proto.getExtension(JvmProtoBuf.propertySignature), property.nameResolver, property.typeTable
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
else if (property is JavaPropertyDescriptor) {
|
else if (property is JavaPropertyDescriptor) {
|
||||||
val field = ((property.source as? JavaSourceElement)?.javaElement as? ReflectJavaField)?.member ?:
|
val element = (property.source as? JavaSourceElement)?.javaElement
|
||||||
throw KotlinReflectionInternalError("Incorrect resolution sequence for Java field $property")
|
when (element) {
|
||||||
|
is ReflectJavaField -> return JvmPropertySignature.JavaField(element.member)
|
||||||
return JvmPropertySignature.JavaField(field)
|
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})")
|
else throw KotlinReflectionInternalError("Unknown origin of $property (${property.javaClass})")
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user