Refactor property calls in reflection, fix some corner cases

- compute a FunctionCaller instance for getter and setter so that "call" only
  delegates to that FunctionCaller's "call", in the same way it's done in
  KFunctionImpl
- use RuntimeTypeMapper.mapPropertySignature to get the exact origin and
  signature of a property and its accessors. This makes unwrapFakeOverride call
  unnecessary and also fixes some cases like private Java fields
- temporarily drop custom range checks, will be re-added soon
This commit is contained in:
Alexander Udalov
2015-08-04 05:10:27 +03:00
parent a91729e041
commit 9c522b4d49
18 changed files with 249 additions and 205 deletions
@@ -0,0 +1,3 @@
public class J {
private String result = "Fail";
}
@@ -0,0 +1,10 @@
import kotlin.reflect.*
import kotlin.reflect.jvm.*
fun box(): String {
val a = J()
val p = J::class.members.single { it.name == "result" } as KMutableProperty1<J, String>
p.isAccessible = true
p[a] = "OK"
return p[a]
}
@@ -0,0 +1,3 @@
public class J {
private static String result = "Fail";
}
@@ -0,0 +1,10 @@
import kotlin.reflect.*
import kotlin.reflect.jvm.*
fun box(): String {
val a = J()
val p = J::class.members.single { it.name == "result" } as KMutableProperty0<String>
p.isAccessible = true
p.set("OK")
return p.get()
}
@@ -0,0 +1,25 @@
import kotlin.reflect.*
import kotlin.reflect.jvm.*
import kotlin.platform.platformStatic as static
object Obj {
private static var result: String = "Fail"
}
fun box(): String {
val p = Obj::class.members.single { it.name == "result" } as KMutableProperty1<Any?, String>
p.isAccessible = true
try {
p[null] = "OK"
return "Fail: set should check that first argument is Obj"
} catch (e: IllegalArgumentException) {}
try {
p[null]
return "Fail: get should check that first argument is Obj"
} catch (e: IllegalArgumentException) {}
p[Obj] = "OK"
return p[Obj]
}
@@ -303,6 +303,18 @@ public class BlackBoxWithJavaCodegenTestGenerated extends AbstractBlackBoxCodege
doTestWithJava(fileName); doTestWithJava(fileName);
} }
@TestMetadata("mutatePrivateJavaInstanceField")
public void testMutatePrivateJavaInstanceField() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/reflection/mutatePrivateJavaInstanceField/");
doTestWithJava(fileName);
}
@TestMetadata("mutatePrivateJavaStaticField")
public void testMutatePrivateJavaStaticField() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/reflection/mutatePrivateJavaStaticField/");
doTestWithJava(fileName);
}
@TestMetadata("noConflictOnKotlinGetterAndJavaField") @TestMetadata("noConflictOnKotlinGetterAndJavaField")
public void testNoConflictOnKotlinGetterAndJavaField() throws Exception { public void testNoConflictOnKotlinGetterAndJavaField() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/reflection/noConflictOnKotlinGetterAndJavaField/"); String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/reflection/noConflictOnKotlinGetterAndJavaField/");
@@ -3537,6 +3537,12 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode
doTestWithStdlib(fileName); doTestWithStdlib(fileName);
} }
@TestMetadata("privatePlatformStaticVarInObject.kt")
public void testPrivatePlatformStaticVarInObject() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/properties/privatePlatformStaticVarInObject.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("privatePropertyCallIsAccessibleOnAccessors.kt") @TestMetadata("privatePropertyCallIsAccessibleOnAccessors.kt")
public void testPrivatePropertyCallIsAccessibleOnAccessors() throws Exception { public void testPrivatePropertyCallIsAccessibleOnAccessors() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/properties/privatePropertyCallIsAccessibleOnAccessors.kt"); String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/properties/privatePropertyCallIsAccessibleOnAccessors.kt");
@@ -17,17 +17,12 @@
package kotlin.reflect.jvm.internal package kotlin.reflect.jvm.internal
import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.serialization.ProtoBuf
import org.jetbrains.kotlin.serialization.deserialization.NameResolver
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf
import java.lang.reflect.Field import java.lang.reflect.Field
import java.lang.reflect.Method import kotlin.reflect.jvm.internal.JvmPropertySignature.JavaField
import kotlin.reflect.jvm.internal.JvmPropertySignature.KotlinProperty
abstract class DescriptorBasedProperty<out R> protected constructor( abstract class DescriptorBasedProperty<out R> protected constructor(
container: KCallableContainerImpl, internal val container: KCallableContainerImpl,
name: String, name: String,
signature: String, signature: String,
descriptorInitialValue: PropertyDescriptor? descriptorInitialValue: PropertyDescriptor?
@@ -43,47 +38,19 @@ abstract class DescriptorBasedProperty<out R> protected constructor(
descriptor descriptor
) )
private data class PropertyProtoData(
val proto: ProtoBuf.Callable,
val nameResolver: NameResolver,
val signature: JvmProtoBuf.JvmPropertySignature
)
override val descriptor: PropertyDescriptor by ReflectProperties.lazySoft<PropertyDescriptor>(descriptorInitialValue) { override val descriptor: PropertyDescriptor by ReflectProperties.lazySoft<PropertyDescriptor>(descriptorInitialValue) {
container.findPropertyDescriptor(name, signature) container.findPropertyDescriptor(name, signature)
} }
// null if this is a property declared in a foreign (Java) class internal val javaField: Field? by ReflectProperties.lazySoft {
private val protoData: PropertyProtoData? by ReflectProperties.lazyWeak { val jvmSignature = RuntimeTypeMapper.mapPropertySignature(descriptor)
val property = DescriptorUtils.unwrapFakeOverride(descriptor) as? DeserializedPropertyDescriptor when (jvmSignature) {
if (property != null) { is KotlinProperty -> {
val proto = property.proto if (!jvmSignature.signature.hasField()) null
if (proto.hasExtension(JvmProtoBuf.propertySignature)) { else container.findFieldBySignature(jvmSignature.proto, jvmSignature.signature.field, jvmSignature.nameResolver)
return@lazyWeak PropertyProtoData(proto, property.nameResolver, proto.getExtension(JvmProtoBuf.propertySignature))
} }
is JavaField -> jvmSignature.field
} }
null
}
open val javaField: Field? by ReflectProperties.lazySoft {
val proto = protoData
if (proto == null) container.jClass.getField(name)
else if (!proto.signature.hasField()) null
else container.findFieldBySignature(proto.proto, proto.signature.getField(), proto.nameResolver)
}
open val javaGetter: Method? by ReflectProperties.lazySoft {
val proto = protoData
if (proto == null || !proto.signature.hasGetter()) null
else container.findMethodBySignature(proto.proto, proto.signature.getGetter(), proto.nameResolver,
descriptor.getGetter()?.getVisibility()?.let { Visibilities.isPrivate(it) } ?: false)
}
open val javaSetter: Method? by ReflectProperties.lazySoft {
val proto = protoData
if (proto == null || !proto.signature.hasSetter()) null
else container.findMethodBySignature(proto.proto, proto.signature.getSetter(), proto.nameResolver,
descriptor.getSetter()?.getVisibility()?.let { Visibilities.isPrivate(it) } ?: false)
} }
override fun equals(other: Any?): Boolean = override fun equals(other: Any?): Boolean =
@@ -16,19 +16,32 @@
package kotlin.reflect.jvm.internal package kotlin.reflect.jvm.internal
import java.lang.reflect.Member
import java.lang.reflect.Constructor as ReflectConstructor import java.lang.reflect.Constructor as ReflectConstructor
import java.lang.reflect.Field as ReflectField
import java.lang.reflect.Member as ReflectMember
import java.lang.reflect.Method as ReflectMethod import java.lang.reflect.Method as ReflectMethod
internal sealed class FunctionCaller { internal sealed class FunctionCaller {
abstract val member: ReflectMember
abstract fun call(args: Array<*>): Any? abstract fun call(args: Array<*>): Any?
class Constructor(val constructor: ReflectConstructor<*>) : FunctionCaller() { protected fun checkObjectInstance(obj: Any?) {
override fun call(args: Array<*>): Any? { if (obj == null || !member.declaringClass.isInstance(obj)) {
return constructor.newInstance(*args) throw IllegalArgumentException("An object member requires the object instance passed as the first argument.")
} }
} }
class Constructor(val constructor: ReflectConstructor<*>) : FunctionCaller() {
override val member: Member get() = constructor
override fun call(args: Array<*>): Any? =
constructor.newInstance(*args)
}
abstract class Method(val method: ReflectMethod) : FunctionCaller() { abstract class Method(val method: ReflectMethod) : FunctionCaller() {
override val member: Member get() = method
private val isVoidMethod = method.returnType == Void.TYPE private val isVoidMethod = method.returnType == Void.TYPE
protected fun callMethod(instance: Any?, args: Array<*>): Any? { protected fun callMethod(instance: Any?, args: Array<*>): Any? {
@@ -40,23 +53,57 @@ internal sealed class FunctionCaller {
} }
class StaticMethod(method: ReflectMethod) : Method(method) { class StaticMethod(method: ReflectMethod) : Method(method) {
override fun call(args: Array<*>): Any? { override fun call(args: Array<*>): Any? =
return callMethod(null, args) callMethod(null, args)
}
} }
class InstanceMethod(method: ReflectMethod) : Method(method) { class InstanceMethod(method: ReflectMethod) : Method(method) {
override fun call(args: Array<*>): Any? { override fun call(args: Array<*>): Any? =
return callMethod(args[0], args.asList().subList(1, args.size()).toTypedArray()) callMethod(args[0], args.asList().subList(1, args.size()).toTypedArray())
}
} }
class PlatformStaticInObject(method: ReflectMethod) : Method(method) { class PlatformStaticInObject(method: ReflectMethod) : Method(method) {
override fun call(args: Array<*>): Any? { override fun call(args: Array<*>): Any? {
if (args.isEmpty() || !method.declaringClass.isInstance(args[0])) { checkObjectInstance(args.firstOrNull())
throw IllegalArgumentException("A function in an object requires the object instance passed as the first argument.")
}
return callMethod(null, args.asList().subList(1, args.size()).toTypedArray()) return callMethod(null, args.asList().subList(1, args.size()).toTypedArray())
} }
} }
abstract class Field(val field: ReflectField) : FunctionCaller() {
override val member: Member get() = field
}
class StaticFieldGetter(field: ReflectField) : Field(field) {
override fun call(args: Array<*>): Any? =
field.get(null)
}
class InstanceFieldGetter(field: ReflectField) : Field(field) {
override fun call(args: Array<*>): Any? =
field.get(args[0])
}
class PlatformStaticInObjectFieldGetter(field: ReflectField) : Field(field) {
override fun call(args: Array<*>): Any? {
checkObjectInstance(args.firstOrNull())
return field.get(null)
}
}
class StaticFieldSetter(field: ReflectField) : Field(field) {
override fun call(args: Array<*>): Any? =
field.set(null, args[0])
}
class InstanceFieldSetter(field: ReflectField) : Field(field) {
override fun call(args: Array<*>): Any? =
field.set(args[0], args[1])
}
class PlatformStaticInObjectFieldSetter(field: ReflectField) : Field(field) {
override fun call(args: Array<*>): Any? {
checkObjectInstance(args.firstOrNull())
return field.set(null, args[1])
}
}
} }
@@ -26,6 +26,8 @@ import kotlin.reflect.KType
interface KCallableImpl<out R> : KCallable<R>, KAnnotatedElementImpl { interface KCallableImpl<out R> : KCallable<R>, KAnnotatedElementImpl {
val descriptor: CallableMemberDescriptor val descriptor: CallableMemberDescriptor
val caller: FunctionCaller
override val annotated: Annotated get() = descriptor override val annotated: Annotated get() = descriptor
override val parameters: List<KParameter> override val parameters: List<KParameter>
@@ -51,4 +53,9 @@ interface KCallableImpl<out R> : KCallable<R>, KAnnotatedElementImpl {
override val returnType: KType override val returnType: KType
get() = KTypeImpl(descriptor.returnType!!) get() = KTypeImpl(descriptor.returnType!!)
@suppress("UNCHECKED_CAST")
override fun call(vararg args: Any?): R = reflectionCall {
return caller.call(args) as R
}
} }
@@ -19,7 +19,6 @@ package kotlin.reflect.jvm.internal
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.name.FqName
import java.lang.reflect.Constructor import java.lang.reflect.Constructor
import java.lang.reflect.Member import java.lang.reflect.Member
import java.lang.reflect.Method import java.lang.reflect.Method
@@ -50,7 +49,7 @@ open class KFunctionImpl protected constructor(
override val name: String get() = descriptor.name.asString() override val name: String get() = descriptor.name.asString()
internal val caller: FunctionCaller by ReflectProperties.lazySoft { override val caller: FunctionCaller by ReflectProperties.lazySoft {
val jvmSignature = RuntimeTypeMapper.mapSignature(descriptor) val jvmSignature = RuntimeTypeMapper.mapSignature(descriptor)
val member: Member? = when (jvmSignature) { val member: Member? = when (jvmSignature) {
is KotlinFunction -> is KotlinFunction ->
@@ -74,10 +73,6 @@ open class KFunctionImpl protected constructor(
} }
} }
override fun call(vararg args: Any?): Any? = reflectionCall {
caller.call(args)
}
override fun getArity(): Int { override fun getArity(): Int {
return descriptor.valueParameters.size() + return descriptor.valueParameters.size() +
(if (descriptor.dispatchReceiverParameter != null) 1 else 0) + (if (descriptor.dispatchReceiverParameter != null) 1 else 0) +
@@ -92,8 +87,4 @@ open class KFunctionImpl protected constructor(
override fun toString(): String = override fun toString(): String =
ReflectionObjectRenderer.renderFunction(descriptor) ReflectionObjectRenderer.renderFunction(descriptor)
private companion object {
val PLATFORM_STATIC = FqName("kotlin.platform.platformStatic")
}
} }
@@ -17,7 +17,6 @@
package kotlin.reflect.jvm.internal package kotlin.reflect.jvm.internal
import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import java.lang.reflect.Method
import kotlin.jvm.internal.MutablePropertyReference0 import kotlin.jvm.internal.MutablePropertyReference0
import kotlin.jvm.internal.PropertyReference0 import kotlin.jvm.internal.PropertyReference0
import kotlin.reflect.KMutableProperty0 import kotlin.reflect.KMutableProperty0
@@ -30,17 +29,7 @@ open class KProperty0Impl<out R> : DescriptorBasedProperty<R>, KProperty0<R>, KP
override val getter by ReflectProperties.lazy { Getter(this) } override val getter by ReflectProperties.lazy { Getter(this) }
override val javaGetter: Method get() = super.javaGetter!! override fun get(): R = getter.call()
@suppress("UNCHECKED_CAST")
override fun get(): R = reflectionCall {
return javaGetter.invoke(null) as R
}
override fun call(vararg args: Any?): R {
require(args.isEmpty()) { "Property $name expects no arguments, but ${args.size()} were provided." }
return get()
}
class Getter<out R>(override val property: KProperty0Impl<R>) : KPropertyImpl.Getter<R>(), KProperty0.Getter<R> { class Getter<out R>(override val property: KProperty0Impl<R>) : KPropertyImpl.Getter<R>(), KProperty0.Getter<R> {
override fun invoke(): R = property.get() override fun invoke(): R = property.get()
@@ -54,22 +43,10 @@ open class KMutableProperty0Impl<R> : KProperty0Impl<R>, KMutableProperty0<R>, K
override val setter by ReflectProperties.lazy { Setter(this) } override val setter by ReflectProperties.lazy { Setter(this) }
override val javaSetter: Method get() = super.javaSetter!! override fun set(value: R) = setter.call(value)
override fun set(value: R) {
reflectionCall {
javaSetter.invoke(null, value)
}
}
class Setter<R>(override val property: KMutableProperty0Impl<R>) : KMutablePropertyImpl.Setter<R>(), KMutableProperty0.Setter<R> { class Setter<R>(override val property: KMutableProperty0Impl<R>) : KMutablePropertyImpl.Setter<R>(), KMutableProperty0.Setter<R> {
override fun invoke(value: R): Unit = property.set(value) override fun invoke(value: R): Unit = property.set(value)
@suppress("UNCHECKED_CAST")
override fun call(vararg args: Any?) {
require(args.size() == 1) { "Property setter for ${property.name} expects one argument, but ${args.size()} were provided." }
property.set(args.single() as R)
}
} }
} }
@@ -77,11 +54,11 @@ open class KMutableProperty0Impl<R> : KProperty0Impl<R>, KMutableProperty0<R>, K
class KProperty0FromReferenceImpl( class KProperty0FromReferenceImpl(
val reference: PropertyReference0 val reference: PropertyReference0
) : KProperty0Impl<Any?>( ) : KProperty0Impl<Any?>(
reference.getOwner() as KCallableContainerImpl, reference.owner as KCallableContainerImpl,
reference.getName(), reference.name,
reference.getSignature() reference.signature
) { ) {
override val name: String get() = reference.getName() override val name: String get() = reference.name
override fun get(): Any? = reference.get() override fun get(): Any? = reference.get()
} }
@@ -90,11 +67,11 @@ class KProperty0FromReferenceImpl(
class KMutableProperty0FromReferenceImpl( class KMutableProperty0FromReferenceImpl(
val reference: MutablePropertyReference0 val reference: MutablePropertyReference0
) : KMutableProperty0Impl<Any?>( ) : KMutableProperty0Impl<Any?>(
reference.getOwner() as KCallableContainerImpl, reference.owner as KCallableContainerImpl,
reference.getName(), reference.name,
reference.getSignature() reference.signature
) { ) {
override val name: String get() = reference.getName() override val name: String get() = reference.name
override fun get(): Any? = reference.get() override fun get(): Any? = reference.get()
@@ -17,7 +17,6 @@
package kotlin.reflect.jvm.internal package kotlin.reflect.jvm.internal
import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import java.lang.reflect.Modifier
import kotlin.jvm.internal.MutablePropertyReference1 import kotlin.jvm.internal.MutablePropertyReference1
import kotlin.jvm.internal.PropertyReference1 import kotlin.jvm.internal.PropertyReference1
import kotlin.reflect.KMutableProperty1 import kotlin.reflect.KMutableProperty1
@@ -30,33 +29,13 @@ open class KProperty1Impl<T, out R> : DescriptorBasedProperty<R>, KProperty1<T,
override val getter by ReflectProperties.lazy { Getter(this) } override val getter by ReflectProperties.lazy { Getter(this) }
// TODO: consider optimizing this, not to do complex checks on every access override fun get(receiver: T): R = getter.call(receiver)
@suppress("UNCHECKED_CAST", "IMPLICIT_CAST_TO_UNIT_OR_ANY" /* KT-8619 */)
override fun get(receiver: T): R = reflectionCall {
val getter = javaGetter
return when {
getter == null -> javaField!!.get(receiver)
Modifier.isStatic(getter.modifiers) -> {
// Workaround the case of platformStatic property in object, getter of which doesn't take a receiver
if (getter.parameterTypes.isEmpty()) getter.invoke(null)
else getter.invoke(null, receiver)
}
else -> getter.invoke(receiver)
} as R
}
@suppress("UNCHECKED_CAST")
override fun call(vararg args: Any?): R {
require(args.size() == 1) { "Property $name expects one argument, but ${args.size()} were provided." }
return get(args.single() as T)
}
class Getter<T, out R>(override val property: KProperty1Impl<T, R>) : KPropertyImpl.Getter<R>(), KProperty1.Getter<T, R> { class Getter<T, out R>(override val property: KProperty1Impl<T, R>) : KPropertyImpl.Getter<R>(), KProperty1.Getter<T, R> {
override fun invoke(receiver: T): R = property.get(receiver) override fun invoke(receiver: T): R = property.get(receiver)
} }
} }
open class KMutableProperty1Impl<T, R> : KProperty1Impl<T, R>, KMutableProperty1<T, R>, KMutablePropertyImpl<R> { open class KMutableProperty1Impl<T, R> : KProperty1Impl<T, R>, KMutableProperty1<T, R>, KMutablePropertyImpl<R> {
constructor(container: KCallableContainerImpl, name: String, signature: String) : super(container, name, signature) constructor(container: KCallableContainerImpl, name: String, signature: String) : super(container, name, signature)
@@ -64,29 +43,10 @@ open class KMutableProperty1Impl<T, R> : KProperty1Impl<T, R>, KMutableProperty1
override val setter by ReflectProperties.lazy { Setter(this) } override val setter by ReflectProperties.lazy { Setter(this) }
override fun set(receiver: T, value: R) { override fun set(receiver: T, value: R) = setter.call(receiver, value)
reflectionCall {
val setter = javaSetter
when {
setter == null -> javaField!!.set(receiver, value)
Modifier.isStatic(setter.modifiers) -> {
// Workaround the case of platformStatic property in object, setter of which doesn't take a receiver
if (setter.parameterTypes.size() == 1) setter.invoke(null, value)
else setter.invoke(null, receiver, value)
}
else -> setter.invoke(receiver, value)
}
}
}
class Setter<T, R>(override val property: KMutableProperty1Impl<T, R>) : KMutablePropertyImpl.Setter<R>(), KMutableProperty1.Setter<T, R> { class Setter<T, R>(override val property: KMutableProperty1Impl<T, R>) : KMutablePropertyImpl.Setter<R>(), KMutableProperty1.Setter<T, R> {
override fun invoke(receiver: T, value: R): Unit = property.set(receiver, value) override fun invoke(receiver: T, value: R): Unit = property.set(receiver, value)
@suppress("UNCHECKED_CAST")
override fun call(vararg args: Any?) {
require(args.size() == 2) { "Property setter for ${property.name} expects two arguments, but ${args.size()} were provided." }
property.set(args[0] as T, args[1] as R)
}
} }
} }
@@ -94,11 +54,11 @@ open class KMutableProperty1Impl<T, R> : KProperty1Impl<T, R>, KMutableProperty1
class KProperty1FromReferenceImpl( class KProperty1FromReferenceImpl(
val reference: PropertyReference1 val reference: PropertyReference1
) : KProperty1Impl<Any?, Any?>( ) : KProperty1Impl<Any?, Any?>(
reference.getOwner() as KCallableContainerImpl, reference.owner as KCallableContainerImpl,
reference.getName(), reference.name,
reference.getSignature() reference.signature
) { ) {
override val name: String get() = reference.getName() override val name: String get() = reference.name
override fun get(receiver: Any?): Any? = reference.get(receiver) override fun get(receiver: Any?): Any? = reference.get(receiver)
} }
@@ -107,11 +67,11 @@ class KProperty1FromReferenceImpl(
class KMutableProperty1FromReferenceImpl( class KMutableProperty1FromReferenceImpl(
val reference: MutablePropertyReference1 val reference: MutablePropertyReference1
) : KMutableProperty1Impl<Any?, Any?>( ) : KMutableProperty1Impl<Any?, Any?>(
reference.getOwner() as KCallableContainerImpl, reference.owner as KCallableContainerImpl,
reference.getName(), reference.name,
reference.getSignature() reference.signature
) { ) {
override val name: String get() = reference.getName() override val name: String get() = reference.name
override fun get(receiver: Any?): Any? = reference.get(receiver) override fun get(receiver: Any?): Any? = reference.get(receiver)
@@ -17,8 +17,6 @@
package kotlin.reflect.jvm.internal package kotlin.reflect.jvm.internal
import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import java.lang.reflect.Field
import java.lang.reflect.Method
import kotlin.reflect.KMutableProperty2 import kotlin.reflect.KMutableProperty2
import kotlin.reflect.KProperty2 import kotlin.reflect.KProperty2
@@ -29,27 +27,13 @@ open class KProperty2Impl<D, E, out R> : DescriptorBasedProperty<R>, KProperty2<
override val getter by ReflectProperties.lazy { Getter(this) } override val getter by ReflectProperties.lazy { Getter(this) }
override val javaGetter: Method get() = super.javaGetter!! override fun get(receiver1: D, receiver2: E): R = getter.call(receiver1, receiver2)
override val javaField: Field? get() = null
@suppress("UNCHECKED_CAST")
override fun get(receiver1: D, receiver2: E): R = reflectionCall {
return javaGetter.invoke(receiver1, receiver2) as R
}
@suppress("UNCHECKED_CAST")
override fun call(vararg args: Any?): R {
require(args.size() == 2) { "Property $name expects two arguments, but ${args.size()} were provided." }
return get(args[0] as D, args[1] as E)
}
class Getter<D, E, out R>(override val property: KProperty2Impl<D, E, R>) : KPropertyImpl.Getter<R>(), KProperty2.Getter<D, E, R> { class Getter<D, E, out R>(override val property: KProperty2Impl<D, E, R>) : KPropertyImpl.Getter<R>(), KProperty2.Getter<D, E, R> {
override fun invoke(receiver1: D, receiver2: E): R = property.get(receiver1, receiver2) override fun invoke(receiver1: D, receiver2: E): R = property.get(receiver1, receiver2)
} }
} }
class KMutableProperty2Impl<D, E, R> : KProperty2Impl<D, E, R>, KMutableProperty2<D, E, R>, KMutablePropertyImpl<R> { class KMutableProperty2Impl<D, E, R> : KProperty2Impl<D, E, R>, KMutableProperty2<D, E, R>, KMutablePropertyImpl<R> {
constructor(container: KCallableContainerImpl, name: String, signature: String) : super(container, name, signature) constructor(container: KCallableContainerImpl, name: String, signature: String) : super(container, name, signature)
@@ -57,21 +41,9 @@ class KMutableProperty2Impl<D, E, R> : KProperty2Impl<D, E, R>, KMutableProperty
override val setter by ReflectProperties.lazy { Setter(this) } override val setter by ReflectProperties.lazy { Setter(this) }
override val javaSetter: Method get() = super.javaSetter!! override fun set(receiver1: D, receiver2: E, value: R) = setter.call(receiver1, receiver2, value)
override fun set(receiver1: D, receiver2: E, value: R) {
reflectionCall {
javaSetter.invoke(receiver1, receiver2, value)
}
}
class Setter<D, E, R>(override val property: KMutableProperty2Impl<D, E, R>) : KMutablePropertyImpl.Setter<R>(), KMutableProperty2.Setter<D, E, R> { class Setter<D, E, R>(override val property: KMutableProperty2Impl<D, E, R>) : KMutablePropertyImpl.Setter<R>(), KMutableProperty2.Setter<D, E, R> {
override fun invoke(receiver1: D, receiver2: E, value: R): Unit = property.set(receiver1, receiver2, value) override fun invoke(receiver1: D, receiver2: E, value: R): Unit = property.set(receiver1, receiver2, value)
@suppress("UNCHECKED_CAST")
override fun call(vararg args: Any?) {
require(args.size() == 3) { "Property setter for ${property.name} expects three arguments, but ${args.size()} were provided." }
property.set(args[0] as D, args[1] as E, args[2] as R)
}
} }
} }
@@ -16,19 +16,17 @@
package kotlin.reflect.jvm.internal package kotlin.reflect.jvm.internal
import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.PropertyGetterDescriptor
import org.jetbrains.kotlin.descriptors.PropertySetterDescriptor
import org.jetbrains.kotlin.resolve.DescriptorFactory import org.jetbrains.kotlin.resolve.DescriptorFactory
import java.lang.reflect.Field import java.lang.reflect.Field
import java.lang.reflect.Method import java.lang.reflect.Modifier
import kotlin.reflect.KMutableProperty import kotlin.reflect.KMutableProperty
import kotlin.reflect.KProperty import kotlin.reflect.KProperty
interface KPropertyImpl<out R> : KProperty<R>, KCallableImpl<R> { interface KPropertyImpl<out R> : KProperty<R>, KCallableImpl<R> {
val javaField: Field? val javaField: Field?
val javaGetter: Method? val container: KCallableContainerImpl
override val getter: Getter<R> override val getter: Getter<R>
@@ -36,36 +34,90 @@ interface KPropertyImpl<out R> : KProperty<R>, KCallableImpl<R> {
override val name: String get() = descriptor.name.asString() override val name: String get() = descriptor.name.asString()
interface Accessor<out R> : KProperty.Accessor<R> { override val caller: FunctionCaller get() = getter.caller
override val property: KPropertyImpl<R>
abstract class Accessor<out R> : KProperty.Accessor<R> {
abstract override val property: KPropertyImpl<R>
internal abstract val descriptor: PropertyAccessorDescriptor
} }
abstract class Getter<out R> : KProperty.Getter<R>, Accessor<R>, KCallableImpl<R> { abstract class Getter<out R> : Accessor<R>(), KProperty.Getter<R>, KCallableImpl<R> {
override val name: String get() = "<get-${property.name}>" override val name: String get() = "<get-${property.name}>"
override val descriptor: PropertyGetterDescriptor by ReflectProperties.lazySoft { override val descriptor: PropertyGetterDescriptor by ReflectProperties.lazySoft {
// TODO: default getter created this way won't have any source information // TODO: default getter created this way won't have any source information
property.descriptor.getGetter() ?: DescriptorFactory.createDefaultGetter(property.descriptor) property.descriptor.getter ?: DescriptorFactory.createDefaultGetter(property.descriptor)
} }
override fun call(vararg args: Any?): R = property.call(*args) override val caller: FunctionCaller by ReflectProperties.lazySoft {
computeCallerForAccessor(isGetter = true)
}
} }
} }
interface KMutablePropertyImpl<R> : KMutableProperty<R>, KPropertyImpl<R> { interface KMutablePropertyImpl<R> : KMutableProperty<R>, KPropertyImpl<R> {
val javaSetter: Method?
override val setter: Setter<R> override val setter: Setter<R>
abstract class Setter<R> : KMutableProperty.Setter<R>, KPropertyImpl.Accessor<R>, KCallableImpl<Unit> { abstract class Setter<R> : KPropertyImpl.Accessor<R>(), KMutableProperty.Setter<R>, KCallableImpl<Unit> {
abstract override val property: KMutablePropertyImpl<R> abstract override val property: KMutablePropertyImpl<R>
override val name: String get() = "<set-${property.name}>" override val name: String get() = "<set-${property.name}>"
override val descriptor: PropertySetterDescriptor by ReflectProperties.lazySoft { override val descriptor: PropertySetterDescriptor by ReflectProperties.lazySoft {
// TODO: default setter created this way won't have any source information // TODO: default setter created this way won't have any source information
property.descriptor.getSetter() ?: DescriptorFactory.createDefaultSetter(property.descriptor) property.descriptor.setter ?: DescriptorFactory.createDefaultSetter(property.descriptor)
}
override val caller: FunctionCaller by ReflectProperties.lazySoft {
computeCallerForAccessor(isGetter = false)
}
}
}
private fun KPropertyImpl.Accessor<*>.computeCallerForAccessor(isGetter: Boolean): FunctionCaller {
fun isPlatformStaticProperty() =
property.descriptor.annotations.findAnnotation(PLATFORM_STATIC) != null
fun computeFieldCaller(field: Field): FunctionCaller.Field = when {
!Modifier.isStatic(field.modifiers) ->
if (isGetter) FunctionCaller.InstanceFieldGetter(field)
else FunctionCaller.InstanceFieldSetter(field)
isPlatformStaticProperty() ->
if (isGetter) FunctionCaller.PlatformStaticInObjectFieldGetter(field)
else FunctionCaller.PlatformStaticInObjectFieldSetter(field)
else ->
if (isGetter) FunctionCaller.StaticFieldGetter(field)
else FunctionCaller.StaticFieldSetter(field)
}
val jvmSignature = RuntimeTypeMapper.mapPropertySignature(property.descriptor)
return when (jvmSignature) {
is JvmPropertySignature.KotlinProperty -> {
val accessorSignature = jvmSignature.signature.run {
when {
isGetter -> if (hasGetter()) getter else null
else -> if (hasSetter()) setter else null
}
}
val accessor = accessorSignature?.let { signature ->
property.container.findMethodBySignature(
jvmSignature.proto, signature, jvmSignature.nameResolver, Visibilities.isPrivate(descriptor.visibility)
)
}
when {
accessor == null -> computeFieldCaller(property.javaField!!)
!Modifier.isStatic(accessor.modifiers) -> FunctionCaller.InstanceMethod(accessor)
isPlatformStaticProperty() -> FunctionCaller.PlatformStaticInObject(accessor)
else -> FunctionCaller.StaticMethod(accessor)
}
}
is JvmPropertySignature.JavaField -> {
computeFieldCaller(jvmSignature.field)
} }
} }
} }
@@ -79,17 +79,18 @@ sealed class JvmFunctionSignature {
} }
} }
interface JvmPropertySignature { sealed class JvmPropertySignature {
/** /**
* Returns the JVM signature of the getter of this property. In case the property doesn't have a getter, * Returns the JVM signature of the getter of this property. In case the property doesn't have a getter,
* constructs the signature of its imaginary default getter. See CallableReference#getSignature for more information * constructs the signature of its imaginary default getter. See CallableReference#getSignature for more information
*/ */
fun asString(): String abstract fun asString(): String
class KotlinProperty( class KotlinProperty(
private val signature: JvmProtoBuf.JvmPropertySignature, val proto: ProtoBuf.Callable,
private val nameResolver: NameResolver val signature: JvmProtoBuf.JvmPropertySignature,
) : JvmPropertySignature { val nameResolver: NameResolver
) : JvmPropertySignature() {
private val string: String private val string: String
init { init {
@@ -106,7 +107,7 @@ interface JvmPropertySignature {
override fun asString(): String = string override fun asString(): String = string
} }
class JavaImaginaryFieldGetter(private val field: Field) : JvmPropertySignature { class JavaField(val field: Field) : JvmPropertySignature() {
override fun asString(): String = override fun asString(): String =
JvmAbi.getterName(field.name) + JvmAbi.getterName(field.name) +
"()" + "()" +
@@ -151,13 +152,13 @@ object RuntimeTypeMapper {
if (!proto.hasExtension(JvmProtoBuf.propertySignature)) { if (!proto.hasExtension(JvmProtoBuf.propertySignature)) {
throw KotlinReflectionInternalError("No metadata found for $property") throw KotlinReflectionInternalError("No metadata found for $property")
} }
return JvmPropertySignature.KotlinProperty(proto.getExtension(JvmProtoBuf.propertySignature), property.nameResolver) return JvmPropertySignature.KotlinProperty(proto, proto.getExtension(JvmProtoBuf.propertySignature), property.nameResolver)
} }
else if (property is JavaPropertyDescriptor) { else if (property is JavaPropertyDescriptor) {
val field = ((property.source as? JavaSourceElement)?.javaElement as? ReflectJavaField)?.member ?: val field = ((property.source as? JavaSourceElement)?.javaElement as? ReflectJavaField)?.member ?:
throw KotlinReflectionInternalError("Incorrect resolution sequence for Java field $property") throw KotlinReflectionInternalError("Incorrect resolution sequence for Java field $property")
return JvmPropertySignature.JavaImaginaryFieldGetter(field) return JvmPropertySignature.JavaField(field)
} }
else throw KotlinReflectionInternalError("Unknown origin of $property (${property.javaClass})") else throw KotlinReflectionInternalError("Unknown origin of $property (${property.javaClass})")
} }
@@ -16,8 +16,11 @@
package kotlin.reflect.jvm.internal package kotlin.reflect.jvm.internal
import org.jetbrains.kotlin.name.FqName
import kotlin.reflect.IllegalCallableAccessException import kotlin.reflect.IllegalCallableAccessException
internal val PLATFORM_STATIC = FqName("kotlin.platform.platformStatic")
// TODO: wrap other exceptions // TODO: wrap other exceptions
internal inline fun <R> reflectionCall(block: () -> R): R = internal inline fun <R> reflectionCall(block: () -> R): R =
try { try {
@@ -55,14 +55,14 @@ public val KProperty<*>.javaField: Field?
* or `null` if the property has no getter, for example in case of a simple private `val` in a class. * or `null` if the property has no getter, for example in case of a simple private `val` in a class.
*/ */
public val KProperty<*>.javaGetter: Method? public val KProperty<*>.javaGetter: Method?
get() = (this as? KPropertyImpl<*>)?.javaGetter get() = getter.javaMethod
/** /**
* Returns a Java [Method] instance corresponding to the setter of the given mutable property, * Returns a Java [Method] instance corresponding to the setter of the given mutable property,
* or `null` if the property has no setter, for example in case of a simple private `var` in a class. * or `null` if the property has no setter, for example in case of a simple private `var` in a class.
*/ */
public val KMutableProperty<*>.javaSetter: Method? public val KMutableProperty<*>.javaSetter: Method?
get() = (this as? KMutablePropertyImpl<*>)?.javaSetter get() = setter.javaMethod
/** /**
@@ -71,9 +71,7 @@ public val KMutableProperty<*>.javaSetter: Method?
*/ */
public val KFunction<*>.javaMethod: Method? public val KFunction<*>.javaMethod: Method?
get() = when (this) { get() = when (this) {
is KFunctionImpl -> (caller as? FunctionCaller.Method)?.method is KCallableImpl<*> -> (caller as? FunctionCaller.Method)?.method
is KPropertyImpl.Getter<*> -> property.javaGetter
is KMutablePropertyImpl.Setter<*> -> property.javaSetter
else -> null else -> null
} }