Introduce additional API for introspecting functions
memberFunctions, declaredMemberFunctions, staticFunctions, etc. #KT-8797 Fixed
This commit is contained in:
+6
@@ -0,0 +1,6 @@
|
||||
public class J {
|
||||
public void publicMemberJ() {}
|
||||
private void privateMemberJ() {}
|
||||
public static void publicStaticJ() {}
|
||||
private static void privateStaticJ() {}
|
||||
}
|
||||
+65
@@ -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"
|
||||
}
|
||||
+6
@@ -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 -> {
|
||||
|
||||
Reference in New Issue
Block a user