Implement KClass.getProperties()
#KT-6570 In Progress
This commit is contained in:
+19
@@ -0,0 +1,19 @@
|
|||||||
|
import kotlin.reflect.*
|
||||||
|
import kotlin.reflect.jvm.*
|
||||||
|
|
||||||
|
class K(private val value: String)
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
val p = javaClass<K>().kotlin.getProperties().single() as KMemberProperty<K, String>
|
||||||
|
|
||||||
|
try {
|
||||||
|
return p.get(K("Fail: private property should not be accessible by default"))
|
||||||
|
}
|
||||||
|
catch (e: IllegalPropertyAccessException) {
|
||||||
|
// OK
|
||||||
|
}
|
||||||
|
|
||||||
|
p.accessible = true
|
||||||
|
|
||||||
|
return p.get(K("OK"))
|
||||||
|
}
|
||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
import kotlin.reflect.jvm.*
|
||||||
|
import kotlin.test.*
|
||||||
|
|
||||||
|
open class Super(val r: String)
|
||||||
|
|
||||||
|
class Sub(r: String) : Super(r)
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
val props = javaClass<Sub>().kotlin.getProperties()
|
||||||
|
assertEquals(listOf("r"), props.map { it.name })
|
||||||
|
return props.single().get(Sub("OK")).toString()
|
||||||
|
}
|
||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
import kotlin.reflect.jvm.kotlin
|
||||||
|
import kotlin.reflect.KMutableMemberProperty
|
||||||
|
|
||||||
|
class A(val readonly: String) {
|
||||||
|
var mutable: String = "before"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
val props = javaClass<A>().kotlin.getProperties()
|
||||||
|
val readonly = props.single { it.name == "readonly" }
|
||||||
|
assert(readonly !is KMutableMemberProperty<A, *>) { "Fail 1: $readonly" }
|
||||||
|
val mutable = props.single { it.name == "mutable" }
|
||||||
|
assert(mutable is KMutableMemberProperty<A, *>) { "Fail 2: $mutable" }
|
||||||
|
|
||||||
|
val a = A("")
|
||||||
|
mutable as KMutableMemberProperty<A, String>
|
||||||
|
assert(mutable[a] == "before") { "Fail 3: ${mutable.get(a)}" }
|
||||||
|
mutable[a] = "OK"
|
||||||
|
return mutable.get(a)
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import kotlin.reflect.jvm.kotlin
|
||||||
|
|
||||||
|
class A(param: String) {
|
||||||
|
val int: Int get() = 42
|
||||||
|
val string: String = param
|
||||||
|
var anyVar: Any? = null
|
||||||
|
|
||||||
|
val List<IntRange>.extensionToList: Unit get() {}
|
||||||
|
|
||||||
|
fun notAProperty() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
val klass = javaClass<A>().kotlin
|
||||||
|
|
||||||
|
val props = klass.getProperties()
|
||||||
|
|
||||||
|
val names = props.map { it.name }.toSortedList()
|
||||||
|
assert(names == listOf("anyVar", "int", "string")) { "Fail names: $props" }
|
||||||
|
|
||||||
|
val stringProp = props.firstOrNull { it.name == "string" } ?: return "Fail, string not found: $props"
|
||||||
|
return stringProp.get(A("OK")) as String
|
||||||
|
}
|
||||||
+34
@@ -2528,6 +2528,7 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode
|
|||||||
Reflection.GenericSignature.class,
|
Reflection.GenericSignature.class,
|
||||||
Reflection.Mapping.class,
|
Reflection.Mapping.class,
|
||||||
Reflection.MethodsFromAny.class,
|
Reflection.MethodsFromAny.class,
|
||||||
|
Reflection.Properties.class,
|
||||||
})
|
})
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
public static class Reflection extends AbstractBlackBoxCodegenTest {
|
public static class Reflection extends AbstractBlackBoxCodegenTest {
|
||||||
@@ -2780,6 +2781,39 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode
|
|||||||
doTestWithStdlib(fileName);
|
doTestWithStdlib(fileName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("compiler/testData/codegen/boxWithStdlib/reflection/properties")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class Properties extends AbstractBlackBoxCodegenTest {
|
||||||
|
public void testAllFilesPresentInProperties() throws Exception {
|
||||||
|
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxWithStdlib/reflection/properties"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("callPrivatePropertyFromGetProperties.kt")
|
||||||
|
public void testCallPrivatePropertyFromGetProperties() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/properties/callPrivatePropertyFromGetProperties.kt");
|
||||||
|
doTestWithStdlib(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("fakeOverridesInSubclass.kt")
|
||||||
|
public void testFakeOverridesInSubclass() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/properties/fakeOverridesInSubclass.kt");
|
||||||
|
doTestWithStdlib(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("getPropertiesMutableVsReadonly.kt")
|
||||||
|
public void testGetPropertiesMutableVsReadonly() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/properties/getPropertiesMutableVsReadonly.kt");
|
||||||
|
doTestWithStdlib(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("simpleGetProperties.kt")
|
||||||
|
public void testSimpleGetProperties() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/properties/simpleGetProperties.kt");
|
||||||
|
doTestWithStdlib(fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/codegen/boxWithStdlib/regressions")
|
@TestMetadata("compiler/testData/codegen/boxWithStdlib/regressions")
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package kotlin.reflect.jvm.internal
|
package kotlin.reflect.jvm.internal
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||||
import org.jetbrains.kotlin.resolve.scopes.JetScope
|
import org.jetbrains.kotlin.resolve.scopes.JetScope
|
||||||
import org.jetbrains.kotlin.serialization.deserialization.findClassAcrossModuleDependencies
|
import org.jetbrains.kotlin.serialization.deserialization.findClassAcrossModuleDependencies
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
@@ -40,6 +41,19 @@ class KClassImpl<T>(override val jClass: Class<T>) : KCallableContainerImpl(), K
|
|||||||
|
|
||||||
override val scope: JetScope get() = descriptor.getDefaultType().getMemberScope()
|
override val scope: JetScope get() = descriptor.getDefaultType().getMemberScope()
|
||||||
|
|
||||||
|
override fun getProperties(): Collection<KMemberProperty<T, *>> {
|
||||||
|
return scope.getAllDescriptors().stream()
|
||||||
|
.filterIsInstance<PropertyDescriptor>()
|
||||||
|
.filter { descriptor ->
|
||||||
|
descriptor.getExtensionReceiverParameter() == null
|
||||||
|
}
|
||||||
|
.map { descriptor ->
|
||||||
|
if (descriptor.isVar()) KMutableMemberPropertyImpl<T, Any?>(this) { descriptor }
|
||||||
|
else KMemberPropertyImpl<T, Any?>(this) { descriptor }
|
||||||
|
}
|
||||||
|
.toList()
|
||||||
|
}
|
||||||
|
|
||||||
fun memberProperty(name: String): KMemberProperty<T, *> {
|
fun memberProperty(name: String): KMemberProperty<T, *> {
|
||||||
return KMemberPropertyImpl<T, Any>(this, findPropertyDescriptor(name))
|
return KMemberPropertyImpl<T, Any>(this, findPropertyDescriptor(name))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,4 +16,6 @@
|
|||||||
|
|
||||||
package kotlin.reflect
|
package kotlin.reflect
|
||||||
|
|
||||||
public trait KClass<out T>
|
public trait KClass<T> {
|
||||||
|
public fun getProperties(): Collection<KMemberProperty<T, *>>
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user