diff --git a/compiler/testData/codegen/boxWithStdlib/callableReference/property/platformNamedAccessors.kt b/compiler/testData/codegen/boxWithStdlib/callableReference/property/platformNamedAccessors.kt new file mode 100644 index 00000000000..4d7d7cef883 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/callableReference/property/platformNamedAccessors.kt @@ -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() +} diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/mapping/topLevelProperty.kt b/compiler/testData/codegen/boxWithStdlib/reflection/mapping/topLevelProperty.kt index ada90d5c564..30ddedb53eb 100644 --- a/compiler/testData/codegen/boxWithStdlib/reflection/mapping/topLevelProperty.kt +++ b/compiler/testData/codegen/boxWithStdlib/reflection/mapping/topLevelProperty.kt @@ -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!! diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java index a9d74f2c840..9c8d1477e79 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java @@ -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"); diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/DescriptorBasedProperty.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/DescriptorBasedProperty.kt index b3ddba51a7a..eb353eb577e 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/DescriptorBasedProperty.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/DescriptorBasedProperty.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) diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KPackageImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KPackageImpl.kt index df51b69f5af..22ad3b811dd 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KPackageImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KPackageImpl.kt @@ -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() +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 topLevelExtensionProperty(name: String, receiver: Class): KTopLevelExtensionProperty { + return KTopLevelExtensionPropertyImpl(name, this, receiver) + } + + fun mutableTopLevelExtensionProperty(name: String, receiver: Class): KMutableTopLevelExtensionProperty { + 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())) { if (name == "_DefaultPackage") "" else name.substringBeforeLast(".") } else name diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KTopLevelVariableImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KTopLevelVariableImpl.kt index 234e9ac7f18..8ad1606e759 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KTopLevelVariableImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KTopLevelVariableImpl.kt @@ -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( - override val name: String, - protected val owner: KPackageImpl -) : KTopLevelVariable, KVariableImpl { - // TODO: load the field from the corresponding package part - override val field: Field? get() = null + override val container: KPackageImpl, + computeDescriptor: () -> PropertyDescriptor +) : DescriptorBasedProperty(computeDescriptor), KTopLevelVariable, KVariableImpl { + 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.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( } 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( - name: String, - owner: KPackageImpl -) : KMutableTopLevelVariable, KMutableVariableImpl, KTopLevelVariableImpl(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(container, computeDescriptor), KMutableTopLevelVariable, KMutableVariableImpl { + override val setter: Method get() = super.setter!! override fun set(value: R) { try { @@ -73,7 +64,4 @@ class KMutableTopLevelVariableImpl( throw IllegalPropertyAccessException(e) } } - - override fun toString(): String = - "var $name" } diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/ReflectionFactoryImpl.java b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/ReflectionFactoryImpl.java index 98fb87a2cf5..ca1e121009e 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/ReflectionFactoryImpl.java +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/ReflectionFactoryImpl.java @@ -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); } } diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/util.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/util.kt index d297d8e8a62..d8b7ed0805f 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/util.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/util.kt @@ -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) diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/mapping.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/mapping.kt index c833c0b8ca0..f348e4e39ae 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/mapping.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/mapping.kt @@ -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