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:
@@ -25,6 +25,7 @@ import kotlin.reflect.*
|
||||
import kotlin.reflect.full.companionObject
|
||||
import kotlin.reflect.full.functions
|
||||
import kotlin.reflect.full.memberProperties
|
||||
import kotlin.reflect.jvm.internal.*
|
||||
import kotlin.reflect.jvm.internal.KPackageImpl
|
||||
import kotlin.reflect.jvm.internal.KTypeImpl
|
||||
import kotlin.reflect.jvm.internal.asKCallableImpl
|
||||
@@ -92,14 +93,22 @@ val Field.kotlinProperty: KProperty<*>?
|
||||
get() {
|
||||
if (isSynthetic) return null
|
||||
|
||||
// TODO: optimize (search by name)
|
||||
if (Modifier.isStatic(modifiers)) {
|
||||
val kotlinPackage = getKPackage()
|
||||
if (kotlinPackage != null) {
|
||||
return kotlinPackage.members.findKProperty(this)
|
||||
}
|
||||
|
||||
val kotlinPackage = getKPackage()
|
||||
if (kotlinPackage != null) {
|
||||
return kotlinPackage.members.filterIsInstance<KProperty<*>>().firstOrNull { it.javaField == this }
|
||||
val companionKClass = declaringClass.kotlin.companionObject
|
||||
if (companionKClass != null) {
|
||||
val companionField = declaringClass.getDeclaredFieldOrNull(name)
|
||||
if (companionField != null) {
|
||||
companionKClass.memberProperties.findKProperty(companionField)?.let { return it }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return declaringClass.kotlin.memberProperties.firstOrNull { it.javaField == this }
|
||||
return declaringClass.kotlin.memberProperties.findKProperty(this)
|
||||
}
|
||||
|
||||
|
||||
@@ -119,23 +128,45 @@ val Method.kotlinFunction: KFunction<*>?
|
||||
if (Modifier.isStatic(modifiers)) {
|
||||
val kotlinPackage = getKPackage()
|
||||
if (kotlinPackage != null) {
|
||||
return kotlinPackage.members.filterIsInstance<KFunction<*>>().firstOrNull { it.javaMethod == this }
|
||||
return kotlinPackage.members.findKFunction(this)
|
||||
}
|
||||
|
||||
// For static bridge method generated for a @JvmStatic function in the companion object, also try to find the latter
|
||||
val companion = declaringClass.kotlin.companionObject
|
||||
if (companion != null) {
|
||||
companion.functions.firstOrNull {
|
||||
val m = it.javaMethod
|
||||
m != null && m.name == this.name &&
|
||||
m.parameterTypes.contentEquals(this.parameterTypes) && m.returnType == this.returnType
|
||||
}?.let { return it }
|
||||
val companionKClass = declaringClass.kotlin.companionObject
|
||||
if (companionKClass != null) {
|
||||
val companionMethod = companionKClass.java.getDeclaredMethodOrNull(name, *parameterTypes)
|
||||
if (companionMethod != null) {
|
||||
companionKClass.functions.findKFunction(companionMethod)?.let { return it }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return declaringClass.kotlin.functions.firstOrNull { it.javaMethod == this }
|
||||
return declaringClass.kotlin.functions.findKFunction(this)
|
||||
}
|
||||
|
||||
private fun Collection<KCallable<*>>.findKFunction(method: Method): KFunction<*>? {
|
||||
// As an optimization, try to search among functions with the same name first, and then among the rest of functions.
|
||||
// This is needed because a function's JVM name might be different from its Kotlin name (because of `@JvmName`, inline class mangling,
|
||||
// internal visibility, etc).
|
||||
for (callable in this) {
|
||||
if (callable is KFunction<*> && callable.name == method.name && callable.javaMethod == method) return callable
|
||||
}
|
||||
for (callable in this) {
|
||||
if (callable is KFunction<*> && callable.name != method.name && callable.javaMethod == method) return callable
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun Collection<KCallable<*>>.findKProperty(field: Field): KProperty<*>? {
|
||||
for (callable in this) {
|
||||
if (callable is KProperty<*> && callable.name == field.name && callable.javaField == field) return callable
|
||||
}
|
||||
for (callable in this) {
|
||||
if (callable is KProperty<*> && callable.name != field.name && callable.javaField == field) return callable
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a [KFunction] instance corresponding to the given Java [Constructor] instance,
|
||||
* or `null` if this constructor cannot be represented by a Kotlin function
|
||||
|
||||
@@ -46,6 +46,8 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||
import org.jetbrains.kotlin.resolve.isInlineClassType
|
||||
import org.jetbrains.kotlin.serialization.deserialization.DeserializationContext
|
||||
import org.jetbrains.kotlin.serialization.deserialization.MemberDeserializer
|
||||
import java.lang.reflect.Field
|
||||
import java.lang.reflect.Method
|
||||
import java.lang.reflect.Type
|
||||
import kotlin.jvm.internal.FunctionReference
|
||||
import kotlin.jvm.internal.PropertyReference
|
||||
@@ -308,3 +310,17 @@ internal open class CreateKCallableVisitor(private val container: KDeclarationCo
|
||||
override fun visitFunctionDescriptor(descriptor: FunctionDescriptor, data: Unit): KCallableImpl<*> =
|
||||
KFunctionImpl(container, descriptor)
|
||||
}
|
||||
|
||||
internal fun Class<*>.getDeclaredMethodOrNull(name: String, vararg parameterTypes: Class<*>): Method? =
|
||||
try {
|
||||
getDeclaredMethod(name, *parameterTypes)
|
||||
} catch (e: NoSuchMethodException) {
|
||||
null
|
||||
}
|
||||
|
||||
internal fun Class<*>.getDeclaredFieldOrNull(name: String): Field? =
|
||||
try {
|
||||
getDeclaredField(name)
|
||||
} catch (e: NoSuchFieldException) {
|
||||
null
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user