From 93656c93c11fa3af8e732076c6db57f1461c1e5a Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Wed, 15 Jul 2015 23:50:45 +0300 Subject: [PATCH] Support KPackage.members, functions and properties --- .../reflection/packages/simpleGetMembers.kt | 23 +++++++ ...lackBoxWithStdlibCodegenTestGenerated.java | 15 +++++ core/builtins/src/kotlin/reflect/KClass.kt | 2 +- .../kotlin/reflect/KDeclarationContainer.kt | 7 +- .../src/kotlin/reflect/KClassExtensions.kt | 11 ---- .../KDeclarationContainerExtensions.kt | 30 +++++++++ .../src/kotlin/reflect/KPackageExtensions.kt | 37 +++++++++++ .../jvm/internal/KCallableContainerImpl.kt | 64 ++++++++++++++++++- .../kotlin/reflect/jvm/internal/KClassImpl.kt | 54 +--------------- .../reflect/jvm/internal/KProperty0Impl.kt | 5 ++ .../reflect/jvm/internal/KProperty2Impl.kt | 8 +-- 11 files changed, 184 insertions(+), 72 deletions(-) create mode 100644 compiler/testData/codegen/boxWithStdlib/reflection/packages/simpleGetMembers.kt create mode 100644 core/reflection.jvm/src/kotlin/reflect/KDeclarationContainerExtensions.kt create mode 100644 core/reflection.jvm/src/kotlin/reflect/KPackageExtensions.kt diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/packages/simpleGetMembers.kt b/compiler/testData/codegen/boxWithStdlib/reflection/packages/simpleGetMembers.kt new file mode 100644 index 00000000000..a71ad49e403 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/reflection/packages/simpleGetMembers.kt @@ -0,0 +1,23 @@ +import kotlin.reflect.* +import kotlin.reflect.jvm.* +import kotlin.test.assertEquals + +fun foo() {} +fun Int.bar() {} +val baz = 42 +val Int.quux: Int get() = this + +fun box(): String { + fun check(actual: Collection>, expected: Set) { + assertEquals(expected, actual.map { it.name }.toSet()) + } + + val kp = Class.forName("_DefaultPackage").kotlinPackage ?: return "Fail: package class not found" + + check(kp.members, setOf("bar", "baz", "foo", "box", "quux")) + check(kp.functions, setOf("bar", "foo", "box")) + check(kp.properties, setOf("baz")) + check(kp.extensionProperties, setOf("quux")) + + return "OK" +} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java index f005b89c563..2316b7a9ec9 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java @@ -3214,6 +3214,21 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode } } + @TestMetadata("compiler/testData/codegen/boxWithStdlib/reflection/packages") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Packages extends AbstractBlackBoxCodegenTest { + public void testAllFilesPresentInPackages() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxWithStdlib/reflection/packages"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("simpleGetMembers.kt") + public void testSimpleGetMembers() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/packages/simpleGetMembers.kt"); + doTestWithStdlib(fileName); + } + } + @TestMetadata("compiler/testData/codegen/boxWithStdlib/reflection/parameters") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/core/builtins/src/kotlin/reflect/KClass.kt b/core/builtins/src/kotlin/reflect/KClass.kt index 39cd612a24a..81660d6de15 100644 --- a/core/builtins/src/kotlin/reflect/KClass.kt +++ b/core/builtins/src/kotlin/reflect/KClass.kt @@ -42,7 +42,7 @@ public interface KClass : KDeclarationContainer { * All functions and properties accessible in this class, including those declared in this class * and all of its superclasses. Does not include constructors. */ - public val members: Collection> + override val members: Collection> /** * All constructors declared in this class. diff --git a/core/builtins/src/kotlin/reflect/KDeclarationContainer.kt b/core/builtins/src/kotlin/reflect/KDeclarationContainer.kt index 89e02989564..447cfb33d49 100644 --- a/core/builtins/src/kotlin/reflect/KDeclarationContainer.kt +++ b/core/builtins/src/kotlin/reflect/KDeclarationContainer.kt @@ -20,4 +20,9 @@ package kotlin.reflect * Represents an entity which may contain declarations of any other entities, * such as a class or a package. */ -public interface KDeclarationContainer +public interface KDeclarationContainer { + /** + * All functions and properties accessible in this container. + */ + public val members: Collection> +} diff --git a/core/reflection.jvm/src/kotlin/reflect/KClassExtensions.kt b/core/reflection.jvm/src/kotlin/reflect/KClassExtensions.kt index e37794e2ff4..63878a8c5cb 100644 --- a/core/reflection.jvm/src/kotlin/reflect/KClassExtensions.kt +++ b/core/reflection.jvm/src/kotlin/reflect/KClassExtensions.kt @@ -18,17 +18,6 @@ package kotlin.reflect import kotlin.reflect.jvm.internal.KClassImpl -/** - * Returns all functions declared in this class and all of its superclasses. - * If this is a Java class, it includes all non-static methods declared in the class and the superclasses, - * as well as static methods declared in the class. - */ -public val KClass.functions: Collection> - get() = (this as KClassImpl) - .getMembers(declaredOnly = false, nonExtensions = true, extensions = true) - .filterIsInstance>() - .toList() - /** * Returns all functions declared in this class. * If this is a Java class, it includes both non-static and static methods. diff --git a/core/reflection.jvm/src/kotlin/reflect/KDeclarationContainerExtensions.kt b/core/reflection.jvm/src/kotlin/reflect/KDeclarationContainerExtensions.kt new file mode 100644 index 00000000000..6d13b504c7a --- /dev/null +++ b/core/reflection.jvm/src/kotlin/reflect/KDeclarationContainerExtensions.kt @@ -0,0 +1,30 @@ +/* + * 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.KCallableContainerImpl + +/** + * Returns all functions declared in this container. + * If this container is a Java class, it includes all non-static methods declared in the class + * and the superclasses, as well as static methods declared in the class. + */ +public val KDeclarationContainer.functions: Collection> + get() = (this as KCallableContainerImpl) + .getMembers(declaredOnly = false, nonExtensions = true, extensions = true) + .filterIsInstance>() + .toList() diff --git a/core/reflection.jvm/src/kotlin/reflect/KPackageExtensions.kt b/core/reflection.jvm/src/kotlin/reflect/KPackageExtensions.kt new file mode 100644 index 00000000000..45f27b73490 --- /dev/null +++ b/core/reflection.jvm/src/kotlin/reflect/KPackageExtensions.kt @@ -0,0 +1,37 @@ +/* + * 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.KPackageImpl + +/** + * Returns all non-extension properties declared in this package. + */ +public val KPackage.properties: Collection> + get() = (this as KPackageImpl) + .getMembers(declaredOnly = false, nonExtensions = true, extensions = false) + .filterIsInstance>() + .toList() + +/** + * Returns all extension properties declared in this package. + */ +public val KPackage.extensionProperties: Collection> + get() = (this as KPackageImpl) + .getMembers(declaredOnly = false, nonExtensions = false, extensions = true) + .filterIsInstance>() + .toList() diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KCallableContainerImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KCallableContainerImpl.kt index 06396056aca..0e5b9e5aec1 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KCallableContainerImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KCallableContainerImpl.kt @@ -16,9 +16,8 @@ package kotlin.reflect.jvm.internal -import org.jetbrains.kotlin.descriptors.ConstructorDescriptor -import org.jetbrains.kotlin.descriptors.FunctionDescriptor -import org.jetbrains.kotlin.descriptors.PropertyDescriptor +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.impl.DeclarationDescriptorVisitorEmptyBodies 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 @@ -31,6 +30,7 @@ import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf.JvmType.PrimitiveType.* import java.lang.reflect.Field import java.lang.reflect.Method +import kotlin.reflect.KCallable import kotlin.reflect.KDeclarationContainer import kotlin.reflect.KotlinReflectionInternalError @@ -46,6 +46,64 @@ abstract class KCallableContainerImpl : KDeclarationContainer { abstract val constructorDescriptors: Collection + override val members: Collection> + get() = getMembers(declaredOnly = false, nonExtensions = true, extensions = true).toList() + + fun getMembers(declaredOnly: Boolean, nonExtensions: Boolean, extensions: Boolean): Sequence> { + val visitor = object : DeclarationDescriptorVisitorEmptyBodies?, Unit>() { + private fun skipCallable(descriptor: CallableMemberDescriptor): Boolean { + if (declaredOnly && !descriptor.getKind().isReal()) return true + + val isExtension = descriptor.getExtensionReceiverParameter() != null + if (isExtension && !extensions) return true + if (!isExtension && !nonExtensions) return true + + return false + } + + override fun visitPropertyDescriptor(descriptor: PropertyDescriptor, data: Unit): KCallable<*>? { + return if (skipCallable(descriptor)) null else createProperty(descriptor) + } + + override fun visitFunctionDescriptor(descriptor: FunctionDescriptor, data: Unit): KCallable<*>? { + return if (skipCallable(descriptor)) null else KFunctionImpl(this@KCallableContainerImpl, descriptor) + } + + override fun visitConstructorDescriptor(descriptor: ConstructorDescriptor, data: Unit): KCallable<*>? { + throw IllegalStateException("No constructors should appear in this scope: $descriptor") + } + } + + return scope.getAllDescriptors().asSequence() + .filter { descriptor -> + descriptor !is MemberDescriptor || descriptor.getVisibility() != Visibilities.INVISIBLE_FAKE + } + .map { descriptor -> + descriptor.accept(visitor, Unit) + } + .filterNotNull() + } + + private fun createProperty(descriptor: PropertyDescriptor): KPropertyImpl<*> { + val receiverCount = (descriptor.dispatchReceiverParameter?.let { 1 } ?: 0) + + (descriptor.extensionReceiverParameter?.let { 1 } ?: 0) + + when { + descriptor.isVar -> when (receiverCount) { + 0 -> return KMutableProperty0Impl(this, descriptor) + 1 -> return KMutableProperty1Impl(this, descriptor) + 2 -> return KMutableProperty2Impl(this, descriptor) + } + else -> when (receiverCount) { + 0 -> return KProperty0Impl(this, descriptor) + 1 -> return KProperty1Impl(this, descriptor) + 2 -> return KProperty2Impl(this, descriptor) + } + } + + throw KotlinReflectionInternalError("Unsupported property: $descriptor") + } + fun findPropertyDescriptor(name: String, signature: String): PropertyDescriptor { val properties = scope .getProperties(Name.guess(name)) 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 4f0970724d1..a814fd44568 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt @@ -16,13 +16,12 @@ package kotlin.reflect.jvm.internal -import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.descriptors.impl.DeclarationDescriptorVisitorEmptyBodies +import org.jetbrains.kotlin.descriptors.ClassKind +import org.jetbrains.kotlin.descriptors.ConstructorDescriptor import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.resolve.scopes.ChainedScope import org.jetbrains.kotlin.resolve.scopes.JetScope import org.jetbrains.kotlin.serialization.deserialization.findClassAcrossModuleDependencies -import kotlin.reflect.KCallable import kotlin.reflect.KClass import kotlin.reflect.KFunction import kotlin.reflect.KotlinReflectionInternalError @@ -84,61 +83,12 @@ class KClassImpl(override val jClass: Class) : KCallableContainerImpl(), K } } - override val members: Collection> - get() = getMembers(declaredOnly = false, nonExtensions = true, extensions = true).toList() - @suppress("UNCHECKED_CAST") override val constructors: Collection> get() = constructorDescriptors.map { KFunctionImpl(this, it) as KFunction } - fun getMembers(declaredOnly: Boolean, nonExtensions: Boolean, extensions: Boolean): Sequence> { - val visitor = object : DeclarationDescriptorVisitorEmptyBodies?, Nothing>() { - private fun skipCallable(descriptor: CallableMemberDescriptor): Boolean { - if (declaredOnly && !descriptor.getKind().isReal()) return true - - val isExtension = descriptor.getExtensionReceiverParameter() != null - if (isExtension && !extensions) return true - if (!isExtension && !nonExtensions) return true - - return false - } - - override fun visitPropertyDescriptor(descriptor: PropertyDescriptor, data: Nothing?): KCallable<*>? { - if (skipCallable(descriptor)) return null - - return if (descriptor.getExtensionReceiverParameter() == null) { - if (descriptor.isVar()) KMutableProperty1Impl(this@KClassImpl, descriptor) - else KProperty1Impl(this@KClassImpl, descriptor) - } - else { - if (descriptor.isVar()) KMutableProperty2Impl(this@KClassImpl, descriptor) - else KProperty2Impl(this@KClassImpl, descriptor) - } - } - - override fun visitFunctionDescriptor(descriptor: FunctionDescriptor, data: Nothing?): KCallable<*>? { - if (skipCallable(descriptor)) return null - - return KFunctionImpl(this@KClassImpl, descriptor) - } - - override fun visitConstructorDescriptor(descriptor: ConstructorDescriptor, data: Nothing?): KCallable<*>? { - throw IllegalStateException("No constructors should appear in this scope: $descriptor") - } - } - - return scope.getAllDescriptors().asSequence() - .filter { descriptor -> - descriptor !is MemberDescriptor || descriptor.getVisibility() != Visibilities.INVISIBLE_FAKE - } - .map { descriptor -> - descriptor.accept(visitor, null) - } - .filterNotNull() - } - override fun equals(other: Any?): Boolean = other is KClassImpl<*> && jClass == other.jClass diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty0Impl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty0Impl.kt index 14fac033c94..6818e08ad38 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty0Impl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty0Impl.kt @@ -16,6 +16,7 @@ package kotlin.reflect.jvm.internal +import org.jetbrains.kotlin.descriptors.PropertyDescriptor import java.lang.reflect.Method import kotlin.jvm.internal.MutablePropertyReference0 import kotlin.jvm.internal.PropertyReference0 @@ -24,6 +25,8 @@ import kotlin.reflect.KMutableProperty0 import kotlin.reflect.KProperty0 open class KProperty0Impl : DescriptorBasedProperty, KProperty0, KPropertyImpl { + constructor(container: KCallableContainerImpl, descriptor: PropertyDescriptor) : super(container, descriptor) + constructor(container: KCallableContainerImpl, name: String, signature: String) : super(container, name, signature) override val name: String get() = descriptor.getName().asString() @@ -48,6 +51,8 @@ open class KProperty0Impl : DescriptorBasedProperty, KProperty0, KP } open class KMutableProperty0Impl : KProperty0Impl, KMutableProperty0, KMutablePropertyImpl { + constructor(container: KCallableContainerImpl, descriptor: PropertyDescriptor) : super(container, descriptor) + constructor(container: KCallableContainerImpl, name: String, signature: String) : super(container, name, signature) override val setter by ReflectProperties.lazy { Setter(this) } diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty2Impl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty2Impl.kt index aaa13a41154..366965f4032 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty2Impl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KProperty2Impl.kt @@ -24,9 +24,9 @@ import kotlin.reflect.KMutableProperty2 import kotlin.reflect.KProperty2 open class KProperty2Impl : DescriptorBasedProperty, KProperty2, KPropertyImpl { - constructor(container: KClassImpl, name: String, signature: String) : super(container, name, signature) + constructor(container: KCallableContainerImpl, name: String, signature: String) : super(container, name, signature) - constructor(container: KClassImpl, descriptor: PropertyDescriptor) : super(container, descriptor) + constructor(container: KCallableContainerImpl, descriptor: PropertyDescriptor) : super(container, descriptor) override val name: String get() = descriptor.getName().asString() @@ -53,9 +53,9 @@ open class KProperty2Impl : DescriptorBasedProperty, KProperty2< class KMutableProperty2Impl : KProperty2Impl, KMutableProperty2, KMutablePropertyImpl { - constructor(container: KClassImpl, name: String, signature: String) : super(container, name, signature) + constructor(container: KCallableContainerImpl, name: String, signature: String) : super(container, name, signature) - constructor(container: KClassImpl, descriptor: PropertyDescriptor) : super(container, descriptor) + constructor(container: KCallableContainerImpl, descriptor: PropertyDescriptor) : super(container, descriptor) override val setter by ReflectProperties.lazy { Setter(this) }