Support property getters/setters in reflection
This commit is contained in:
+30
@@ -0,0 +1,30 @@
|
||||
import kotlin.reflect.*
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
var foo = ""
|
||||
var String.bar: String
|
||||
get() = this
|
||||
set(value) {}
|
||||
|
||||
class A(var baz: Int) {
|
||||
var String.quux: String
|
||||
get() = this
|
||||
set(value) {}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
assertEquals("<get-foo>", ::foo.getter.name)
|
||||
assertEquals("<set-foo>", ::foo.setter.name)
|
||||
|
||||
assertEquals("<get-bar>", String::bar.getter.name)
|
||||
assertEquals("<set-bar>", String::bar.setter.name)
|
||||
|
||||
assertEquals("<get-baz>", A::baz.getter.name)
|
||||
assertEquals("<set-baz>", A::baz.setter.name)
|
||||
|
||||
val me = A::class.extensionProperties.single() as KMutableProperty2<A, String, String>
|
||||
assertEquals("<get-quux>", me.getter.name)
|
||||
assertEquals("<set-quux>", me.setter.name)
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
var state: String = ""
|
||||
|
||||
var String.prop: String
|
||||
get() = length().toString()
|
||||
set(value) { state = this + value }
|
||||
|
||||
fun box(): String {
|
||||
val prop = String::prop
|
||||
|
||||
assertEquals("3", prop.getter.invoke("abc"))
|
||||
assertEquals("5", prop.getter("defgh"))
|
||||
|
||||
prop.setter("O", "K")
|
||||
|
||||
return state
|
||||
}
|
||||
Vendored
+20
@@ -0,0 +1,20 @@
|
||||
import kotlin.reflect.KMutableProperty2
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class C(var state: String) {
|
||||
var String.prop: String
|
||||
get() = length().toString()
|
||||
set(value) { state = this + value }
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val prop = C::class.extensionProperties.single() as KMutableProperty2<C, String, String>
|
||||
|
||||
val c = C("")
|
||||
assertEquals("3", prop.getter.invoke(c, "abc"))
|
||||
assertEquals("1", prop.getter(c, "d"))
|
||||
|
||||
prop.setter(c, "O", "K")
|
||||
|
||||
return c.state
|
||||
}
|
||||
Vendored
+15
@@ -0,0 +1,15 @@
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class C(var state: String)
|
||||
|
||||
fun box(): String {
|
||||
val prop = C::state
|
||||
|
||||
val c = C("1")
|
||||
assertEquals("1", prop.getter.invoke(c))
|
||||
assertEquals("1", prop.getter(c))
|
||||
|
||||
prop.setter(c, "OK")
|
||||
|
||||
return prop.get(c)
|
||||
}
|
||||
compiler/testData/codegen/boxWithStdlib/reflection/properties/accessors/topLevelPropertyAccessors.kt
Vendored
+14
@@ -0,0 +1,14 @@
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
var state: String = ""
|
||||
|
||||
fun box(): String {
|
||||
val prop = ::state
|
||||
|
||||
assertEquals("", prop.getter.invoke())
|
||||
assertEquals("", prop.getter())
|
||||
|
||||
prop.setter("OK")
|
||||
|
||||
return prop.get()
|
||||
}
|
||||
+39
@@ -3251,6 +3251,45 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/properties/simpleGetProperties.kt");
|
||||
doTestWithStdlib(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/boxWithStdlib/reflection/properties/accessors")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class Accessors extends AbstractBlackBoxCodegenTest {
|
||||
@TestMetadata("accessorNames.kt")
|
||||
public void testAccessorNames() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/properties/accessors/accessorNames.kt");
|
||||
doTestWithStdlib(fileName);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInAccessors() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxWithStdlib/reflection/properties/accessors"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("extensionPropertyAccessors.kt")
|
||||
public void testExtensionPropertyAccessors() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/properties/accessors/extensionPropertyAccessors.kt");
|
||||
doTestWithStdlib(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("memberExtensions.kt")
|
||||
public void testMemberExtensions() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/properties/accessors/memberExtensions.kt");
|
||||
doTestWithStdlib(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("memberPropertyAccessors.kt")
|
||||
public void testMemberPropertyAccessors() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/properties/accessors/memberPropertyAccessors.kt");
|
||||
doTestWithStdlib(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("topLevelPropertyAccessors.kt")
|
||||
public void testTopLevelPropertyAccessors() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/properties/accessors/topLevelPropertyAccessors.kt");
|
||||
doTestWithStdlib(fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,11 @@ package kotlin.reflect
|
||||
public interface KCallable<out R> {
|
||||
/**
|
||||
* The name of this callable as it was declared in the source code.
|
||||
* If the callable has no name, a special invented name is created.
|
||||
* Nameless callables include:
|
||||
* - constructors have the name "<init>",
|
||||
* - property accessors: the getter for a property named "foo" will have the name "<get-foo>",
|
||||
* the setter, similarly, will have the name "<set-foo>".
|
||||
*/
|
||||
public val name: String
|
||||
}
|
||||
|
||||
@@ -24,12 +24,40 @@ package kotlin.reflect
|
||||
*
|
||||
* @param R the type of the property.
|
||||
*/
|
||||
public interface KProperty<out R> : KCallable<R>
|
||||
public interface KProperty<out R> : KCallable<R> {
|
||||
/** The getter of this property, used to obtain the value of the property. */
|
||||
public val getter: Getter<R>
|
||||
|
||||
/**
|
||||
* Represents a property accessor, which is a `get` or `set` method declared alongside the property.
|
||||
* See the [Kotlin language documentation](http://kotlinlang.org/docs/reference/properties.html#getters-and-setters)
|
||||
* for more information.
|
||||
*
|
||||
* @param R the type of the property, which it is an accessor of.
|
||||
*/
|
||||
public interface Accessor<out R> {
|
||||
/** The property which this accessor is originated from. */
|
||||
public val property: KProperty<R>
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of the property is a `get` method declared alongside the property.
|
||||
*/
|
||||
public interface Getter<out R> : Accessor<R>, KFunction<R>
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a property declared as a `var`.
|
||||
*/
|
||||
public interface KMutableProperty<R> : KProperty<R>
|
||||
public interface KMutableProperty<R> : KProperty<R> {
|
||||
/** The setter of this mutable property, used to change the value of the property. */
|
||||
public val setter: Setter<R>
|
||||
|
||||
/**
|
||||
* Setter of the property is a `set` method declared alongside the property.
|
||||
*/
|
||||
public interface Setter<R> : KProperty.Accessor<R>, KFunction<Unit>
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -42,6 +70,10 @@ public interface KProperty0<out R> : KProperty<R> {
|
||||
* Returns the current value of the property.
|
||||
*/
|
||||
public fun get(): R
|
||||
|
||||
override val getter: Getter<R>
|
||||
|
||||
public interface Getter<out R> : KProperty.Getter<R>, () -> R
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -54,6 +86,10 @@ public interface KMutableProperty0<R> : KProperty0<R>, KMutableProperty<R> {
|
||||
* @param value the new value to be assigned to this property.
|
||||
*/
|
||||
public fun set(value: R)
|
||||
|
||||
override val setter: Setter<R>
|
||||
|
||||
public interface Setter<R> : KMutableProperty.Setter<R>, (R) -> Unit
|
||||
}
|
||||
|
||||
|
||||
@@ -72,6 +108,10 @@ public interface KProperty1<T, out R> : KProperty<R> {
|
||||
* or an extension receiver if this is a top level extension property.
|
||||
*/
|
||||
public fun get(receiver: T): R
|
||||
|
||||
override val getter: Getter<T, R>
|
||||
|
||||
public interface Getter<T, out R> : KProperty.Getter<R>, (T) -> R
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -87,6 +127,10 @@ public interface KMutableProperty1<T, R> : KProperty1<T, R>, KMutableProperty<R>
|
||||
* @param value the new value to be assigned to this property.
|
||||
*/
|
||||
public fun set(receiver: T, value: R)
|
||||
|
||||
override val setter: Setter<T, R>
|
||||
|
||||
public interface Setter<T, R> : KMutableProperty.Setter<R>, (T, R) -> Unit
|
||||
}
|
||||
|
||||
|
||||
@@ -109,6 +153,10 @@ public interface KProperty2<D, E, out R> : KProperty<R> {
|
||||
* @param receiver2 the instance of the second receiver.
|
||||
*/
|
||||
public fun get(receiver1: D, receiver2: E): R
|
||||
|
||||
override val getter: Getter<D, E, R>
|
||||
|
||||
public interface Getter<D, E, out R> : KProperty.Getter<R>, (D, E) -> R
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -123,4 +171,8 @@ public interface KMutableProperty2<D, E, R> : KProperty2<D, E, R>, KMutablePrope
|
||||
* @param value the new value to be assigned to this property.
|
||||
*/
|
||||
public fun set(receiver1: D, receiver2: E, value: R)
|
||||
|
||||
override val setter: Setter<D, E, R>
|
||||
|
||||
public interface Setter<D, E, R> : KMutableProperty.Setter<R>, (D, E, R) -> Unit
|
||||
}
|
||||
|
||||
@@ -28,6 +28,8 @@ open class KProperty0Impl<out R> : DescriptorBasedProperty, KProperty0<R>, KProp
|
||||
|
||||
override val name: String get() = descriptor.getName().asString()
|
||||
|
||||
override val getter by ReflectProperties.lazy { Getter(this) }
|
||||
|
||||
override val javaGetter: Method get() = super.javaGetter!!
|
||||
|
||||
override fun get(): R {
|
||||
@@ -39,11 +41,17 @@ open class KProperty0Impl<out R> : DescriptorBasedProperty, KProperty0<R>, KProp
|
||||
throw IllegalPropertyAccessException(e)
|
||||
}
|
||||
}
|
||||
|
||||
class Getter<out R>(override val property: KProperty0Impl<R>) : KPropertyImpl.Getter<R>, KProperty0.Getter<R> {
|
||||
override fun invoke(): R = property.get()
|
||||
}
|
||||
}
|
||||
|
||||
open class KMutableProperty0Impl<R> : KProperty0Impl<R>, KMutableProperty0<R>, KMutablePropertyImpl<R> {
|
||||
constructor(container: KCallableContainerImpl, name: String, signature: String) : super(container, name, signature)
|
||||
|
||||
override val setter by ReflectProperties.lazy { Setter(this) }
|
||||
|
||||
override val javaSetter: Method get() = super.javaSetter!!
|
||||
|
||||
override fun set(value: R) {
|
||||
@@ -54,6 +62,10 @@ open class KMutableProperty0Impl<R> : KProperty0Impl<R>, KMutableProperty0<R>, K
|
||||
throw IllegalPropertyAccessException(e)
|
||||
}
|
||||
}
|
||||
|
||||
class Setter<R>(override val property: KMutableProperty0Impl<R>) : KMutablePropertyImpl.Setter<R>, KMutableProperty0.Setter<R> {
|
||||
override fun invoke(value: R): Unit = property.set(value)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -18,11 +18,11 @@ 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.IllegalPropertyAccessException
|
||||
import kotlin.reflect.KMutableProperty1
|
||||
import kotlin.reflect.KProperty1
|
||||
import kotlin.jvm.internal.MutablePropertyReference1
|
||||
import kotlin.jvm.internal.PropertyReference1
|
||||
|
||||
open class KProperty1Impl<T, out R> : DescriptorBasedProperty, KProperty1<T, R>, KPropertyImpl<R> {
|
||||
constructor(container: KCallableContainerImpl, name: String, signature: String) : super(container, name, signature)
|
||||
@@ -31,6 +31,8 @@ open class KProperty1Impl<T, out R> : DescriptorBasedProperty, KProperty1<T, R>,
|
||||
|
||||
override val name: String get() = descriptor.getName().asString()
|
||||
|
||||
override val getter by ReflectProperties.lazy { Getter(this) }
|
||||
|
||||
// TODO: consider optimizing this, not to do complex checks on every access
|
||||
@suppress("UNCHECKED_CAST")
|
||||
override fun get(receiver: T): R {
|
||||
@@ -53,6 +55,10 @@ open class KProperty1Impl<T, out R> : DescriptorBasedProperty, KProperty1<T, R>,
|
||||
throw IllegalPropertyAccessException(e)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -61,6 +67,8 @@ open class KMutableProperty1Impl<T, R> : KProperty1Impl<T, R>, KMutableProperty1
|
||||
|
||||
constructor(container: KCallableContainerImpl, descriptor: PropertyDescriptor) : super(container, descriptor)
|
||||
|
||||
override val setter by ReflectProperties.lazy { Setter(this) }
|
||||
|
||||
override fun set(receiver: T, value: R) {
|
||||
try {
|
||||
val setter = javaSetter ?:
|
||||
@@ -83,6 +91,10 @@ open class KMutableProperty1Impl<T, R> : KProperty1Impl<T, R>, KMutableProperty1
|
||||
throw IllegalPropertyAccessException(e)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -30,6 +30,8 @@ open class KProperty2Impl<D, E, out R> : DescriptorBasedProperty, KProperty2<D,
|
||||
|
||||
override val name: String get() = descriptor.getName().asString()
|
||||
|
||||
override val getter by ReflectProperties.lazy { Getter(this) }
|
||||
|
||||
override val javaGetter: Method get() = super.javaGetter!!
|
||||
|
||||
override val javaField: Field? get() = null
|
||||
@@ -43,6 +45,10 @@ open class KProperty2Impl<D, E, out R> : DescriptorBasedProperty, KProperty2<D,
|
||||
throw IllegalPropertyAccessException(e)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,6 +57,8 @@ class KMutableProperty2Impl<D, E, R> : KProperty2Impl<D, E, R>, KMutableProperty
|
||||
|
||||
constructor(container: KClassImpl<D>, descriptor: PropertyDescriptor) : super(container, descriptor)
|
||||
|
||||
override val setter by ReflectProperties.lazy { Setter(this) }
|
||||
|
||||
override val javaSetter: Method get() = super.javaSetter!!
|
||||
|
||||
override fun set(receiver1: D, receiver2: E, value: R) {
|
||||
@@ -61,4 +69,8 @@ class KMutableProperty2Impl<D, E, R> : KProperty2Impl<D, E, R>, KMutableProperty
|
||||
throw IllegalPropertyAccessException(e)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,9 +23,25 @@ interface KPropertyImpl<out R> : KProperty<R>, KCallableImpl<R> {
|
||||
val javaField: Field?
|
||||
|
||||
val javaGetter: Method?
|
||||
|
||||
override val getter: Getter<R>
|
||||
|
||||
interface Accessor<out R> : KProperty.Accessor<R> {
|
||||
override val property: KPropertyImpl<R>
|
||||
}
|
||||
|
||||
interface Getter<out R> : KProperty.Getter<R>, KCallableImpl<R> {
|
||||
override val name: String get() = "<get-${property.name}>"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
interface KMutablePropertyImpl<R> : KMutableProperty<R>, KPropertyImpl<R> {
|
||||
val javaSetter: Method?
|
||||
|
||||
override val setter: Setter<R>
|
||||
|
||||
interface Setter<R> : KMutableProperty.Setter<R>, KPropertyImpl.Accessor<R>, KCallableImpl<Unit> {
|
||||
override val name: String get() = "<set-${property.name}>"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package kotlin.jvm.internal;
|
||||
|
||||
import kotlin.reflect.KMutableProperty0;
|
||||
import kotlin.reflect.KProperty0;
|
||||
|
||||
public class MutablePropertyReference0 extends MutablePropertyReference implements KMutableProperty0 {
|
||||
@Override
|
||||
@@ -28,4 +29,14 @@ public class MutablePropertyReference0 extends MutablePropertyReference implemen
|
||||
public void set(Object value) {
|
||||
throw error();
|
||||
}
|
||||
|
||||
@Override
|
||||
public KProperty0.Getter getGetter() {
|
||||
throw error();
|
||||
}
|
||||
|
||||
@Override
|
||||
public KMutableProperty0.Setter getSetter() {
|
||||
throw error();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package kotlin.jvm.internal;
|
||||
|
||||
import kotlin.reflect.KMutableProperty1;
|
||||
import kotlin.reflect.KProperty1;
|
||||
|
||||
public class MutablePropertyReference1 extends MutablePropertyReference implements KMutableProperty1 {
|
||||
@Override
|
||||
@@ -28,4 +29,14 @@ public class MutablePropertyReference1 extends MutablePropertyReference implemen
|
||||
public void set(Object receiver, Object value) {
|
||||
throw error();
|
||||
}
|
||||
|
||||
@Override
|
||||
public KProperty1.Getter getGetter() {
|
||||
throw error();
|
||||
}
|
||||
|
||||
@Override
|
||||
public KMutableProperty1.Setter getSetter() {
|
||||
throw error();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package kotlin.jvm.internal;
|
||||
|
||||
import kotlin.reflect.KMutableProperty2;
|
||||
import kotlin.reflect.KProperty2;
|
||||
|
||||
public class MutablePropertyReference2 extends MutablePropertyReference implements KMutableProperty2 {
|
||||
@Override
|
||||
@@ -28,4 +29,14 @@ public class MutablePropertyReference2 extends MutablePropertyReference implemen
|
||||
public void set(Object receiver1, Object receiver2, Object value) {
|
||||
throw error();
|
||||
}
|
||||
|
||||
@Override
|
||||
public KProperty2.Getter getGetter() {
|
||||
throw error();
|
||||
}
|
||||
|
||||
@Override
|
||||
public KMutableProperty2.Setter getSetter() {
|
||||
throw error();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,4 +23,9 @@ public class PropertyReference0 extends PropertyReference implements KProperty0
|
||||
public Object get() {
|
||||
throw error();
|
||||
}
|
||||
|
||||
@Override
|
||||
public KProperty0.Getter getGetter() {
|
||||
throw error();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,4 +23,9 @@ public class PropertyReference1 extends PropertyReference implements KProperty1
|
||||
public Object get(Object receiver) {
|
||||
throw error();
|
||||
}
|
||||
|
||||
@Override
|
||||
public KProperty1.Getter getGetter() {
|
||||
throw error();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,4 +23,9 @@ public class PropertyReference2 extends PropertyReference implements KProperty2
|
||||
public Object get(Object receiver1, Object receiver2) {
|
||||
throw error();
|
||||
}
|
||||
|
||||
@Override
|
||||
public KProperty2.Getter getGetter() {
|
||||
throw error();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user