Support KClass.objectInstance for objects and companion objects

This commit is contained in:
Alexander Udalov
2015-07-23 18:40:24 +03:00
parent 2eb5201575
commit 6878453d44
5 changed files with 60 additions and 2 deletions
@@ -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"
}
@@ -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");
+6 -1
View File
@@ -24,7 +24,7 @@ package kotlin.reflect
*
* @param T the type of the class.
*/
public interface KClass<T> : KDeclarationContainer, KAnnotatedElement {
public interface KClass<T : Any> : 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<T> : KDeclarationContainer, KAnnotatedElement {
* All constructors declared in this class.
*/
public val constructors: Collection<KFunction<T>>
/**
* The instance of the object declaration, or `null` if this class is not an object declaration.
*/
public val objectInstance: T?
}
@@ -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<T>(override val jClass: Class<T>) : KCallableContainerImpl(), KClass<T>, KAnnotatedElementImpl {
class KClassImpl<T : Any>(override val jClass: Class<T>) : KCallableContainerImpl(), KClass<T>, KAnnotatedElementImpl {
val descriptor by ReflectProperties.lazySoft {
val classId = classId
@@ -92,6 +93,20 @@ class KClassImpl<T>(override val jClass: Class<T>) : KCallableContainerImpl(), K
KFunctionImpl(this, it) as KFunction<T>
}
@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
@@ -36,5 +36,8 @@ public class ClassReference(override val jClass: Class<*>) : KClass<Any>, Declar
override val annotations: List<Annotation>
get() = error()
override val objectInstance: Any?
get() = error()
private fun error(): Nothing = throw KotlinReflectionNotSupportedError()
}