Support KClass.constructors in reflection

This commit is contained in:
Alexander Udalov
2015-07-13 18:59:10 +03:00
parent da5cffdb60
commit 81ef1c19d8
12 changed files with 190 additions and 51 deletions
@@ -0,0 +1,19 @@
import kotlin.reflect.*
import kotlin.test.assertTrue
interface Interface
annotation class Anno(val x: Int)
object Obj
class C {
companion object
}
fun box(): String {
assertTrue(Interface::class.constructors.isEmpty())
assertTrue(Anno::class.constructors.isEmpty())
assertTrue(Obj::class.constructors.isEmpty())
assertTrue(C.Companion::class.constructors.isEmpty())
return "OK"
}
@@ -0,0 +1,29 @@
import java.util.Collections
import kotlin.reflect.*
import kotlin.test.assertEquals
import kotlin.test.assertTrue
open class A private constructor(x: Int) {
public constructor(s: String): this(s.length())
constructor(): this("")
}
class B : A("")
class C {
class Nested
inner class Inner
}
fun box(): String {
assertEquals(3, A::class.constructors.size())
assertEquals(1, B::class.constructors.size())
assertTrue(Collections.disjoint(A::class.members, A::class.constructors))
assertTrue(Collections.disjoint(B::class.members, B::class.constructors))
assertEquals(1, C.Nested::class.constructors.size())
assertEquals(1, C.Inner::class.constructors.size())
return "OK"
}
@@ -2847,11 +2847,23 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxWithStdlib/reflection/constructors"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("classesWithoutConstructors.kt")
public void testClassesWithoutConstructors() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/constructors/classesWithoutConstructors.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("constructorName.kt")
public void testConstructorName() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/constructors/constructorName.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("simpleGetConstructors.kt")
public void testSimpleGetConstructors() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/constructors/simpleGetConstructors.kt");
doTestWithStdlib(fileName);
}
}
@TestMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing")
+7 -2
View File
@@ -39,8 +39,13 @@ public interface KClass<T> : KDeclarationContainer {
public val qualifiedName: String?
/**
* All elements accessible in this class, including functions and properties
* declared in this class and all of its superclasses.
* 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<KCallable<*>>
/**
* All constructors declared in this class.
*/
public val constructors: Collection<KFunction<T>>
}
@@ -112,7 +112,7 @@ public class ConstructorDescriptorImpl extends FunctionDescriptorImpl implements
@NotNull
@Override
protected FunctionDescriptorImpl createSubstitutedCopy(
protected ConstructorDescriptorImpl createSubstitutedCopy(
@NotNull DeclarationDescriptor newOwner,
@Nullable FunctionDescriptor original,
@NotNull Kind kind
@@ -18,7 +18,6 @@ package org.jetbrains.kotlin.serialization.deserialization
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.ConstructorDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.PropertyGetterDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.PropertySetterDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
@@ -28,10 +27,7 @@ import org.jetbrains.kotlin.serialization.ProtoBuf.Callable
import org.jetbrains.kotlin.serialization.ProtoBuf.Callable.CallableKind.FUN
import org.jetbrains.kotlin.serialization.ProtoBuf.Callable.CallableKind.VAL
import org.jetbrains.kotlin.serialization.ProtoBuf.Callable.CallableKind.VAR
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedAnnotations
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedSimpleFunctionDescriptor
import org.jetbrains.kotlin.serialization.deserialization.descriptors.*
public class MemberDeserializer(private val c: DeserializationContext) {
public fun loadCallable(proto: Callable): CallableMemberDescriptor {
@@ -152,9 +148,9 @@ public class MemberDeserializer(private val c: DeserializationContext) {
public fun loadConstructor(proto: Callable, isPrimary: Boolean): ConstructorDescriptor {
val classDescriptor = c.containingDeclaration as ClassDescriptor
val descriptor = ConstructorDescriptorImpl.create(
classDescriptor, getAnnotations(proto, proto.getFlags(), AnnotatedCallableKind.FUNCTION),
isPrimary, SourceElement.NO_SOURCE
val descriptor = DeserializedConstructorDescriptor(
classDescriptor, null, getAnnotations(proto, proto.getFlags(), AnnotatedCallableKind.FUNCTION),
isPrimary, CallableMemberDescriptor.Kind.DECLARATION, proto, c.nameResolver
)
val local = c.childContext(descriptor, listOf())
descriptor.initialize(
@@ -0,0 +1,45 @@
/*
* 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 org.jetbrains.kotlin.serialization.deserialization.descriptors
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.ConstructorDescriptorImpl
import org.jetbrains.kotlin.serialization.ProtoBuf
import org.jetbrains.kotlin.serialization.deserialization.NameResolver
public class DeserializedConstructorDescriptor(
containingDeclaration: ClassDescriptor,
original: ConstructorDescriptor?,
annotations: Annotations,
isPrimary: Boolean,
kind: CallableMemberDescriptor.Kind,
override val proto: ProtoBuf.Callable,
override val nameResolver: NameResolver
) : ConstructorDescriptorImpl(containingDeclaration, original, annotations, isPrimary, kind, SourceElement.NO_SOURCE),
DeserializedCallableMemberDescriptor {
override fun createSubstitutedCopy(
newOwner: DeclarationDescriptor,
original: FunctionDescriptor?,
kind: CallableMemberDescriptor.Kind
): DeserializedConstructorDescriptor {
return DeserializedConstructorDescriptor(
newOwner as ClassDescriptor, original as ConstructorDescriptor?, getAnnotations(), isPrimary, kind, proto, nameResolver
)
}
}
@@ -16,6 +16,7 @@
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.load.java.structure.reflect.classId
@@ -43,6 +44,8 @@ abstract class KCallableContainerImpl : KDeclarationContainer {
abstract val scope: JetScope
abstract val constructorDescriptors: Collection<ConstructorDescriptor>
fun findPropertyDescriptor(name: String, signature: String): PropertyDescriptor {
val properties = scope
.getProperties(Name.guess(name))
@@ -63,8 +66,7 @@ abstract class KCallableContainerImpl : KDeclarationContainer {
}
fun findFunctionDescriptor(name: String, signature: String): FunctionDescriptor {
val functions = scope
.getFunctions(Name.guess(name))
val functions = (if (name == "<init>") constructorDescriptors.toList() else scope.getFunctions(Name.guess(name)))
.filter { descriptor ->
RuntimeTypeMapper.mapSignature(descriptor) == signature
}
@@ -24,6 +24,7 @@ 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
class KClassImpl<T>(override val jClass: Class<T>) : KCallableContainerImpl(), KClass<T> {
@@ -43,6 +44,15 @@ class KClassImpl<T>(override val jClass: Class<T>) : KCallableContainerImpl(), K
descriptor, "KClassImpl scope", descriptor.getDefaultType().getMemberScope(), descriptor.getStaticScope()
)
override val constructorDescriptors: Collection<ConstructorDescriptor>
get() {
val descriptor = descriptor
if (descriptor.getKind() == ClassKind.CLASS || descriptor.getKind() == ClassKind.ENUM_CLASS) {
return descriptor.getConstructors()
}
return emptyList()
}
override val simpleName: String? get() {
if (jClass.isAnonymousClass()) return null
@@ -77,44 +87,57 @@ class KClassImpl<T>(override val jClass: Class<T>) : KCallableContainerImpl(), K
override val members: Collection<KCallable<*>>
get() = getMembers(declaredOnly = false, nonExtensions = true, extensions = true).toList()
fun getMembers(declaredOnly: Boolean, nonExtensions: Boolean, extensions: Boolean): Sequence<KCallable<*>> =
scope.getAllDescriptors().asSequence()
.filter { descriptor ->
descriptor !is MemberDescriptor || descriptor.getVisibility() != Visibilities.INVISIBLE_FAKE
}
.map { descriptor ->
descriptor.accept(object : DeclarationDescriptorVisitorEmptyBodies<KCallable<*>?, Nothing>() {
private fun skipCallable(descriptor: CallableMemberDescriptor): Boolean {
if (declaredOnly && !descriptor.getKind().isReal()) return true
@suppress("UNCHECKED_CAST")
override val constructors: Collection<KFunction<T>>
get() = constructorDescriptors.map {
KFunctionImpl(this, it) as KFunction<T>
}
val isExtension = descriptor.getExtensionReceiverParameter() != null
if (isExtension && !extensions) return true
if (!isExtension && !nonExtensions) return true
fun getMembers(declaredOnly: Boolean, nonExtensions: Boolean, extensions: Boolean): Sequence<KCallable<*>> {
val visitor = object : DeclarationDescriptorVisitorEmptyBodies<KCallable<*>?, Nothing>() {
private fun skipCallable(descriptor: CallableMemberDescriptor): Boolean {
if (declaredOnly && !descriptor.getKind().isReal()) return true
return false
}
val isExtension = descriptor.getExtensionReceiverParameter() != null
if (isExtension && !extensions) return true
if (!isExtension && !nonExtensions) return true
override fun visitPropertyDescriptor(descriptor: PropertyDescriptor, data: Nothing?): KCallable<*>? {
if (skipCallable(descriptor)) return null
return false
}
return if (descriptor.getExtensionReceiverParameter() == null) {
if (descriptor.isVar()) KMutableProperty1Impl<T, Any?>(this@KClassImpl, descriptor)
else KProperty1Impl<T, Any?>(this@KClassImpl, descriptor)
}
else {
if (descriptor.isVar()) KMutableProperty2Impl<T, Any?, Any?>(this@KClassImpl, descriptor)
else KProperty2Impl<T, Any?, Any?>(this@KClassImpl, descriptor)
}
}
override fun visitPropertyDescriptor(descriptor: PropertyDescriptor, data: Nothing?): KCallable<*>? {
if (skipCallable(descriptor)) return null
override fun visitFunctionDescriptor(descriptor: FunctionDescriptor, data: Nothing?): KCallable<*>? {
if (skipCallable(descriptor)) return null
return if (descriptor.getExtensionReceiverParameter() == null) {
if (descriptor.isVar()) KMutableProperty1Impl<T, Any?>(this@KClassImpl, descriptor)
else KProperty1Impl<T, Any?>(this@KClassImpl, descriptor)
}
else {
if (descriptor.isVar()) KMutableProperty2Impl<T, Any?, Any?>(this@KClassImpl, descriptor)
else KProperty2Impl<T, Any?, Any?>(this@KClassImpl, descriptor)
}
}
return KFunctionImpl(this@KClassImpl, descriptor)
}
}, null)
}
.filterNotNull()
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
@@ -16,6 +16,7 @@
package kotlin.reflect.jvm.internal
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
import org.jetbrains.kotlin.resolve.scopes.JetScope
import kotlin.jvm.internal.FunctionReference
import kotlin.reflect.KotlinReflectionInternalError
@@ -65,5 +66,8 @@ object EmptyContainerForLocal : KCallableContainerImpl() {
override val scope: JetScope
get() = fail()
override val constructorDescriptors: Collection<ConstructorDescriptor>
get() = fail()
private fun fail() = throw KotlinReflectionInternalError("Introspecting local functions is not yet supported in Kotlin reflection")
}
@@ -16,10 +16,11 @@
package kotlin.reflect.jvm.internal
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
import org.jetbrains.kotlin.load.java.structure.reflect.classId
import org.jetbrains.kotlin.resolve.scopes.JetScope
import kotlin.jvm.internal.KotlinPackage
import kotlin.reflect.*
import kotlin.reflect.KPackage
class KPackageImpl(override val jClass: Class<*>) : KCallableContainerImpl(), KPackage {
val descriptor by ReflectProperties.lazySoft {
@@ -31,6 +32,9 @@ class KPackageImpl(override val jClass: Class<*>) : KCallableContainerImpl(), KP
override val scope: JetScope get() = descriptor.memberScope
override val constructorDescriptors: Collection<ConstructorDescriptor>
get() = emptyList()
override fun equals(other: Any?): Boolean =
other is KPackageImpl && jClass == other.jClass
@@ -31,22 +31,22 @@ import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedSimpleFunctionDescriptor
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf
import kotlin.reflect.KotlinReflectionInternalError
object RuntimeTypeMapper {
fun mapSignature(function: FunctionDescriptor): String {
if (function is DeserializedSimpleFunctionDescriptor) {
val proto = function.getProto()
if (function is DeserializedCallableMemberDescriptor) {
val proto = function.proto
if (!proto.hasExtension(JvmProtoBuf.methodSignature)) {
// If it's a deserialized function but has no JVM signature, it must be from built-ins
return mapIntrinsicFunctionSignature(function) ?:
throw KotlinReflectionInternalError("No metadata found for $function")
}
val signature = proto.getExtension(JvmProtoBuf.methodSignature)
return SignatureDeserializer(function.getNameResolver()).methodSignatureString(signature)
return SignatureDeserializer(function.nameResolver).methodSignatureString(signature)
}
else if (function is JavaMethodDescriptor) {
val method = (function.getSource() as? JavaSourceElement)?.javaElement as? JavaMethod ?:
@@ -130,7 +130,7 @@ object RuntimeTypeMapper {
else throw KotlinReflectionInternalError("Unknown origin of $property (${property.javaClass})")
}
private fun mapIntrinsicFunctionSignature(function: DeserializedSimpleFunctionDescriptor): String? {
private fun mapIntrinsicFunctionSignature(function: FunctionDescriptor): String? {
val parameters = function.getValueParameters()
when (function.getName().asString()) {