Support KClass.functions and declaredFunctions
This commit is contained in:
+21
@@ -0,0 +1,21 @@
|
||||
import kotlin.reflect.*
|
||||
|
||||
open class A {
|
||||
fun mem() {}
|
||||
fun Int.memExt() {}
|
||||
}
|
||||
|
||||
class B : A()
|
||||
|
||||
fun box(): String {
|
||||
val all = A::class.functions.map { it.name }.toSortedList()
|
||||
assert(all == listOf("equals", "hashCode", "mem", "memExt", "toString")) { "Fail A functions: ${A::class.functions}" }
|
||||
|
||||
val declared = A::class.declaredFunctions.map { it.name }.toSortedList()
|
||||
assert(declared == listOf("mem", "memExt")) { "Fail A declaredFunctions: ${A::class.declaredFunctions}" }
|
||||
|
||||
val declaredSubclass = B::class.declaredFunctions.map { it.name }.toSortedList()
|
||||
assert(declaredSubclass.isEmpty()) { "Fail B declaredFunctions: ${B::class.declaredFunctions}" }
|
||||
|
||||
return "OK"
|
||||
}
|
||||
Vendored
+7
@@ -5,9 +5,16 @@ class A {
|
||||
var String.id: String
|
||||
get() = this
|
||||
set(value) {}
|
||||
|
||||
fun Int.foo(): Double = toDouble()
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val p = javaClass<A>().kotlin.extensionProperties.single()
|
||||
return if ("$p" == "var A.(kotlin.String.)id") "OK" else "Fail $p"
|
||||
|
||||
val q = javaClass<A>().kotlin.declaredFunctions.single()
|
||||
if ("$q" != "fun A.(kotlin.Int.)foo(): kotlin.Double") return "Fail q $q"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
|
||||
Vendored
+4
@@ -5,6 +5,8 @@ fun foo(bar: String): Int = bar.length()
|
||||
|
||||
class A(val c: String) {
|
||||
fun foz(baz: Int) {}
|
||||
|
||||
fun Double.mext(mez: Long) {}
|
||||
}
|
||||
|
||||
fun Int.qux(zux: String) {}
|
||||
@@ -21,6 +23,8 @@ fun box(): String {
|
||||
checkParameters(A::foz, listOf(null, "baz"))
|
||||
checkParameters(Int::qux, listOf(null, "zux"))
|
||||
|
||||
checkParameters(A::class.functions.single { it.name == "mext" }, listOf(null, null, "mez"))
|
||||
|
||||
checkParameters(::A, listOf("c"))
|
||||
|
||||
return "OK"
|
||||
|
||||
+6
@@ -3027,6 +3027,12 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode
|
||||
doTestWithStdlib(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("simpleGetFunctions.kt")
|
||||
public void testSimpleGetFunctions() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/functions/simpleGetFunctions.kt");
|
||||
doTestWithStdlib(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("simpleNames.kt")
|
||||
public void testSimpleNames() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/functions/simpleNames.kt");
|
||||
|
||||
@@ -18,6 +18,27 @@ package kotlin.reflect
|
||||
|
||||
import kotlin.reflect.jvm.internal.KClassImpl
|
||||
|
||||
/**
|
||||
* Returns all functions declared in this class and all of its superclasses.
|
||||
* If this 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 <T> KClass<T>.functions: Collection<KFunction<*>>
|
||||
get() = (this as KClassImpl<T>)
|
||||
.getMembers(declaredOnly = false, nonExtensions = true, 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.
|
||||
*/
|
||||
public val KClass<*>.declaredFunctions: Collection<KFunction<*>>
|
||||
get() = (this as KClassImpl)
|
||||
.getMembers(declaredOnly = true, nonExtensions = true, extensions = true)
|
||||
.filterIsInstance<KFunction<*>>()
|
||||
.toList()
|
||||
|
||||
/**
|
||||
* Returns non-extension properties declared in this class and all of its superclasses.
|
||||
*/
|
||||
|
||||
@@ -16,9 +16,7 @@
|
||||
|
||||
package kotlin.reflect.jvm.internal
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.MemberDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.impl.DeclarationDescriptorVisitorEmptyBodies
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.resolve.scopes.ChainedScope
|
||||
@@ -86,14 +84,20 @@ class KClassImpl<T>(override val jClass: Class<T>) : KCallableContainerImpl(), K
|
||||
}
|
||||
.map { descriptor ->
|
||||
descriptor.accept(object : DeclarationDescriptorVisitorEmptyBodies<KCallable<*>?, Nothing>() {
|
||||
override fun visitPropertyDescriptor(descriptor: PropertyDescriptor, data: Nothing?): KCallable<*>? {
|
||||
if (declaredOnly && !descriptor.getKind().isReal()) return null
|
||||
private fun skipCallable(descriptor: CallableMemberDescriptor): Boolean {
|
||||
if (declaredOnly && !descriptor.getKind().isReal()) return true
|
||||
|
||||
val isExtension = descriptor.getExtensionReceiverParameter() != null
|
||||
if (isExtension && !extensions) return null
|
||||
if (!isExtension && !nonExtensions) return null
|
||||
if (isExtension && !extensions) return true
|
||||
if (!isExtension && !nonExtensions) return true
|
||||
|
||||
return if (!isExtension) {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun visitPropertyDescriptor(descriptor: PropertyDescriptor, 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)
|
||||
}
|
||||
@@ -102,6 +106,12 @@ class KClassImpl<T>(override val jClass: Class<T>) : KCallableContainerImpl(), K
|
||||
else KProperty2Impl<T, Any?, Any?>(this@KClassImpl, descriptor)
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitFunctionDescriptor(descriptor: FunctionDescriptor, data: Nothing?): KCallable<*>? {
|
||||
if (skipCallable(descriptor)) return null
|
||||
|
||||
return KFunctionImpl(this@KClassImpl, descriptor)
|
||||
}
|
||||
}, null)
|
||||
}
|
||||
.filterNotNull()
|
||||
|
||||
@@ -41,7 +41,9 @@ object RuntimeTypeMapper {
|
||||
if (function is DeserializedSimpleFunctionDescriptor) {
|
||||
val proto = function.getProto()
|
||||
if (!proto.hasExtension(JvmProtoBuf.methodSignature)) {
|
||||
throw KotlinReflectionInternalError("No metadata found for $function")
|
||||
// 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)
|
||||
@@ -128,6 +130,31 @@ object RuntimeTypeMapper {
|
||||
else throw KotlinReflectionInternalError("Unknown origin of $property (${property.javaClass})")
|
||||
}
|
||||
|
||||
private fun mapIntrinsicFunctionSignature(function: DeserializedSimpleFunctionDescriptor): String? {
|
||||
val parameters = function.getValueParameters()
|
||||
|
||||
when (function.getName().asString()) {
|
||||
"equals" -> {
|
||||
if (parameters.size() == 1 && KotlinBuiltIns.isNullableAny(parameters.single().getType())) {
|
||||
return "equals(Ljava/lang/Object;)Z"
|
||||
}
|
||||
}
|
||||
"hashCode" -> {
|
||||
if (parameters.isEmpty()) {
|
||||
return "hashCode()I"
|
||||
}
|
||||
}
|
||||
"toString" -> {
|
||||
if (parameters.isEmpty()) {
|
||||
return "toString()Ljava/lang/String;"
|
||||
}
|
||||
}
|
||||
// TODO: generalize and support other functions from built-ins
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
fun mapJvmClassToKotlinClassId(klass: Class<*>): ClassId {
|
||||
if (klass.isArray()) {
|
||||
klass.getComponentType().primitiveType?.let {
|
||||
|
||||
Reference in New Issue
Block a user