Use descriptors for reflection on top level properties
This also allows to obtain a Field object from the package part (see mapping.kt)
This commit is contained in:
+24
@@ -0,0 +1,24 @@
|
||||
import kotlin.platform.platformName
|
||||
import kotlin.reflect.jvm.*
|
||||
|
||||
var state: String = "value"
|
||||
[platformName("getter")]
|
||||
get
|
||||
[platformName("setter")]
|
||||
set
|
||||
|
||||
fun box(): String {
|
||||
val p = ::state
|
||||
|
||||
if (p.name != "state") return "Fail name: ${p.name}"
|
||||
if (p.get() != "value") return "Fail get: ${p.get()}"
|
||||
p.set("OK")
|
||||
|
||||
val getterName = p.javaGetter!!.getName()
|
||||
if (getterName != "getter") return "Fail getter name: $getterName"
|
||||
|
||||
val setterName = p.javaSetter!!.getName()
|
||||
if (setterName != "setter") return "Fail setter name: $setterName"
|
||||
|
||||
return p.get()
|
||||
}
|
||||
@@ -6,8 +6,9 @@ var topLevel = "123"
|
||||
fun box(): String {
|
||||
val p = ::topLevel
|
||||
|
||||
// TODO: uncomment when fields are loaded from package parts
|
||||
// assert(p.javaField != null, "Fail p field")
|
||||
assert(p.javaField != null, "Fail p field")
|
||||
val field = p.javaField!!
|
||||
assert(field.getDeclaringClass().getName() contains "_DefaultPackage\$", "Fail field not in package part: ${field.getDeclaringClass()}")
|
||||
|
||||
val getter = p.javaGetter!!
|
||||
val setter = p.javaSetter!!
|
||||
|
||||
+6
@@ -789,6 +789,12 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode
|
||||
doTestWithStdlib(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("platformNamedAccessors.kt")
|
||||
public void testPlatformNamedAccessors() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/callableReference/property/platformNamedAccessors.kt");
|
||||
doTestWithStdlib(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("privateClassVal.kt")
|
||||
public void testPrivateClassVal() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/callableReference/property/privateClassVal.kt");
|
||||
|
||||
@@ -50,16 +50,16 @@ abstract class DescriptorBasedProperty(computeDescriptor: () -> PropertyDescript
|
||||
val field: Field? by ReflectProperties.lazySoft {
|
||||
val proto = protoData
|
||||
if (!proto.signature.hasField()) null
|
||||
else container.findFieldBySignature(proto.signature.getField(), proto.nameResolver)
|
||||
else container.findFieldBySignature(proto.proto, proto.signature.getField(), proto.nameResolver)
|
||||
}
|
||||
|
||||
val getter: Method? by ReflectProperties.lazySoft {
|
||||
open val getter: Method? by ReflectProperties.lazySoft {
|
||||
val proto = protoData
|
||||
if (!proto.signature.hasGetter()) null
|
||||
else container.findMethodBySignature(proto.signature.getGetter(), proto.nameResolver)
|
||||
}
|
||||
|
||||
val setter: Method? by ReflectProperties.lazySoft {
|
||||
open val setter: Method? by ReflectProperties.lazySoft {
|
||||
val proto = protoData
|
||||
if (!proto.signature.hasSetter()) null
|
||||
else container.findMethodBySignature(proto.signature.getSetter(), proto.nameResolver)
|
||||
|
||||
@@ -16,12 +16,39 @@
|
||||
|
||||
package kotlin.reflect.jvm.internal
|
||||
|
||||
import kotlin.reflect.KPackage
|
||||
import org.jetbrains.kotlin.load.java.structure.reflect.classId
|
||||
import org.jetbrains.kotlin.resolve.scopes.JetScope
|
||||
import kotlin.jvm.internal.KotlinPackage
|
||||
import kotlin.reflect.*
|
||||
|
||||
private val KOTLIN_PACKAGE_ANNOTATION_CLASS = javaClass<KotlinPackage>()
|
||||
class KPackageImpl(override val jClass: Class<*>) : KCallableContainerImpl(), KPackage {
|
||||
val descriptor by ReflectProperties.lazySoft {
|
||||
val moduleData = jClass.getOrCreateModule()
|
||||
val fqName = jClass.classId.getPackageFqName()
|
||||
|
||||
moduleData.module.getPackage(fqName) ?: throw KotlinReflectionInternalError("Package not resolved: $fqName")
|
||||
}
|
||||
|
||||
override val scope: JetScope get() = descriptor.getMemberScope()
|
||||
|
||||
fun topLevelVariable(name: String): KTopLevelVariable<*> {
|
||||
val descriptor = findPropertyDescriptor(name)
|
||||
return KTopLevelVariableImpl(this, descriptor)
|
||||
}
|
||||
|
||||
fun mutableTopLevelVariable(name: String): KMutableTopLevelVariable<*> {
|
||||
val descriptor = findPropertyDescriptor(name)
|
||||
return KMutableTopLevelVariableImpl(this, descriptor)
|
||||
}
|
||||
|
||||
fun <T> topLevelExtensionProperty(name: String, receiver: Class<T>): KTopLevelExtensionProperty<T, *> {
|
||||
return KTopLevelExtensionPropertyImpl(name, this, receiver)
|
||||
}
|
||||
|
||||
fun <T> mutableTopLevelExtensionProperty(name: String, receiver: Class<T>): KMutableTopLevelExtensionProperty<T, *> {
|
||||
return KMutableTopLevelExtensionPropertyImpl(name, this, receiver)
|
||||
}
|
||||
|
||||
class KPackageImpl(val jClass: Class<*>) : KPackage {
|
||||
override fun equals(other: Any?): Boolean =
|
||||
other is KPackageImpl && jClass == other.jClass
|
||||
|
||||
@@ -30,7 +57,7 @@ class KPackageImpl(val jClass: Class<*>) : KPackage {
|
||||
|
||||
override fun toString(): String {
|
||||
val name = jClass.getName()
|
||||
return "package " + if (jClass.isAnnotationPresent(KOTLIN_PACKAGE_ANNOTATION_CLASS)) {
|
||||
return "package " + if (jClass.isAnnotationPresent(javaClass<KotlinPackage>())) {
|
||||
if (name == "_DefaultPackage") "<default>" else name.substringBeforeLast(".")
|
||||
}
|
||||
else name
|
||||
|
||||
@@ -16,27 +16,24 @@
|
||||
|
||||
package kotlin.reflect.jvm.internal
|
||||
|
||||
import java.lang.reflect.*
|
||||
import kotlin.reflect.*
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import java.lang.reflect.Method
|
||||
import kotlin.reflect.IllegalPropertyAccessException
|
||||
import kotlin.reflect.KMutableTopLevelVariable
|
||||
import kotlin.reflect.KTopLevelVariable
|
||||
|
||||
open class KTopLevelVariableImpl<out R>(
|
||||
override val name: String,
|
||||
protected val owner: KPackageImpl
|
||||
) : KTopLevelVariable<R>, KVariableImpl<R> {
|
||||
// TODO: load the field from the corresponding package part
|
||||
override val field: Field? get() = null
|
||||
override val container: KPackageImpl,
|
||||
computeDescriptor: () -> PropertyDescriptor
|
||||
) : DescriptorBasedProperty(computeDescriptor), KTopLevelVariable<R>, KVariableImpl<R> {
|
||||
override val name: String get() = descriptor.getName().asString()
|
||||
|
||||
// TODO: extract, make lazy (weak?), use our descriptors knowledge, support Java fields
|
||||
override val getter: Method = try {
|
||||
owner.jClass.getMethod(getterName(name))
|
||||
}
|
||||
catch (e: NoSuchMethodException) {
|
||||
throw NoSuchPropertyException(e)
|
||||
}
|
||||
override val getter: Method get() = super<DescriptorBasedProperty>.getter!!
|
||||
|
||||
override fun get(): R {
|
||||
try {
|
||||
return getter(null) as R
|
||||
[suppress("UNCHECKED_CAST")]
|
||||
return getter.invoke(null) as R
|
||||
}
|
||||
catch (e: IllegalAccessException) {
|
||||
throw IllegalPropertyAccessException(e)
|
||||
@@ -44,26 +41,20 @@ open class KTopLevelVariableImpl<out R>(
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean =
|
||||
other is KTopLevelVariableImpl<*> && name == other.name && owner == other.owner
|
||||
other is KTopLevelVariableImpl<*> && descriptor == other.descriptor
|
||||
|
||||
override fun hashCode(): Int =
|
||||
name.hashCode() * 31 + owner.hashCode()
|
||||
descriptor.hashCode()
|
||||
|
||||
// TODO: include visibility, return type, maybe package
|
||||
override fun toString(): String =
|
||||
"val $name"
|
||||
ReflectionObjectRenderer.renderProperty(descriptor)
|
||||
}
|
||||
|
||||
class KMutableTopLevelVariableImpl<R>(
|
||||
name: String,
|
||||
owner: KPackageImpl
|
||||
) : KMutableTopLevelVariable<R>, KMutableVariableImpl<R>, KTopLevelVariableImpl<R>(name, owner) {
|
||||
override val setter: Method = try {
|
||||
owner.jClass.getMethod(setterName(name), getter.getReturnType())
|
||||
}
|
||||
catch (e: NoSuchMethodException) {
|
||||
throw NoSuchPropertyException(e)
|
||||
}
|
||||
container: KPackageImpl,
|
||||
computeDescriptor: () -> PropertyDescriptor
|
||||
) : KTopLevelVariableImpl<R>(container, computeDescriptor), KMutableTopLevelVariable<R>, KMutableVariableImpl<R> {
|
||||
override val setter: Method get() = super<KTopLevelVariableImpl>.setter!!
|
||||
|
||||
override fun set(value: R) {
|
||||
try {
|
||||
@@ -73,7 +64,4 @@ class KMutableTopLevelVariableImpl<R>(
|
||||
throw IllegalPropertyAccessException(e)
|
||||
}
|
||||
}
|
||||
|
||||
override fun toString(): String =
|
||||
"var $name"
|
||||
}
|
||||
|
||||
@@ -48,21 +48,21 @@ public class ReflectionFactoryImpl extends ReflectionFactory {
|
||||
|
||||
@Override
|
||||
public KTopLevelVariable topLevelVariable(String name, KPackage owner) {
|
||||
return new KTopLevelVariableImpl(name, ((KPackageImpl) owner));
|
||||
return ((KPackageImpl) owner).topLevelVariable(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public KMutableTopLevelVariable mutableTopLevelVariable(String name, KPackage owner) {
|
||||
return new KMutableTopLevelVariableImpl(name, (KPackageImpl) owner);
|
||||
return ((KPackageImpl) owner).mutableTopLevelVariable(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public KTopLevelExtensionProperty topLevelExtensionProperty(String name, KPackage owner, Class receiver) {
|
||||
return new KTopLevelExtensionPropertyImpl(name, (KPackageImpl) owner, receiver);
|
||||
return ((KPackageImpl) owner).topLevelExtensionProperty(name, receiver);
|
||||
}
|
||||
|
||||
@Override
|
||||
public KMutableTopLevelExtensionProperty mutableTopLevelExtensionProperty(String name, KPackage owner, Class receiver) {
|
||||
return new KMutableTopLevelExtensionPropertyImpl(name, (KPackageImpl) owner, receiver);
|
||||
return ((KPackageImpl) owner).mutableTopLevelExtensionProperty(name, receiver);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,8 +16,11 @@
|
||||
|
||||
package kotlin.reflect.jvm.internal
|
||||
|
||||
import org.jetbrains.kotlin.load.java.structure.reflect.classId
|
||||
import org.jetbrains.kotlin.load.java.structure.reflect.classLoader
|
||||
import org.jetbrains.kotlin.load.java.structure.reflect.createArrayType
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.serialization.ProtoBuf
|
||||
import org.jetbrains.kotlin.serialization.deserialization.NameResolver
|
||||
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf
|
||||
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf.JvmType.PrimitiveType.*
|
||||
@@ -61,13 +64,26 @@ private fun KCallableContainerImpl.findMethodBySignature(signature: JvmProtoBuf.
|
||||
}
|
||||
|
||||
// TODO: check resulting field's type
|
||||
private fun KCallableContainerImpl.findFieldBySignature(signature: JvmProtoBuf.JvmFieldSignature, nameResolver: NameResolver): Field? {
|
||||
private fun KCallableContainerImpl.findFieldBySignature(
|
||||
proto: ProtoBuf.Callable,
|
||||
signature: JvmProtoBuf.JvmFieldSignature,
|
||||
nameResolver: NameResolver
|
||||
): Field? {
|
||||
val name = nameResolver.getString(signature.getName())
|
||||
|
||||
val owner =
|
||||
if (signature.getIsStaticInOuter())
|
||||
jClass.getEnclosingClass()
|
||||
?: throw KotlinReflectionInternalError("Inconsistent metadata for field $name in $jClass")
|
||||
else jClass
|
||||
when {
|
||||
proto.hasExtension(JvmProtoBuf.implClassName) -> {
|
||||
val implClassName = nameResolver.getName(proto.getExtension(JvmProtoBuf.implClassName))
|
||||
// TODO: store fq name of impl class name in jvm_descriptors.proto
|
||||
val classId = ClassId(jClass.classId.getPackageFqName(), implClassName)
|
||||
jClass.classLoader.loadClass(classId.asSingleFqName().asString())
|
||||
}
|
||||
signature.getIsStaticInOuter() -> {
|
||||
jClass.getEnclosingClass() ?: throw KotlinReflectionInternalError("Inconsistent metadata for field $name in $jClass")
|
||||
}
|
||||
else -> jClass
|
||||
}
|
||||
|
||||
return try {
|
||||
owner.getDeclaredField(name)
|
||||
|
||||
@@ -16,7 +16,9 @@
|
||||
|
||||
package kotlin.reflect.jvm
|
||||
|
||||
import java.lang.reflect.*
|
||||
import java.lang.reflect.Field
|
||||
import java.lang.reflect.Method
|
||||
import java.lang.reflect.Modifier
|
||||
import kotlin.jvm.internal.Reflection
|
||||
import kotlin.reflect.*
|
||||
import kotlin.reflect.jvm.internal.*
|
||||
@@ -37,7 +39,8 @@ public val KMutableProperty<*>.javaSetter: Method?
|
||||
get() = (this as? KMutablePropertyImpl<*>)?.setter
|
||||
|
||||
|
||||
// TODO: val KTopLevelVariable<*>.javaField: Field
|
||||
public val KTopLevelVariable<*>.javaField: Field?
|
||||
get() = (this as KPropertyImpl<*>).field
|
||||
|
||||
public val KTopLevelVariable<*>.javaGetter: Method
|
||||
get() = (this as KTopLevelVariableImpl<*>).getter
|
||||
|
||||
Reference in New Issue
Block a user