diff --git a/compiler/testData/codegen/boxWithJava/reflection/declaredVsInheritedProperties/J.java b/compiler/testData/codegen/boxWithJava/reflection/declaredVsInheritedProperties/J.java new file mode 100644 index 00000000000..58db865e2e7 --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/reflection/declaredVsInheritedProperties/J.java @@ -0,0 +1,6 @@ +public class J { + public String publicMemberJ; + private String privateMemberJ; + public static String publicStaticJ; + private static String privateStaticJ; +} diff --git a/compiler/testData/codegen/boxWithJava/reflection/declaredVsInheritedProperties/K.kt b/compiler/testData/codegen/boxWithJava/reflection/declaredVsInheritedProperties/K.kt new file mode 100644 index 00000000000..f4c6cdd8ecf --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/reflection/declaredVsInheritedProperties/K.kt @@ -0,0 +1,55 @@ +import kotlin.reflect.* +import kotlin.test.assertEquals + +open class K : J() { + public val publicMemberK: String = "" + private val privateMemberK: String = "" + public val Any.publicMemberExtensionK: String get() = "" + private val Any.privateMemberExtensionK: String get() = "" +} + +class L : K() + +fun Collection>.names(): Set = + this.map { it.name }.toSet() + +fun check(c: Collection>, names: Set) { + assertEquals(names, c.names()) +} + +fun box(): String { + val j = J::class + + check(j.staticProperties, + setOf("publicStaticJ", "privateStaticJ")) + check(j.declaredMemberProperties, + setOf("publicMemberJ", "privateMemberJ")) + check(j.declaredMemberExtensionProperties, + emptySet()) + + check(j.memberProperties, j.declaredMemberProperties.names()) + check(j.memberExtensionProperties, emptySet()) + + val k = K::class + + check(k.staticProperties, + emptySet()) + check(k.declaredMemberProperties, + setOf("publicMemberK", "privateMemberK")) + check(k.declaredMemberExtensionProperties, + setOf("publicMemberExtensionK", "privateMemberExtensionK")) + + check(k.memberProperties, setOf("publicMemberJ") + k.declaredMemberProperties.names()) + check(k.memberExtensionProperties, k.declaredMemberExtensionProperties.names()) + + + val l = L::class + + check(l.staticProperties, emptySet()) + check(l.declaredMemberProperties, emptySet()) + check(l.declaredMemberExtensionProperties, emptySet()) + check(l.memberProperties, setOf("publicMemberJ", "publicMemberK")) + check(l.memberExtensionProperties, setOf("publicMemberExtensionK")) + + return "OK" +} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java index 71739e7cbe9..130d8602ab3 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java @@ -291,6 +291,12 @@ public class BlackBoxWithJavaCodegenTestGenerated extends AbstractBlackBoxCodege doTestWithJava(fileName); } + @TestMetadata("declaredVsInheritedProperties") + public void testDeclaredVsInheritedProperties() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/reflection/declaredVsInheritedProperties/"); + doTestWithJava(fileName); + } + @TestMetadata("functionReferenceErasedToKFunction") public void testFunctionReferenceErasedToKFunction() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/reflection/functionReferenceErasedToKFunction/"); diff --git a/core/reflection.jvm/src/kotlin/reflect/KClassExtensions.kt b/core/reflection.jvm/src/kotlin/reflect/KClassExtensions.kt index 837fcece7b4..eb4acb75085 100644 --- a/core/reflection.jvm/src/kotlin/reflect/KClassExtensions.kt +++ b/core/reflection.jvm/src/kotlin/reflect/KClassExtensions.kt @@ -114,6 +114,16 @@ public val KClass<*>.declaredMemberExtensionFunctions: Collection> .filterIsInstance>() .toList() +/** + * Returns static properties declared in this class. + * Only properties representing static fields of Java classes are considered static. + */ +public val KClass<*>.staticProperties: Collection> + get() = (this as KClassImpl) + .getMembers(staticScope, declaredOnly = false, nonExtensions = true, extensions = false) + .filterIsInstance>() + .toList() + /** * Returns non-extension properties declared in this class and all of its superclasses. */ diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/RuntimeTypeMapper.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/RuntimeTypeMapper.kt index 1bb5a683606..a195ee3b671 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/RuntimeTypeMapper.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/RuntimeTypeMapper.kt @@ -149,7 +149,8 @@ object RuntimeTypeMapper { } } - fun mapPropertySignature(property: PropertyDescriptor): JvmPropertySignature { + fun mapPropertySignature(possiblyOverriddenProperty: PropertyDescriptor): JvmPropertySignature { + val property = DescriptorUtils.unwrapFakeOverride(possiblyOverriddenProperty) if (property is DeserializedPropertyDescriptor) { val proto = property.proto if (!proto.hasExtension(JvmProtoBuf.propertySignature)) {