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:
+3
@@ -0,0 +1,3 @@
|
||||
public class J {
|
||||
private String result = "Fail";
|
||||
}
|
||||
+10
@@ -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]
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
public class J {
|
||||
private static String result = "Fail";
|
||||
}
|
||||
+10
@@ -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()
|
||||
}
|
||||
Vendored
+25
@@ -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]
|
||||
}
|
||||
+12
@@ -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/");
|
||||
|
||||
+6
@@ -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
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user