Reflection: improve and optimize kotlinFunction/kotlinProperty
- Make the implementations very similar, to fix KT-54833 where the companion object case was forgotten for kotlinProperty. - Optimize both functions to look up the function/property by name first, to cover the most probable case when the JVM name of a declaration is equal to its Kotlin name. This fixes KT-55937. #KT-54833 Fixed #KT-55937 Fixed
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
// WITH_REFLECT
|
||||
// TARGET_BACKEND: JVM
|
||||
|
||||
import kotlin.reflect.KProperty1
|
||||
import kotlin.reflect.jvm.kotlinProperty
|
||||
|
||||
class C {
|
||||
companion object {
|
||||
val x = "OK"
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val f = C::class.java.getDeclaredField("x").kotlinProperty as KProperty1<C.Companion, String>
|
||||
return f.get(C.Companion)
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
// WITH_REFLECT
|
||||
// TARGET_BACKEND: JVM
|
||||
|
||||
import kotlin.reflect.KFunction
|
||||
import kotlin.reflect.jvm.javaMethod
|
||||
import kotlin.reflect.jvm.kotlinFunction
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class A {
|
||||
@JvmName("jvmFoo")
|
||||
fun foo(s: String): Int = s.length
|
||||
|
||||
fun mangled(z: Z): Number = z.value
|
||||
|
||||
internal fun internal(s: String): Int = s.length
|
||||
|
||||
|
||||
// Some different members with similar JVM signatures, to check that kotlinFunction doesn't incorrectly resolve into one of these.
|
||||
private fun jvmFoo(s: String): String = s
|
||||
private fun `mangled-IQRRRT4`(z: Number) {}
|
||||
private fun `internal$main`(s: String): String = s
|
||||
}
|
||||
|
||||
@JvmInline
|
||||
value class Z(val value: Number)
|
||||
|
||||
fun test(f: KFunction<*>) {
|
||||
val javaMethod = f.javaMethod
|
||||
?: error("javaMethod == null for $f")
|
||||
assertEquals(f, javaMethod.kotlinFunction, "Incorrect kotlinFunction for $javaMethod")
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
test(A::foo)
|
||||
test(A::mangled)
|
||||
test(A::internal)
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
// WITH_REFLECT
|
||||
// TARGET_BACKEND: JVM
|
||||
|
||||
import kotlin.reflect.KProperty
|
||||
import kotlin.reflect.full.declaredMemberProperties
|
||||
import kotlin.reflect.jvm.javaField
|
||||
import kotlin.reflect.jvm.kotlinProperty
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class A {
|
||||
val x = "outer" // NB: backing field of this property has the name `x$1`, to avoid conflict with public field moved from companion.
|
||||
val y = "outer" // Same here, `y$1`.
|
||||
|
||||
companion object {
|
||||
@JvmField
|
||||
val x = "companion"
|
||||
|
||||
const val y = "companion"
|
||||
}
|
||||
}
|
||||
|
||||
fun test(f: KProperty<*>) {
|
||||
val javaField = f.javaField
|
||||
?: error("javaField == null for $f")
|
||||
|
||||
assertEquals(f, javaField.kotlinProperty, "Incorrect kotlinProperty for $javaField")
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
test(A::x)
|
||||
test(A::y)
|
||||
|
||||
// We have to use reflection API to get companion object properties if we want to test the invariant `p.javaField.kotlinProperty == p`.
|
||||
// If we used the callable reference syntax instead `A.Companion::x`, we'd get a bound property reference, which is an instance of
|
||||
// `KProperty0`. Whereas `kotlinProperty` always return unbound reference, so a `KProperty1`.
|
||||
test(A.Companion::class.declaredMemberProperties.single { it.name == "x" })
|
||||
test(A.Companion::class.declaredMemberProperties.single { it.name == "y" })
|
||||
|
||||
return "OK"
|
||||
}
|
||||
Reference in New Issue
Block a user