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);
}
@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")
public void testNoConflictOnKotlinGetterAndJavaField() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/reflection/noConflictOnKotlinGetterAndJavaField/");
@@ -3537,6 +3537,12 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode
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")
public void testPrivatePropertyCallIsAccessibleOnAccessors() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/properties/privatePropertyCallIsAccessibleOnAccessors.kt");
@@ -17,17 +17,12 @@
package kotlin.reflect.jvm.internal
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.Method
import kotlin.reflect.jvm.internal.JvmPropertySignature.JavaField
import kotlin.reflect.jvm.internal.JvmPropertySignature.KotlinProperty
abstract class DescriptorBasedProperty<out R> protected constructor(
container: KCallableContainerImpl,
internal val container: KCallableContainerImpl,
name: String,
signature: String,
descriptorInitialValue: PropertyDescriptor?
@@ -43,47 +38,19 @@ abstract class DescriptorBasedProperty<out R> protected constructor(
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) {
container.findPropertyDescriptor(name, signature)
}
// null if this is a property declared in a foreign (Java) class
private val protoData: PropertyProtoData? by ReflectProperties.lazyWeak {
val property = DescriptorUtils.unwrapFakeOverride(descriptor) as? DeserializedPropertyDescriptor
if (property != null) {
val proto = property.proto
if (proto.hasExtension(JvmProtoBuf.propertySignature)) {
return@lazyWeak PropertyProtoData(proto, property.nameResolver, proto.getExtension(JvmProtoBuf.propertySignature))
internal val javaField: Field? by ReflectProperties.lazySoft {
val jvmSignature = RuntimeTypeMapper.mapPropertySignature(descriptor)
when (jvmSignature) {
is KotlinProperty -> {
if (!jvmSignature.signature.hasField()) null
else container.findFieldBySignature(jvmSignature.proto, jvmSignature.signature.field, jvmSignature.nameResolver)
}
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 =
@@ -16,19 +16,32 @@
package kotlin.reflect.jvm.internal
import java.lang.reflect.Member
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
internal sealed class FunctionCaller {
abstract val member: ReflectMember
abstract fun call(args: Array<*>): Any?
class Constructor(val constructor: ReflectConstructor<*>) : FunctionCaller() {
override fun call(args: Array<*>): Any? {
return constructor.newInstance(*args)
protected fun checkObjectInstance(obj: Any?) {
if (obj == null || !member.declaringClass.isInstance(obj)) {
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() {
override val member: Member get() = method
private val isVoidMethod = method.returnType == Void.TYPE
protected fun callMethod(instance: Any?, args: Array<*>): Any? {
@@ -40,23 +53,57 @@ internal sealed class FunctionCaller {
}
class StaticMethod(method: ReflectMethod) : Method(method) {
override fun call(args: Array<*>): Any? {
return callMethod(null, args)
}
override fun call(args: Array<*>): Any? =
callMethod(null, args)
}
class InstanceMethod(method: ReflectMethod) : Method(method) {
override fun call(args: Array<*>): Any? {
return callMethod(args[0], args.asList().subList(1, args.size()).toTypedArray())
}
override fun call(args: Array<*>): Any? =
callMethod(args[0], args.asList().subList(1, args.size()).toTypedArray())
}
class PlatformStaticInObject(method: ReflectMethod) : Method(method) {
override fun call(args: Array<*>): Any? {
if (args.isEmpty() || !method.declaringClass.isInstance(args[0])) {
throw IllegalArgumentException("A function in an object requires the object instance passed as the first argument.")
}
checkObjectInstance(args.firstOrNull())
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 {
val descriptor: CallableMemberDescriptor
val caller: FunctionCaller
override val annotated: Annotated get() = descriptor
override val parameters: List<KParameter>
@@ -51,4 +53,9 @@ interface KCallableImpl<out R> : KCallable<R>, KAnnotatedElementImpl {
override val returnType: KType
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.Visibilities
import org.jetbrains.kotlin.name.FqName
import java.lang.reflect.Constructor
import java.lang.reflect.Member
import java.lang.reflect.Method
@@ -50,7 +49,7 @@ open class KFunctionImpl protected constructor(
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 member: Member? = when (jvmSignature) {
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 {
return descriptor.valueParameters.size() +
(if (descriptor.dispatchReceiverParameter != null) 1 else 0) +
@@ -92,8 +87,4 @@ open class KFunctionImpl protected constructor(
override fun toString(): String =
ReflectionObjectRenderer.renderFunction(descriptor)
private companion object {
val PLATFORM_STATIC = FqName("kotlin.platform.platformStatic")
}
}
@@ -17,7 +17,6 @@
package kotlin.reflect.jvm.internal
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import java.lang.reflect.Method
import kotlin.jvm.internal.MutablePropertyReference0
import kotlin.jvm.internal.PropertyReference0
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 javaGetter: Method get() = super.javaGetter!!
@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()
}
override fun get(): R = getter.call()
class Getter<out R>(override val property: KProperty0Impl<R>) : KPropertyImpl.Getter<R>(), KProperty0.Getter<R> {
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 javaSetter: Method get() = super.javaSetter!!
override fun set(value: R) {
reflectionCall {
javaSetter.invoke(null, value)
}
}
override fun set(value: R) = setter.call(value)
class Setter<R>(override val property: KMutableProperty0Impl<R>) : KMutablePropertyImpl.Setter<R>(), KMutableProperty0.Setter<R> {
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(
val reference: PropertyReference0
) : KProperty0Impl<Any?>(
reference.getOwner() as KCallableContainerImpl,
reference.getName(),
reference.getSignature()
reference.owner as KCallableContainerImpl,
reference.name,
reference.signature
) {
override val name: String get() = reference.getName()
override val name: String get() = reference.name
override fun get(): Any? = reference.get()
}
@@ -90,11 +67,11 @@ class KProperty0FromReferenceImpl(
class KMutableProperty0FromReferenceImpl(
val reference: MutablePropertyReference0
) : KMutableProperty0Impl<Any?>(
reference.getOwner() as KCallableContainerImpl,
reference.getName(),
reference.getSignature()
reference.owner as KCallableContainerImpl,
reference.name,
reference.signature
) {
override val name: String get() = reference.getName()
override val name: String get() = reference.name
override fun get(): Any? = reference.get()
@@ -17,7 +17,6 @@
package kotlin.reflect.jvm.internal
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import java.lang.reflect.Modifier
import kotlin.jvm.internal.MutablePropertyReference1
import kotlin.jvm.internal.PropertyReference1
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) }
// TODO: consider optimizing this, not to do complex checks on every access
@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)
}
override fun get(receiver: T): R = getter.call(receiver)
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)
}
}
open class KMutableProperty1Impl<T, R> : KProperty1Impl<T, R>, KMutableProperty1<T, R>, KMutablePropertyImpl<R> {
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 fun set(receiver: T, value: R) {
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)
}
}
}
override fun set(receiver: T, value: R) = setter.call(receiver, value)
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)
@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(
val reference: PropertyReference1
) : KProperty1Impl<Any?, Any?>(
reference.getOwner() as KCallableContainerImpl,
reference.getName(),
reference.getSignature()
reference.owner as KCallableContainerImpl,
reference.name,
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)
}
@@ -107,11 +67,11 @@ class KProperty1FromReferenceImpl(
class KMutableProperty1FromReferenceImpl(
val reference: MutablePropertyReference1
) : KMutableProperty1Impl<Any?, Any?>(
reference.getOwner() as KCallableContainerImpl,
reference.getName(),
reference.getSignature()
reference.owner as KCallableContainerImpl,
reference.name,
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)
@@ -17,8 +17,6 @@
package kotlin.reflect.jvm.internal
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import java.lang.reflect.Field
import java.lang.reflect.Method
import kotlin.reflect.KMutableProperty2
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 javaGetter: Method get() = super.javaGetter!!
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)
}
override fun get(receiver1: D, receiver2: E): R = getter.call(receiver1, receiver2)
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)
}
}
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)
@@ -57,21 +41,9 @@ class KMutableProperty2Impl<D, E, R> : KProperty2Impl<D, E, R>, KMutableProperty
override val setter by ReflectProperties.lazy { Setter(this) }
override val javaSetter: Method get() = super.javaSetter!!
override fun set(receiver1: D, receiver2: E, value: R) {
reflectionCall {
javaSetter.invoke(receiver1, receiver2, value)
}
}
override fun set(receiver1: D, receiver2: E, value: R) = setter.call(receiver1, receiver2, value)
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)
@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
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.PropertyGetterDescriptor
import org.jetbrains.kotlin.descriptors.PropertySetterDescriptor
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.resolve.DescriptorFactory
import java.lang.reflect.Field
import java.lang.reflect.Method
import java.lang.reflect.Modifier
import kotlin.reflect.KMutableProperty
import kotlin.reflect.KProperty
interface KPropertyImpl<out R> : KProperty<R>, KCallableImpl<R> {
val javaField: Field?
val javaGetter: Method?
val container: KCallableContainerImpl
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()
interface Accessor<out R> : KProperty.Accessor<R> {
override val property: KPropertyImpl<R>
override val caller: FunctionCaller get() = getter.caller
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 descriptor: PropertyGetterDescriptor by ReflectProperties.lazySoft {
// 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> {
val javaSetter: Method?
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>
override val name: String get() = "<set-${property.name}>"
override val descriptor: PropertySetterDescriptor by ReflectProperties.lazySoft {
// 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,
* constructs the signature of its imaginary default getter. See CallableReference#getSignature for more information
*/
fun asString(): String
abstract fun asString(): String
class KotlinProperty(
private val signature: JvmProtoBuf.JvmPropertySignature,
private val nameResolver: NameResolver
) : JvmPropertySignature {
val proto: ProtoBuf.Callable,
val signature: JvmProtoBuf.JvmPropertySignature,
val nameResolver: NameResolver
) : JvmPropertySignature() {
private val string: String
init {
@@ -106,7 +107,7 @@ interface JvmPropertySignature {
override fun asString(): String = string
}
class JavaImaginaryFieldGetter(private val field: Field) : JvmPropertySignature {
class JavaField(val field: Field) : JvmPropertySignature() {
override fun asString(): String =
JvmAbi.getterName(field.name) +
"()" +
@@ -151,13 +152,13 @@ object RuntimeTypeMapper {
if (!proto.hasExtension(JvmProtoBuf.propertySignature)) {
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) {
val field = ((property.source as? JavaSourceElement)?.javaElement as? ReflectJavaField)?.member ?:
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})")
}
@@ -16,8 +16,11 @@
package kotlin.reflect.jvm.internal
import org.jetbrains.kotlin.name.FqName
import kotlin.reflect.IllegalCallableAccessException
internal val PLATFORM_STATIC = FqName("kotlin.platform.platformStatic")
// TODO: wrap other exceptions
internal inline fun <R> reflectionCall(block: () -> R): R =
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.
*/
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,
* 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?
get() = (this as? KMutablePropertyImpl<*>)?.javaSetter
get() = setter.javaMethod
/**
@@ -71,9 +71,7 @@ public val KMutableProperty<*>.javaSetter: Method?
*/
public val KFunction<*>.javaMethod: Method?
get() = when (this) {
is KFunctionImpl -> (caller as? FunctionCaller.Method)?.method
is KPropertyImpl.Getter<*> -> property.javaGetter
is KMutablePropertyImpl.Setter<*> -> property.javaSetter
is KCallableImpl<*> -> (caller as? FunctionCaller.Method)?.method
else -> null
}