Introduce additional API for introspecting functions

memberFunctions, declaredMemberFunctions, staticFunctions, etc.

 #KT-8797 Fixed
This commit is contained in:
Alexander Udalov
2015-08-20 15:37:55 -07:00
parent ebe4a8ec89
commit a73d02418d
11 changed files with 191 additions and 32 deletions
@@ -0,0 +1,6 @@
public class J {
public void publicMemberJ() {}
private void privateMemberJ() {}
public static void publicStaticJ() {}
private static void privateStaticJ() {}
}
@@ -0,0 +1,65 @@
import kotlin.reflect.*
import kotlin.test.assertEquals
open class K : J() {
public fun publicMemberK() {}
private fun privateMemberK() {}
public fun Any.publicMemberExtensionK() {}
private fun Any.privateMemberExtensionK() {}
}
class L : K()
fun Collection<KFunction<*>>.names(): Set<String> =
this.map { it.name }.toSet()
fun check(c: Collection<KFunction<*>>, names: Set<String>) {
assertEquals(names, c.names())
}
fun box(): String {
val any = setOf("equals", "hashCode", "toString")
val j = J::class
check(j.staticFunctions,
setOf("publicStaticJ", "privateStaticJ"))
check(j.declaredFunctions,
setOf("publicMemberJ", "privateMemberJ", "publicStaticJ", "privateStaticJ"))
check(j.declaredMemberFunctions,
setOf("publicMemberJ", "privateMemberJ"))
check(j.declaredMemberExtensionFunctions,
emptySet())
check(j.functions, any + j.declaredFunctions.names())
check(j.memberFunctions, any + j.declaredMemberFunctions.names())
check(j.memberExtensionFunctions, emptySet())
val k = K::class
check(k.staticFunctions,
emptySet())
check(k.declaredFunctions,
setOf("publicMemberK", "privateMemberK", "publicMemberExtensionK", "privateMemberExtensionK"))
check(k.declaredMemberFunctions,
setOf("publicMemberK", "privateMemberK"))
check(k.declaredMemberExtensionFunctions,
setOf("publicMemberExtensionK", "privateMemberExtensionK"))
check(k.memberFunctions, any + setOf("publicMemberJ") + k.declaredMemberFunctions.names())
check(k.memberExtensionFunctions, k.declaredMemberExtensionFunctions.names())
check(k.functions, any + (k.memberFunctions + k.memberExtensionFunctions).names())
val l = L::class
check(l.staticFunctions, emptySet())
check(l.declaredFunctions, emptySet())
check(l.declaredMemberFunctions, emptySet())
check(l.declaredMemberExtensionFunctions, emptySet())
check(l.memberFunctions, any + setOf("publicMemberJ", "publicMemberK"))
check(l.memberExtensionFunctions, setOf("publicMemberExtensionK"))
check(l.functions, any + (l.memberFunctions + l.memberExtensionFunctions).names())
return "OK"
}
@@ -285,6 +285,12 @@ public class BlackBoxWithJavaCodegenTestGenerated extends AbstractBlackBoxCodege
doTestWithJava(fileName);
}
@TestMetadata("declaredVsInheritedFunctions")
public void testDeclaredVsInheritedFunctions() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/reflection/declaredVsInheritedFunctions/");
doTestWithJava(fileName);
}
@TestMetadata("functionReferenceErasedToKFunction")
public void testFunctionReferenceErasedToKFunction() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/reflection/functionReferenceErasedToKFunction/");
@@ -30,13 +30,60 @@ public val <T : Any> KClass<T>.primaryConstructor: KFunction<T>?
((it as KFunctionImpl).descriptor as ConstructorDescriptor).isPrimary
}
/**
* Returns static functions declared in this class.
*/
public val KClass<*>.staticFunctions: Collection<KFunction<*>>
get() = (this as KClassImpl)
.getMembers(staticScope, declaredOnly = false, nonExtensions = true, extensions = true)
.filterIsInstance<KFunction<*>>()
.toList()
/**
* Returns non-extension non-static functions declared in this class and all of its superclasses.
*/
public val KClass<*>.memberFunctions: Collection<KFunction<*>>
get() = (this as KClassImpl)
.getMembers(memberScope, declaredOnly = false, nonExtensions = true, extensions = false)
.filterIsInstance<KFunction<*>>()
.toList()
/**
* Returns extension functions declared in this class and all of its superclasses.
*/
public val KClass<*>.memberExtensionFunctions: Collection<KFunction<*>>
get() = (this as KClassImpl)
.getMembers(memberScope, declaredOnly = false, nonExtensions = false, extensions = true)
.filterIsInstance<KFunction<*>>()
.toList()
/**
* Returns all functions declared in this class.
* If this is a Java class, it includes both non-static and static methods.
* If this is a Java class, it includes all non-static methods (both extensions and non-extensions)
* declared in the class and the superclasses, as well as static methods declared in the class.
*/
public val KClass<*>.declaredFunctions: Collection<KFunction<*>>
get() = (this as KClassImpl)
.getMembers(declaredOnly = true, nonExtensions = true, extensions = true)
.getMembers(memberScope, declaredOnly = true, nonExtensions = true, extensions = true)
.plus(getMembers(staticScope, declaredOnly = true, nonExtensions = true, extensions = true))
.filterIsInstance<KFunction<*>>()
.toList()
/**
* Returns non-extension non-static functions declared in this class.
*/
public val KClass<*>.declaredMemberFunctions: Collection<KFunction<*>>
get() = (this as KClassImpl)
.getMembers(memberScope, declaredOnly = true, nonExtensions = true, extensions = false)
.filterIsInstance<KFunction<*>>()
.toList()
/**
* Returns extension functions declared in this class.
*/
public val KClass<*>.declaredMemberExtensionFunctions: Collection<KFunction<*>>
get() = (this as KClassImpl)
.getMembers(memberScope, declaredOnly = true, nonExtensions = false, extensions = true)
.filterIsInstance<KFunction<*>>()
.toList()
@@ -45,7 +92,7 @@ public val KClass<*>.declaredFunctions: Collection<KFunction<*>>
*/
public val <T : Any> KClass<T>.memberProperties: Collection<KProperty1<T, *>>
get() = (this as KClassImpl<T>)
.getMembers(declaredOnly = false, nonExtensions = true, extensions = false)
.getMembers(memberScope, declaredOnly = false, nonExtensions = true, extensions = false)
.filterIsInstance<KProperty1<T, *>>()
.toList()
@@ -54,7 +101,7 @@ public val <T : Any> KClass<T>.memberProperties: Collection<KProperty1<T, *>>
*/
public val <T : Any> KClass<T>.memberExtensionProperties: Collection<KProperty2<T, *, *>>
get() = (this as KClassImpl<T>)
.getMembers(declaredOnly = false, nonExtensions = false, extensions = true)
.getMembers(memberScope, declaredOnly = false, nonExtensions = false, extensions = true)
.filterIsInstance<KProperty2<T, *, *>>()
.toList()
@@ -63,7 +110,7 @@ public val <T : Any> KClass<T>.memberExtensionProperties: Collection<KProperty2<
*/
public val <T : Any> KClass<T>.declaredMemberProperties: Collection<KProperty1<T, *>>
get() = (this as KClassImpl<T>)
.getMembers(declaredOnly = true, nonExtensions = true, extensions = false)
.getMembers(memberScope, declaredOnly = true, nonExtensions = true, extensions = false)
.filterIsInstance<KProperty1<T, *>>()
.toList()
@@ -72,6 +119,6 @@ public val <T : Any> KClass<T>.declaredMemberProperties: Collection<KProperty1<T
*/
public val <T : Any> KClass<T>.declaredMemberExtensionProperties: Collection<KProperty2<T, *, *>>
get() = (this as KClassImpl<T>)
.getMembers(declaredOnly = true, nonExtensions = false, extensions = true)
.getMembers(memberScope, declaredOnly = true, nonExtensions = false, extensions = true)
.filterIsInstance<KProperty2<T, *, *>>()
.toList()
@@ -16,15 +16,10 @@
package kotlin.reflect
import kotlin.reflect.jvm.internal.KDeclarationContainerImpl
/**
* 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<KFunction<*>>
get() = (this as KDeclarationContainerImpl)
.getMembers(declaredOnly = false, nonExtensions = true, extensions = true)
.filterIsInstance<KFunction<*>>()
.toList()
get() = members.filterIsInstance<KFunction<*>>()
@@ -23,7 +23,7 @@ import kotlin.reflect.jvm.internal.KPackageImpl
*/
public val KPackage.properties: Collection<KProperty0<*>>
get() = (this as KPackageImpl)
.getMembers(declaredOnly = false, nonExtensions = true, extensions = false)
.getMembers(scope, declaredOnly = false, nonExtensions = true, extensions = false)
.filterIsInstance<KProperty0<*>>()
.toList()
@@ -32,6 +32,6 @@ public val KPackage.properties: Collection<KProperty0<*>>
*/
public val KPackage.extensionProperties: Collection<KProperty1<*, *>>
get() = (this as KPackageImpl)
.getMembers(declaredOnly = false, nonExtensions = false, extensions = true)
.getMembers(scope, declaredOnly = false, nonExtensions = false, extensions = true)
.filterIsInstance<KProperty1<*, *>>()
.toList()
@@ -18,12 +18,16 @@ package kotlin.reflect.jvm.internal
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.annotations.Annotated
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.resolve.scopes.ChainedScope
import org.jetbrains.kotlin.name.Name
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
@@ -43,9 +47,14 @@ class KClassImpl<T : Any>(override val jClass: Class<T>) : KDeclarationContainer
private val classId: ClassId get() = RuntimeTypeMapper.mapJvmClassToKotlinClassId(jClass)
override val scope: JetScope get() = ChainedScope(
descriptor, "KClassImpl scope", descriptor.getDefaultType().getMemberScope(), descriptor.getStaticScope()
)
internal val memberScope: JetScope get() = descriptor.defaultType.memberScope
internal val staticScope: JetScope get() = descriptor.staticScope
override val members: Collection<KCallable<*>>
get() = getMembers(memberScope, declaredOnly = false, nonExtensions = true, extensions = true)
.plus(getMembers(staticScope, declaredOnly = false, nonExtensions = true, extensions = true))
.toList()
override val constructorDescriptors: Collection<ConstructorDescriptor>
get() {
@@ -56,6 +65,15 @@ class KClassImpl<T : Any>(override val jClass: Class<T>) : KDeclarationContainer
return emptyList()
}
@suppress("UNCHECKED_CAST")
override fun getProperties(name: Name): Collection<PropertyDescriptor> =
(memberScope.getProperties(name, NoLookupLocation.FROM_REFLECTION) +
staticScope.getProperties(name, NoLookupLocation.FROM_REFLECTION)) as Collection<PropertyDescriptor>
override fun getFunctions(name: Name): Collection<FunctionDescriptor> =
memberScope.getFunctions(name, NoLookupLocation.FROM_REFLECTION) +
staticScope.getFunctions(name, NoLookupLocation.FROM_REFLECTION)
override val simpleName: String? get() {
if (jClass.isAnonymousClass()) return null
@@ -18,7 +18,6 @@ package kotlin.reflect.jvm.internal
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.DeclarationDescriptorVisitorEmptyBodies
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.load.java.structure.reflect.classId
import org.jetbrains.kotlin.load.java.structure.reflect.createArrayType
import org.jetbrains.kotlin.load.java.structure.reflect.safeClassLoader
@@ -42,14 +41,13 @@ abstract class KDeclarationContainerImpl : ClassBasedDeclarationContainer {
jClass.getOrCreateModule()
}
abstract val scope: JetScope
abstract val constructorDescriptors: Collection<ConstructorDescriptor>
override val members: Collection<KCallable<*>>
get() = getMembers(declaredOnly = false, nonExtensions = true, extensions = true).toList()
abstract fun getProperties(name: Name): Collection<PropertyDescriptor>
fun getMembers(declaredOnly: Boolean, nonExtensions: Boolean, extensions: Boolean): Sequence<KCallable<*>> {
abstract fun getFunctions(name: Name): Collection<FunctionDescriptor>
fun getMembers(scope: JetScope, declaredOnly: Boolean, nonExtensions: Boolean, extensions: Boolean): Sequence<KCallable<*>> {
val visitor = object : DeclarationDescriptorVisitorEmptyBodies<KCallable<*>?, Unit>() {
private fun skipCallable(descriptor: CallableMemberDescriptor): Boolean {
if (declaredOnly && !descriptor.getKind().isReal()) return true
@@ -105,8 +103,7 @@ abstract class KDeclarationContainerImpl : ClassBasedDeclarationContainer {
}
fun findPropertyDescriptor(name: String, signature: String): PropertyDescriptor {
val properties = scope
.getProperties(Name.guess(name), NoLookupLocation.FROM_REFLECTION)
val properties = getProperties(Name.guess(name))
.filter { descriptor ->
descriptor is PropertyDescriptor &&
RuntimeTypeMapper.mapPropertySignature(descriptor).asString() == signature
@@ -120,11 +117,11 @@ abstract class KDeclarationContainerImpl : ClassBasedDeclarationContainer {
)
}
return properties.single() as PropertyDescriptor
return properties.single()
}
fun findFunctionDescriptor(name: String, signature: String): FunctionDescriptor {
val functions = (if (name == "<init>") constructorDescriptors.toList() else scope.getFunctions(Name.guess(name), NoLookupLocation.FROM_REFLECTION))
val functions = (if (name == "<init>") constructorDescriptors.toList() else getFunctions(Name.guess(name)))
.filter { descriptor ->
RuntimeTypeMapper.mapSignature(descriptor).asString() == signature
}
@@ -17,8 +17,11 @@
package kotlin.reflect.jvm.internal
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
import org.jetbrains.kotlin.resolve.scopes.JetScope
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.name.Name
import kotlin.jvm.internal.FunctionReference
import kotlin.reflect.KCallable
import kotlin.reflect.KotlinReflectionInternalError
class KFunctionFromReferenceImpl(
@@ -63,11 +66,15 @@ object EmptyContainerForLocal : KDeclarationContainerImpl() {
override val jClass: Class<*>
get() = fail()
override val scope: JetScope
override val members: Collection<KCallable<*>>
get() = fail()
override val constructorDescriptors: Collection<ConstructorDescriptor>
get() = fail()
override fun getProperties(name: Name): Collection<PropertyDescriptor> = fail()
override fun getFunctions(name: Name): Collection<FunctionDescriptor> = fail()
private fun fail() = throw KotlinReflectionInternalError("Introspecting local functions is not yet supported in Kotlin reflection")
}
@@ -17,9 +17,14 @@
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.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.load.java.structure.reflect.classId
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.scopes.JetScope
import kotlin.jvm.internal.KotlinPackage
import kotlin.reflect.KCallable
import kotlin.reflect.KPackage
class KPackageImpl(override val jClass: Class<*>) : KDeclarationContainerImpl(), KPackage {
@@ -30,11 +35,21 @@ class KPackageImpl(override val jClass: Class<*>) : KDeclarationContainerImpl(),
moduleData.module.getPackage(fqName)
}
override val scope: JetScope get() = descriptor.memberScope
internal val scope: JetScope get() = descriptor.memberScope
override val members: Collection<KCallable<*>>
get() = getMembers(scope, declaredOnly = false, nonExtensions = true, extensions = true).toList()
override val constructorDescriptors: Collection<ConstructorDescriptor>
get() = emptyList()
@suppress("UNCHECKED_CAST")
override fun getProperties(name: Name): Collection<PropertyDescriptor> =
scope.getProperties(name, NoLookupLocation.FROM_REFLECTION) as Collection<PropertyDescriptor>
override fun getFunctions(name: Name): Collection<FunctionDescriptor> =
scope.getFunctions(name, NoLookupLocation.FROM_REFLECTION)
override fun equals(other: Any?): Boolean =
other is KPackageImpl && jClass == other.jClass
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.load.java.structure.reflect.*
import org.jetbrains.kotlin.load.kotlin.SignatureDeserializer
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
import org.jetbrains.kotlin.serialization.ProtoBuf
@@ -117,7 +118,9 @@ sealed class JvmPropertySignature {
object RuntimeTypeMapper {
fun mapSignature(possiblySubstitutedFunction: FunctionDescriptor): JvmFunctionSignature {
val function = possiblySubstitutedFunction.original
// Fake overrides don't have a source element, so we need to take a declaration.
// TODO: support the case when a fake override overrides several declarations with different signatures
val function = DescriptorUtils.unwrapFakeOverride(possiblySubstitutedFunction).original
when (function) {
is DeserializedCallableMemberDescriptor -> {