Support property getters/setters in reflection

This commit is contained in:
Alexander Udalov
2015-07-01 19:08:31 +03:00
parent 749d0c4a52
commit 4f1247f03f
18 changed files with 297 additions and 4 deletions
@@ -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"
}
@@ -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
}
@@ -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
}
@@ -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)
}
@@ -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()
}
@@ -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
}
+54 -2
View File
@@ -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();
}
}