From e8f9a9f3b84784a403aa02245393f80beccf797e Mon Sep 17 00:00:00 2001 From: Michael Bogdanov Date: Mon, 12 Oct 2015 19:20:07 +0300 Subject: [PATCH] Support reflection on @JvmField properties inside class companion --- .../reflect/jvm/internal/FunctionCaller.kt | 30 +++++++++++++++++++ .../reflect/jvm/internal/KPropertyImpl.kt | 18 +++++++++++ 2 files changed, 48 insertions(+) diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/FunctionCaller.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/FunctionCaller.kt index cf872b3799c..d9f281b87bd 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/FunctionCaller.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/FunctionCaller.kt @@ -158,6 +158,21 @@ internal abstract class FunctionCaller( } } + class ClassCompanionFieldGetter( + field: ReflectField, + klass: Class<*> + ) : FunctionCaller( + field, + field.genericType, + klass, + emptyArray() + ) { + override fun call(args: Array<*>): Any? { + checkArguments(args) + return member.get(args.first()) + } + } + class StaticFieldSetter(field: ReflectField, notNull: Boolean) : FieldSetter(field, notNull) class InstanceFieldSetter(field: ReflectField, notNull: Boolean) : FieldSetter(field, notNull) @@ -168,4 +183,19 @@ internal abstract class FunctionCaller( checkObjectInstance(args.firstOrNull()) } } + + class ClassCompanionFieldSetter( + field: ReflectField, + klass: Class<*> + ) : FunctionCaller( + field, + Void.TYPE, + klass, + arrayOf(field.genericType) + ) { + override fun call(args: Array<*>): Any? { + checkArguments(args) + return member.set(instanceClass, args.last()) + } + } } diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KPropertyImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KPropertyImpl.kt index 1070937fd6e..8938763e2ed 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KPropertyImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KPropertyImpl.kt @@ -18,7 +18,10 @@ package kotlin.reflect.jvm.internal import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotations +import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement +import org.jetbrains.kotlin.load.kotlin.reflect.ReflectKotlinClass import org.jetbrains.kotlin.resolve.DescriptorFactory +import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.types.TypeUtils import java.lang.reflect.Field import java.lang.reflect.Modifier @@ -86,14 +89,29 @@ internal interface KMutablePropertyImpl : KMutableProperty, KPropertyImpl< private fun KPropertyImpl.Accessor<*>.computeCallerForAccessor(isGetter: Boolean): FunctionCaller<*> { + fun isInsideClassCompanionObject(): Boolean { + val possibleCompanionObject = property.descriptor.containingDeclaration + if (DescriptorUtils.isCompanionObject(possibleCompanionObject) && !DescriptorUtils.isInterface(possibleCompanionObject.containingDeclaration)) { + return true + } + return false + } fun isJvmStaticProperty() = property.descriptor.annotations.findAnnotation(PLATFORM_STATIC) != null || property.descriptor.annotations.findAnnotation(JVM_STATIC) != null + fun isNotNullProperty() = !TypeUtils.isNullableType(property.descriptor.type) fun computeFieldCaller(field: Field): FunctionCaller = when { + isInsideClassCompanionObject() -> { + val containingDeclaration = descriptor.containingDeclaration as ClassDescriptor + val sourceElement = containingDeclaration.source as KotlinJvmBinarySourceElement + val klass = (sourceElement.binaryClass as ReflectKotlinClass).klass + if (isGetter) FunctionCaller.ClassCompanionFieldGetter(field, klass) + else FunctionCaller.ClassCompanionFieldSetter(field, klass) + } !Modifier.isStatic(field.modifiers) -> if (isGetter) FunctionCaller.InstanceFieldGetter(field) else FunctionCaller.InstanceFieldSetter(field, isNotNullProperty())