diff --git a/compiler/testData/codegen/boxWithJava/reflection/kotlinPropertyInheritedInJava/K.kt b/compiler/testData/codegen/boxWithJava/reflection/kotlinPropertyInheritedInJava/K.kt index 6b4a03594b8..7cb9078f898 100644 --- a/compiler/testData/codegen/boxWithJava/reflection/kotlinPropertyInheritedInJava/K.kt +++ b/compiler/testData/codegen/boxWithJava/reflection/kotlinPropertyInheritedInJava/K.kt @@ -22,16 +22,17 @@ fun box(): String { val klass = javaClass().kotlin - val prop2 = klass.getProperties().firstOrNull { it.name == "prop" } - ?: "Fail: no 'prop' property in getProperties()" - if (prop != prop2) return "Fail: property references from :: and from getProperties() differ" + if (klass.declaredProperties.isNotEmpty()) return "Fail: declaredProperties should be empty" + if (klass.declaredExtensionProperties.isNotEmpty()) return "Fail: declaredExtensionProperties should be empty" + + val prop2 = klass.properties.firstOrNull { it.name == "prop" } ?: "Fail: no 'prop' property in properties" + if (prop != prop2) return "Fail: property references from :: and from properties differ: $prop != $prop2" if (prop2 !is KMutableMemberProperty<*, *>) return "Fail instanceof 2" (prop2 as KMutableMemberProperty).set(j, "::)") if (prop.get(j) != "::)") return "Fail get after 2: ${prop[j]}" - val ext = klass.getExtensionProperties().firstOrNull { it.name == "ext" } - ?: "Fail: no 'ext' property in getProperties()" + val ext = klass.extensionProperties.firstOrNull { it.name == "ext" } ?: "Fail: no 'ext' property in extensionProperties" ext as KMemberExtensionProperty val fortyTwo = ext.get(j, 42) if (fortyTwo != 42) return "Fail ext get: $fortyTwo" diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/memberExtensionToString.kt b/compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/memberExtensionToString.kt index 9c6af439aee..4ea9ba0ddfc 100644 --- a/compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/memberExtensionToString.kt +++ b/compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/memberExtensionToString.kt @@ -7,6 +7,6 @@ class A { } fun box(): String { - val p = javaClass().kotlin.getExtensionProperties().single() + val p = javaClass().kotlin.extensionProperties.single() return if ("$p" == "var A.(kotlin.String.)id") "OK" else "Fail $p" } diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/properties/allVsDeclared.kt b/compiler/testData/codegen/boxWithStdlib/reflection/properties/allVsDeclared.kt new file mode 100644 index 00000000000..a35b106ffe7 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/reflection/properties/allVsDeclared.kt @@ -0,0 +1,23 @@ +import kotlin.reflect.* +import kotlin.test.* + +open class Super { + val a: Int = 1 + val String.b: String get() = this +} + +class Sub : Super() { + val c: Double = 1.0 + val Char.d: Char get() = this +} + +fun box(): String { + val sub = Sub::class + + assertEquals(listOf("a", "c"), sub.properties.map { it.name }.sort()) + assertEquals(listOf("b", "d"), sub.extensionProperties.map { it.name }.sort()) + assertEquals(listOf("c"), sub.declaredProperties.map { it.name }) + assertEquals(listOf("d"), sub.declaredExtensionProperties.map { it.name }) + + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/properties/callPrivatePropertyFromGetProperties.kt b/compiler/testData/codegen/boxWithStdlib/reflection/properties/callPrivatePropertyFromGetProperties.kt index 8a18c441f61..59589294b1c 100644 --- a/compiler/testData/codegen/boxWithStdlib/reflection/properties/callPrivatePropertyFromGetProperties.kt +++ b/compiler/testData/codegen/boxWithStdlib/reflection/properties/callPrivatePropertyFromGetProperties.kt @@ -4,7 +4,7 @@ import kotlin.reflect.jvm.* class K(private val value: String) fun box(): String { - val p = javaClass().kotlin.getProperties().single() as KMemberProperty + val p = javaClass().kotlin.properties.single() as KMemberProperty try { return p.get(K("Fail: private property should not be accessible by default")) diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/properties/fakeOverridesInSubclass.kt b/compiler/testData/codegen/boxWithStdlib/reflection/properties/fakeOverridesInSubclass.kt index fad0ee62bd3..91d80e0db64 100644 --- a/compiler/testData/codegen/boxWithStdlib/reflection/properties/fakeOverridesInSubclass.kt +++ b/compiler/testData/codegen/boxWithStdlib/reflection/properties/fakeOverridesInSubclass.kt @@ -1,4 +1,5 @@ import kotlin.reflect.jvm.* +import kotlin.reflect.* import kotlin.test.* open class Super(val r: String) @@ -6,7 +7,10 @@ open class Super(val r: String) class Sub(r: String) : Super(r) fun box(): String { - val props = javaClass().kotlin.getProperties() - assertEquals(listOf("r"), props.map { it.name }) - return props.single().get(Sub("OK")).toString() + val props = javaClass().kotlin.declaredProperties + if (!props.isEmpty()) return "Fail $props" + + val allProps = javaClass().kotlin.properties + assertEquals(listOf("r"), allProps.map { it.name }) + return allProps.single().get(Sub("OK")) as String } diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/properties/genericClassLiteralPropertyReceiverIsStar.kt b/compiler/testData/codegen/boxWithStdlib/reflection/properties/genericClassLiteralPropertyReceiverIsStar.kt index 6ee2f3fec80..c87de4331d0 100644 --- a/compiler/testData/codegen/boxWithStdlib/reflection/properties/genericClassLiteralPropertyReceiverIsStar.kt +++ b/compiler/testData/codegen/boxWithStdlib/reflection/properties/genericClassLiteralPropertyReceiverIsStar.kt @@ -5,7 +5,7 @@ class A { } fun box(): String { - val k = A::class.getProperties().single() + val k = A::class.properties.single() k : KMemberProperty, *> return k.get(A()) as String } diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/properties/getExtensionPropertiesMutableVsReadonly.kt b/compiler/testData/codegen/boxWithStdlib/reflection/properties/getExtensionPropertiesMutableVsReadonly.kt index e69f3c4e7b4..76b17b83f51 100644 --- a/compiler/testData/codegen/boxWithStdlib/reflection/properties/getExtensionPropertiesMutableVsReadonly.kt +++ b/compiler/testData/codegen/boxWithStdlib/reflection/properties/getExtensionPropertiesMutableVsReadonly.kt @@ -13,7 +13,7 @@ class A { } fun box(): String { - val props = javaClass().kotlin.getExtensionProperties() + val props = javaClass().kotlin.extensionProperties val readonly = props.single { it.name == "readonly" } assert(readonly !is KMutableMemberExtensionProperty) { "Fail 1: $readonly" } val mutable = props.single { it.name == "mutable" } diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/properties/getPropertiesMutableVsReadonly.kt b/compiler/testData/codegen/boxWithStdlib/reflection/properties/getPropertiesMutableVsReadonly.kt index 74b464d6f72..435243a6938 100644 --- a/compiler/testData/codegen/boxWithStdlib/reflection/properties/getPropertiesMutableVsReadonly.kt +++ b/compiler/testData/codegen/boxWithStdlib/reflection/properties/getPropertiesMutableVsReadonly.kt @@ -6,7 +6,7 @@ class A(val readonly: String) { } fun box(): String { - val props = javaClass().kotlin.getProperties() + val props = javaClass().kotlin.properties val readonly = props.single { it.name == "readonly" } assert(readonly !is KMutableMemberProperty) { "Fail 1: $readonly" } val mutable = props.single { it.name == "mutable" } diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/properties/memberAndMemberExtensionWithSameName.kt b/compiler/testData/codegen/boxWithStdlib/reflection/properties/memberAndMemberExtensionWithSameName.kt index 0bf363f21d1..b194d12e01c 100644 --- a/compiler/testData/codegen/boxWithStdlib/reflection/properties/memberAndMemberExtensionWithSameName.kt +++ b/compiler/testData/codegen/boxWithStdlib/reflection/properties/memberAndMemberExtensionWithSameName.kt @@ -9,13 +9,13 @@ class A { fun box(): String { run { - val foo: KMemberProperty = javaClass().kotlin.getProperties().single() + val foo: KMemberProperty = javaClass().kotlin.properties.single() assert(foo.name == "foo") { "Fail name: $foo (${foo.name})" } assert(foo.get(A()) == "member") { "Fail value: ${foo[A()]}" } } run { - val foo: KMemberExtensionProperty = javaClass().kotlin.getExtensionProperties().single() + val foo: KMemberExtensionProperty = javaClass().kotlin.extensionProperties.single() assert(foo.name == "foo") { "Fail name: $foo (${foo.name})" } foo as KMemberExtensionProperty assert(foo.get(A(), Unit) == "extension") { "Fail value: ${foo[A(), Unit]}" } diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/properties/simpleGetProperties.kt b/compiler/testData/codegen/boxWithStdlib/reflection/properties/simpleGetProperties.kt index 6ddfd38390b..a03f90a6c86 100644 --- a/compiler/testData/codegen/boxWithStdlib/reflection/properties/simpleGetProperties.kt +++ b/compiler/testData/codegen/boxWithStdlib/reflection/properties/simpleGetProperties.kt @@ -13,7 +13,7 @@ class A(param: String) { fun box(): String { val klass = javaClass().kotlin - val props = klass.getProperties() + val props = klass.properties val names = props.map { it.name }.toSortedList() assert(names == listOf("anyVar", "int", "string")) { "Fail names: $props" } diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java index 54f8dcc7858..da6c2574d52 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java @@ -2848,6 +2848,12 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxWithStdlib/reflection/properties"), Pattern.compile("^(.+)\\.kt$"), true); } + @TestMetadata("allVsDeclared.kt") + public void testAllVsDeclared() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/properties/allVsDeclared.kt"); + doTestWithStdlib(fileName); + } + @TestMetadata("callPrivatePropertyFromGetProperties.kt") public void testCallPrivatePropertyFromGetProperties() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/properties/callPrivatePropertyFromGetProperties.kt"); diff --git a/core/builtins/src/kotlin/reflect/KClass.kt b/core/builtins/src/kotlin/reflect/KClass.kt index c4293ef81a7..9ced2887c28 100644 --- a/core/builtins/src/kotlin/reflect/KClass.kt +++ b/core/builtins/src/kotlin/reflect/KClass.kt @@ -19,7 +19,7 @@ package kotlin.reflect public trait KClass { public val simpleName: String? - public fun getProperties(): Collection> + public val properties: Collection> - public fun getExtensionProperties(): Collection> + public val extensionProperties: Collection> } diff --git a/core/reflection.jvm/src/kotlin/reflect/KClassExtensions.kt b/core/reflection.jvm/src/kotlin/reflect/KClassExtensions.kt new file mode 100644 index 00000000000..20fee73fd8e --- /dev/null +++ b/core/reflection.jvm/src/kotlin/reflect/KClassExtensions.kt @@ -0,0 +1,25 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package kotlin.reflect + +import kotlin.reflect.jvm.internal.KClassImpl + +public val KClass.declaredProperties: Collection> + get() = (this as KClassImpl).getProperties(declared = true) + +public val KClass.declaredExtensionProperties: Collection> + get() = (this as KClassImpl).getExtensionProperties(declared = true) diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt index 202e4b3922f..40db574ea77 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt @@ -43,39 +43,39 @@ class KClassImpl(override val jClass: Class) : KCallableContainerImpl(), K return if (name.isSpecial()) null else name.asString() } - override fun getProperties(): Collection> { - return scope.getAllDescriptors().stream() - .filterIsInstance() - .filter { descriptor -> - descriptor.getExtensionReceiverParameter() == null - } - .map { descriptor -> - if (descriptor.isVar()) KMutableMemberPropertyImpl(this) { descriptor } - else KMemberPropertyImpl(this) { descriptor } - } - .toList() - } + override val properties: Collection> + get() = getProperties(declared = false) - override fun getExtensionProperties(): Collection> { - return scope.getAllDescriptors().stream() - .filterIsInstance() - .filter { descriptor -> - descriptor.getExtensionReceiverParameter() != null - } - .map { descriptor -> - if (descriptor.isVar()) KMutableMemberExtensionPropertyImpl(this) { descriptor } - else KMemberExtensionPropertyImpl(this) { descriptor } - } - .toList() - } + override val extensionProperties: Collection> + get() = getExtensionProperties(declared = false) - fun memberProperty(name: String): KMemberProperty { - return KMemberPropertyImpl(this, findPropertyDescriptor(name)) - } + fun getProperties(declared: Boolean): Collection> = + getProperties(extension = false, declared = declared) { descriptor -> + if (descriptor.isVar()) KMutableMemberPropertyImpl(this) { descriptor } + else KMemberPropertyImpl(this) { descriptor } + } - fun mutableMemberProperty(name: String): KMutableMemberProperty { - return KMutableMemberPropertyImpl(this, findPropertyDescriptor(name)) - } + fun getExtensionProperties(declared: Boolean): Collection> = + getProperties(extension = true, declared = declared) { descriptor -> + if (descriptor.isVar()) KMutableMemberExtensionPropertyImpl(this) { descriptor } + else KMemberExtensionPropertyImpl(this) { descriptor } + } + + private fun

> getProperties(extension: Boolean, declared: Boolean, create: (PropertyDescriptor) -> P): Collection

= + scope.getAllDescriptors().sequence() + .filterIsInstance() + .filter { descriptor -> + (descriptor.getExtensionReceiverParameter() != null) == extension && + (descriptor.getKind().isReal() || !declared) + } + .map(create) + .toList() + + fun memberProperty(name: String): KMemberProperty = + KMemberPropertyImpl(this, findPropertyDescriptor(name)) + + fun mutableMemberProperty(name: String): KMutableMemberProperty = + KMutableMemberPropertyImpl(this, findPropertyDescriptor(name)) override fun equals(other: Any?): Boolean = other is KClassImpl<*> && jClass == other.jClass