KT-13440 Bound callable references in reflection
This commit is contained in:
@@ -67,16 +67,30 @@ internal abstract class FunctionCaller<out M : Member?>(
|
||||
}
|
||||
}
|
||||
|
||||
// TODO fix 'callBy' for bound (and non-bound) inner class constructor references
|
||||
// See https://youtrack.jetbrains.com/issue/KT-14990
|
||||
class BoundConstructor(constructor: ReflectConstructor<*>, private val boundReceiver: Any?) :
|
||||
FunctionCaller<ReflectConstructor<*>>(
|
||||
constructor, constructor.declaringClass, null,
|
||||
constructor.genericParameterTypes
|
||||
) {
|
||||
override fun call(args: Array<*>): Any? {
|
||||
checkArguments(args)
|
||||
return member.newInstance(*argsWithReceiver(boundReceiver, args))
|
||||
}
|
||||
}
|
||||
|
||||
// Methods
|
||||
|
||||
abstract class Method(
|
||||
method: ReflectMethod,
|
||||
requiresInstance: Boolean = !Modifier.isStatic(method.modifiers)
|
||||
requiresInstance: Boolean = !Modifier.isStatic(method.modifiers),
|
||||
parameterTypes: Array<Type> = method.genericParameterTypes
|
||||
) : FunctionCaller<ReflectMethod>(
|
||||
method,
|
||||
method.genericReturnType,
|
||||
if (requiresInstance) method.declaringClass else null,
|
||||
method.genericParameterTypes
|
||||
parameterTypes
|
||||
) {
|
||||
private val isVoidMethod = returnType == Void.TYPE
|
||||
|
||||
@@ -98,7 +112,7 @@ internal abstract class FunctionCaller<out M : Member?>(
|
||||
class InstanceMethod(method: ReflectMethod) : Method(method) {
|
||||
override fun call(args: Array<*>): Any? {
|
||||
checkArguments(args)
|
||||
return callMethod(args[0], args.copyOfRange(1, args.size))
|
||||
return callMethod(args[0], args.dropFirstArg())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,7 +120,31 @@ internal abstract class FunctionCaller<out M : Member?>(
|
||||
override fun call(args: Array<*>): Any? {
|
||||
checkArguments(args)
|
||||
checkObjectInstance(args.firstOrNull())
|
||||
return callMethod(null, args.copyOfRange(1, args.size))
|
||||
return callMethod(null, args.dropFirstArg())
|
||||
}
|
||||
}
|
||||
|
||||
class BoundStaticMethod(method: ReflectMethod, private val boundReceiver: Any?) :
|
||||
Method(method, requiresInstance = false, parameterTypes = method.genericParameterTypes.dropFirst()) {
|
||||
override fun call(args: Array<*>): Any? {
|
||||
checkArguments(args)
|
||||
return callMethod(null, argsWithReceiver(boundReceiver, args))
|
||||
}
|
||||
}
|
||||
|
||||
class BoundInstanceMethod(method: ReflectMethod, private val boundReceiver: Any?) :
|
||||
Method(method, requiresInstance = false) {
|
||||
override fun call(args: Array<*>): Any? {
|
||||
checkArguments(args)
|
||||
return callMethod(boundReceiver, args)
|
||||
}
|
||||
}
|
||||
|
||||
class BoundJvmStaticInObject(method: ReflectMethod) :
|
||||
Method(method, requiresInstance = false) {
|
||||
override fun call(args: Array<*>): Any? {
|
||||
checkArguments(args)
|
||||
return callMethod(null, args)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,21 +199,32 @@ internal abstract class FunctionCaller<out M : Member?>(
|
||||
}
|
||||
}
|
||||
|
||||
class ClassCompanionFieldGetter(
|
||||
field: ReflectField,
|
||||
klass: Class<*>
|
||||
) : FunctionCaller<ReflectField>(
|
||||
field,
|
||||
field.genericType,
|
||||
klass,
|
||||
emptyArray()
|
||||
) {
|
||||
class ClassCompanionFieldGetter(field: ReflectField, klass: Class<*>) :
|
||||
FunctionCaller<ReflectField>(field, field.genericType, klass, emptyArray()) {
|
||||
override fun call(args: Array<*>): Any? {
|
||||
checkArguments(args)
|
||||
return member.get(args.first())
|
||||
}
|
||||
}
|
||||
|
||||
class BoundInstanceFieldGetter(field: ReflectField, private val boundReceiver: Any?) :
|
||||
FieldGetter(field, requiresInstance = false) {
|
||||
override fun call(args: Array<*>): Any? {
|
||||
checkArguments(args)
|
||||
return member.get(boundReceiver)
|
||||
}
|
||||
}
|
||||
|
||||
class BoundJvmStaticInObjectFieldGetter(field: ReflectField) : FieldGetter(field, requiresInstance = false)
|
||||
|
||||
class BoundClassCompanionFieldGetter(field: ReflectField, private val boundReceiver: Any?) :
|
||||
FieldGetter(field, requiresInstance = false) {
|
||||
override fun call(args: Array<*>): Any? {
|
||||
checkArguments(args)
|
||||
return member.get(boundReceiver)
|
||||
}
|
||||
}
|
||||
|
||||
class StaticFieldSetter(field: ReflectField, notNull: Boolean) : FieldSetter(field, notNull)
|
||||
|
||||
class InstanceFieldSetter(field: ReflectField, notNull: Boolean) : FieldSetter(field, notNull)
|
||||
@@ -187,18 +236,53 @@ internal abstract class FunctionCaller<out M : Member?>(
|
||||
}
|
||||
}
|
||||
|
||||
class ClassCompanionFieldSetter(
|
||||
field: ReflectField,
|
||||
klass: Class<*>
|
||||
) : FunctionCaller<ReflectField>(
|
||||
field,
|
||||
Void.TYPE,
|
||||
klass,
|
||||
arrayOf(field.genericType)
|
||||
) {
|
||||
class ClassCompanionFieldSetter(field: ReflectField, klass: Class<*>) :
|
||||
FunctionCaller<ReflectField>(field, Void.TYPE, klass, arrayOf(field.genericType)) {
|
||||
override fun call(args: Array<*>): Any? {
|
||||
checkArguments(args)
|
||||
return member.set(instanceClass, args.last())
|
||||
return member.set(null, args.last())
|
||||
}
|
||||
}
|
||||
|
||||
class BoundInstanceFieldSetter(field: ReflectField, notNull: Boolean, private val boundReceiver: Any?) :
|
||||
FieldSetter(field, notNull, false) {
|
||||
override fun call(args: Array<*>): Any? {
|
||||
checkArguments(args)
|
||||
return member.set(boundReceiver, args.first())
|
||||
}
|
||||
}
|
||||
|
||||
class BoundJvmStaticInObjectFieldSetter(field: ReflectField, notNull: Boolean) :
|
||||
FieldSetter(field, notNull, requiresInstance = false) {
|
||||
override fun call(args: Array<*>): Any? {
|
||||
checkArguments(args)
|
||||
return member.set(null, args.last())
|
||||
}
|
||||
}
|
||||
|
||||
class BoundClassCompanionFieldSetter(field: ReflectField, klass: Class<*>) :
|
||||
FunctionCaller<ReflectField>(field, Void.TYPE, klass, arrayOf(field.genericType)) {
|
||||
override fun call(args: Array<*>): Any? {
|
||||
checkArguments(args)
|
||||
return member.set(null, args.last())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
// TODO lazily allocate array at bound callers?
|
||||
fun argsWithReceiver(receiver: Any?, args: Array<out Any?>): Array<out Any?> =
|
||||
arrayOfNulls<Any?>(args.size + 1).apply {
|
||||
this[0] = receiver
|
||||
System.arraycopy(args, 0, this, 1, args.size)
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
inline fun <reified T> Array<out T>.dropFirst(): Array<T> =
|
||||
if (size <= 1) emptyArray<T>() else copyOfRange(1, size) as Array<T>
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun Array<*>.dropFirstArg(): Array<Any?> =
|
||||
(this as Array<Any?>).dropFirst()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,8 @@ internal abstract class KCallableImpl<out R> : KCallable<R> {
|
||||
|
||||
abstract val container: KDeclarationContainerImpl
|
||||
|
||||
abstract val isBound: Boolean
|
||||
|
||||
private val annotations_ = ReflectProperties.lazySoft { descriptor.computeAnnotations() }
|
||||
|
||||
override val annotations: List<Annotation> get() = annotations_()
|
||||
@@ -44,11 +46,11 @@ internal abstract class KCallableImpl<out R> : KCallable<R> {
|
||||
val result = ArrayList<KParameter>()
|
||||
var index = 0
|
||||
|
||||
if (descriptor.dispatchReceiverParameter != null) {
|
||||
if (descriptor.dispatchReceiverParameter != null && !isBound) {
|
||||
result.add(KParameterImpl(this, index++, KParameter.Kind.INSTANCE) { descriptor.dispatchReceiverParameter!! })
|
||||
}
|
||||
|
||||
if (descriptor.extensionReceiverParameter != null) {
|
||||
if (descriptor.extensionReceiverParameter != null && !isBound) {
|
||||
result.add(KParameterImpl(this, index++, KParameter.Kind.EXTENSION_RECEIVER) { descriptor.extensionReceiverParameter!! })
|
||||
}
|
||||
|
||||
|
||||
@@ -50,6 +50,8 @@ internal class KFunctionImpl private constructor(
|
||||
descriptor
|
||||
)
|
||||
|
||||
override val isBound: Boolean get() = boundReceiver != CallableReference.NO_RECEIVER
|
||||
|
||||
override val descriptor: FunctionDescriptor by ReflectProperties.lazySoft(descriptorInitialValue) {
|
||||
container.findFunctionDescriptor(name, signature)
|
||||
}
|
||||
@@ -77,13 +79,15 @@ internal class KFunctionImpl private constructor(
|
||||
}
|
||||
|
||||
when (member) {
|
||||
is Constructor<*> -> FunctionCaller.Constructor(member)
|
||||
is Constructor<*> ->
|
||||
createConstructorCaller(member)
|
||||
is Method -> when {
|
||||
!Modifier.isStatic(member.modifiers) -> FunctionCaller.InstanceMethod(member)
|
||||
!Modifier.isStatic(member.modifiers) ->
|
||||
createInstanceMethodCaller(member)
|
||||
descriptor.annotations.findAnnotation(JVM_STATIC) != null ->
|
||||
FunctionCaller.JvmStaticInObject(member)
|
||||
|
||||
else -> FunctionCaller.StaticMethod(member)
|
||||
createJvmStaticInObjectCaller(member)
|
||||
else ->
|
||||
createStaticMethodCaller(member)
|
||||
}
|
||||
else -> throw KotlinReflectionInternalError("Call is not yet supported for this function: $descriptor (member = $member)")
|
||||
}
|
||||
@@ -112,21 +116,35 @@ internal class KFunctionImpl private constructor(
|
||||
}
|
||||
|
||||
when (member) {
|
||||
is Constructor<*> -> FunctionCaller.Constructor(member)
|
||||
is Constructor<*> ->
|
||||
createConstructorCaller(member)
|
||||
is Method -> when {
|
||||
// Note that static $default methods for @JvmStatic functions are generated differently in objects and companion objects.
|
||||
// In objects, $default's signature does _not_ contain the additional object instance parameter,
|
||||
// as opposed to companion objects where the first parameter is the companion object instance.
|
||||
descriptor.annotations.findAnnotation(JVM_STATIC) != null &&
|
||||
!(descriptor.containingDeclaration as ClassDescriptor).isCompanionObject ->
|
||||
FunctionCaller.JvmStaticInObject(member)
|
||||
createJvmStaticInObjectCaller(member)
|
||||
|
||||
else -> FunctionCaller.StaticMethod(member)
|
||||
else ->
|
||||
createStaticMethodCaller(member)
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun createStaticMethodCaller(member: Method) =
|
||||
if (isBound) FunctionCaller.BoundStaticMethod(member, boundReceiver) else FunctionCaller.StaticMethod(member)
|
||||
|
||||
private fun createJvmStaticInObjectCaller(member: Method) =
|
||||
if (isBound) FunctionCaller.BoundJvmStaticInObject(member) else FunctionCaller.JvmStaticInObject(member)
|
||||
|
||||
private fun createInstanceMethodCaller(member: Method) =
|
||||
if (isBound) FunctionCaller.BoundInstanceMethod(member, boundReceiver) else FunctionCaller.InstanceMethod(member)
|
||||
|
||||
private fun createConstructorCaller(member: Constructor<*>) =
|
||||
if (isBound) FunctionCaller.BoundConstructor(member, boundReceiver) else FunctionCaller.Constructor(member)
|
||||
|
||||
override fun getArity() = caller.arity
|
||||
|
||||
override val isInline: Boolean
|
||||
|
||||
@@ -17,11 +17,12 @@
|
||||
package kotlin.reflect.jvm.internal
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import kotlin.jvm.internal.CallableReference
|
||||
import kotlin.reflect.KMutableProperty2
|
||||
import kotlin.reflect.KProperty2
|
||||
|
||||
internal open class KProperty2Impl<D, E, out R> : KProperty2<D, E, R>, KPropertyImpl<R> {
|
||||
constructor(container: KDeclarationContainerImpl, name: String, signature: String) : super(container, name, signature, null)
|
||||
constructor(container: KDeclarationContainerImpl, name: String, signature: String) : super(container, name, signature, CallableReference.NO_RECEIVER)
|
||||
|
||||
constructor(container: KDeclarationContainerImpl, descriptor: PropertyDescriptor) : super(container, descriptor)
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ internal abstract class KPropertyImpl<out R> private constructor(
|
||||
override val name: String,
|
||||
val signature: String,
|
||||
descriptorInitialValue: PropertyDescriptor?,
|
||||
private val boundReceiver: Any? = CallableReference.NO_RECEIVER
|
||||
val boundReceiver: Any?
|
||||
) : KCallableImpl<R>(), KProperty<R> {
|
||||
constructor(container: KDeclarationContainerImpl, name: String, signature: String, boundReceiver: Any?) : this(
|
||||
container, name, signature, null, boundReceiver
|
||||
@@ -47,9 +47,12 @@ internal abstract class KPropertyImpl<out R> private constructor(
|
||||
container,
|
||||
descriptor.name.asString(),
|
||||
RuntimeTypeMapper.mapPropertySignature(descriptor).asString(),
|
||||
descriptor
|
||||
descriptor,
|
||||
CallableReference.NO_RECEIVER
|
||||
)
|
||||
|
||||
override val isBound: Boolean get() = boundReceiver != CallableReference.NO_RECEIVER
|
||||
|
||||
private val javaField_ = ReflectProperties.lazySoft {
|
||||
val jvmSignature = RuntimeTypeMapper.mapPropertySignature(descriptor)
|
||||
when (jvmSignature) {
|
||||
@@ -116,6 +119,8 @@ internal abstract class KPropertyImpl<out R> private constructor(
|
||||
|
||||
override val defaultCaller: FunctionCaller<*>? get() = null
|
||||
|
||||
override val isBound: Boolean get() = property.isBound
|
||||
|
||||
override val isInline: Boolean get() = descriptor.isInline
|
||||
override val isExternal: Boolean get() = descriptor.isExternal
|
||||
override val isOperator: Boolean get() = descriptor.isOperator
|
||||
@@ -169,15 +174,27 @@ private fun KPropertyImpl.Accessor<*, *>.computeCallerForAccessor(isGetter: Bool
|
||||
fun computeFieldCaller(field: Field): FunctionCaller<Field> = when {
|
||||
isInsideClassCompanionObject() -> {
|
||||
val klass = (descriptor.containingDeclaration as ClassDescriptor).toJavaClass()!!
|
||||
if (isGetter) FunctionCaller.ClassCompanionFieldGetter(field, klass)
|
||||
else FunctionCaller.ClassCompanionFieldSetter(field, klass)
|
||||
if (isGetter)
|
||||
if (isBound) FunctionCaller.BoundClassCompanionFieldGetter(field, klass)
|
||||
else FunctionCaller.ClassCompanionFieldGetter(field, klass)
|
||||
else
|
||||
if (isBound) FunctionCaller.BoundClassCompanionFieldSetter(field, klass)
|
||||
else FunctionCaller.ClassCompanionFieldSetter(field, klass)
|
||||
}
|
||||
!Modifier.isStatic(field.modifiers) ->
|
||||
if (isGetter) FunctionCaller.InstanceFieldGetter(field)
|
||||
else FunctionCaller.InstanceFieldSetter(field, isNotNullProperty())
|
||||
if (isGetter)
|
||||
if (isBound) FunctionCaller.BoundInstanceFieldGetter(field, property.boundReceiver)
|
||||
else FunctionCaller.InstanceFieldGetter(field)
|
||||
else
|
||||
if (isBound) FunctionCaller.BoundInstanceFieldSetter(field, isNotNullProperty(), property.boundReceiver)
|
||||
else FunctionCaller.InstanceFieldSetter(field, isNotNullProperty())
|
||||
isJvmStaticProperty() ->
|
||||
if (isGetter) FunctionCaller.JvmStaticInObjectFieldGetter(field)
|
||||
else FunctionCaller.JvmStaticInObjectFieldSetter(field, isNotNullProperty())
|
||||
if (isGetter)
|
||||
if (isBound) FunctionCaller.BoundJvmStaticInObjectFieldGetter(field)
|
||||
else FunctionCaller.JvmStaticInObjectFieldGetter(field)
|
||||
else
|
||||
if (isBound) FunctionCaller.BoundJvmStaticInObjectFieldSetter(field, isNotNullProperty())
|
||||
else FunctionCaller.JvmStaticInObjectFieldSetter(field, isNotNullProperty())
|
||||
else ->
|
||||
if (isGetter) FunctionCaller.StaticFieldGetter(field)
|
||||
else FunctionCaller.StaticFieldSetter(field, isNotNullProperty())
|
||||
@@ -203,9 +220,15 @@ private fun KPropertyImpl.Accessor<*, *>.computeCallerForAccessor(isGetter: Bool
|
||||
|
||||
when {
|
||||
accessor == null -> computeFieldCaller(property.javaField!!)
|
||||
!Modifier.isStatic(accessor.modifiers) -> FunctionCaller.InstanceMethod(accessor)
|
||||
isJvmStaticProperty() -> FunctionCaller.JvmStaticInObject(accessor)
|
||||
else -> FunctionCaller.StaticMethod(accessor)
|
||||
!Modifier.isStatic(accessor.modifiers) ->
|
||||
if (isBound) FunctionCaller.BoundInstanceMethod(accessor, property.boundReceiver)
|
||||
else FunctionCaller.InstanceMethod(accessor)
|
||||
isJvmStaticProperty() ->
|
||||
if (isBound) FunctionCaller.BoundJvmStaticInObject(accessor)
|
||||
else FunctionCaller.JvmStaticInObject(accessor)
|
||||
else ->
|
||||
if (isBound) FunctionCaller.BoundStaticMethod(accessor, property.boundReceiver)
|
||||
else FunctionCaller.StaticMethod(accessor)
|
||||
}
|
||||
}
|
||||
is JavaField -> {
|
||||
@@ -217,7 +240,8 @@ private fun KPropertyImpl.Accessor<*, *>.computeCallerForAccessor(isGetter: Bool
|
||||
else jvmSignature.setterMethod ?: throw KotlinReflectionInternalError(
|
||||
"No source found for setter of Java method property: ${jvmSignature.getterMethod}"
|
||||
)
|
||||
FunctionCaller.InstanceMethod(method)
|
||||
if (isBound) FunctionCaller.BoundInstanceMethod(method, property.boundReceiver)
|
||||
else FunctionCaller.InstanceMethod(method)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user