KT-13440 Bound callable references in reflection

This commit is contained in:
Dmitry Petrov
2016-11-23 18:54:58 +03:00
parent 5879e201cd
commit 3d2696c81b
33 changed files with 1276 additions and 70 deletions
@@ -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)
}
}
}