From 6878453d4466ed023803a28850b36e3cda517e23 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Thu, 23 Jul 2015 18:40:24 +0300 Subject: [PATCH] Support KClass.objectInstance for objects and companion objects --- .../reflection/classes/objectInstance.kt | 29 +++++++++++++++++++ ...lackBoxWithStdlibCodegenTestGenerated.java | 6 ++++ core/builtins/src/kotlin/reflect/KClass.kt | 7 ++++- .../kotlin/reflect/jvm/internal/KClassImpl.kt | 17 ++++++++++- .../src/kotlin/jvm/internal/ClassReference.kt | 3 ++ 5 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 compiler/testData/codegen/boxWithStdlib/reflection/classes/objectInstance.kt diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/classes/objectInstance.kt b/compiler/testData/codegen/boxWithStdlib/reflection/classes/objectInstance.kt new file mode 100644 index 00000000000..f6cf2a7326c --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/reflection/classes/objectInstance.kt @@ -0,0 +1,29 @@ +import kotlin.test.assertEquals + +object Obj { + fun foo() = 1 +} + +class A { + companion object { + fun foo() = 2 + } +} + +class B { + companion object Factory { + fun foo() = 3 + } +} + +class C + +fun box(): String { + assertEquals(1, Obj::class.objectInstance!!.foo()) + assertEquals(2, A.Companion::class.objectInstance!!.foo()) + assertEquals(3, B.Factory::class.objectInstance!!.foo()) + + assertEquals(null, C::class.objectInstance) + + 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 ec2f8c8b6db..b98350e5cc7 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java @@ -2994,6 +2994,12 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode doTestWithStdlib(fileName); } + @TestMetadata("objectInstance.kt") + public void testObjectInstance() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/classes/objectInstance.kt"); + doTestWithStdlib(fileName); + } + @TestMetadata("qualifiedName.kt") public void testQualifiedName() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/classes/qualifiedName.kt"); diff --git a/core/builtins/src/kotlin/reflect/KClass.kt b/core/builtins/src/kotlin/reflect/KClass.kt index 43bdc10f907..d59938f460f 100644 --- a/core/builtins/src/kotlin/reflect/KClass.kt +++ b/core/builtins/src/kotlin/reflect/KClass.kt @@ -24,7 +24,7 @@ package kotlin.reflect * * @param T the type of the class. */ -public interface KClass : KDeclarationContainer, KAnnotatedElement { +public interface KClass : KDeclarationContainer, KAnnotatedElement { /** * The simple name of the class as it was declared in the source code, * or `null` if the class has no name (if, for example, it is an anonymous object literal). @@ -48,4 +48,9 @@ public interface KClass : KDeclarationContainer, KAnnotatedElement { * All constructors declared in this class. */ public val constructors: Collection> + + /** + * The instance of the object declaration, or `null` if this class is not an object declaration. + */ + public val objectInstance: T? } 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 d28422d1341..511e89dfbf6 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt @@ -19,6 +19,7 @@ package kotlin.reflect.jvm.internal import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.ConstructorDescriptor import org.jetbrains.kotlin.descriptors.annotations.Annotated +import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.resolve.scopes.ChainedScope import org.jetbrains.kotlin.resolve.scopes.JetScope @@ -27,7 +28,7 @@ import kotlin.reflect.KClass import kotlin.reflect.KFunction import kotlin.reflect.KotlinReflectionInternalError -class KClassImpl(override val jClass: Class) : KCallableContainerImpl(), KClass, KAnnotatedElementImpl { +class KClassImpl(override val jClass: Class) : KCallableContainerImpl(), KClass, KAnnotatedElementImpl { val descriptor by ReflectProperties.lazySoft { val classId = classId @@ -92,6 +93,20 @@ class KClassImpl(override val jClass: Class) : KCallableContainerImpl(), K KFunctionImpl(this, it) as KFunction } + @suppress("UNCHECKED_CAST") + override val objectInstance: T? by ReflectProperties.lazy { + val descriptor = descriptor + if (descriptor.kind != ClassKind.OBJECT) return@lazy null + + val field = if (descriptor.isCompanionObject) { + jClass.enclosingClass.getDeclaredField(descriptor.name.asString()) + } + else { + jClass.getDeclaredField(JvmAbi.INSTANCE_FIELD) + } + field.get(null) as T + } + override fun equals(other: Any?): Boolean = other is KClassImpl<*> && jClass == other.jClass diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/ClassReference.kt b/core/runtime.jvm/src/kotlin/jvm/internal/ClassReference.kt index e0ceb5e644e..47b90311ca0 100644 --- a/core/runtime.jvm/src/kotlin/jvm/internal/ClassReference.kt +++ b/core/runtime.jvm/src/kotlin/jvm/internal/ClassReference.kt @@ -36,5 +36,8 @@ public class ClassReference(override val jClass: Class<*>) : KClass, Declar override val annotations: List get() = error() + override val objectInstance: Any? + get() = error() + private fun error(): Nothing = throw KotlinReflectionNotSupportedError() }