diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/functions/simpleGetFunctions.kt b/compiler/testData/codegen/boxWithStdlib/reflection/functions/simpleGetFunctions.kt
new file mode 100644
index 00000000000..80658d4b2ab
--- /dev/null
+++ b/compiler/testData/codegen/boxWithStdlib/reflection/functions/simpleGetFunctions.kt
@@ -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"
+}
diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/memberExtensionToString.kt b/compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/memberExtensionToString.kt
index a5df279344b..762c03732cc 100644
--- a/compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/memberExtensionToString.kt
+++ b/compiler/testData/codegen/boxWithStdlib/reflection/methodsFromAny/memberExtensionToString.kt
@@ -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().kotlin.extensionProperties.single()
return if ("$p" == "var A.(kotlin.String.)id") "OK" else "Fail $p"
+
+ val q = javaClass().kotlin.declaredFunctions.single()
+ if ("$q" != "fun A.(kotlin.Int.)foo(): kotlin.Double") return "Fail q $q"
+
+ return "OK"
}
diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/parameters/functionParameterNameAndIndex.kt b/compiler/testData/codegen/boxWithStdlib/reflection/parameters/functionParameterNameAndIndex.kt
index 3d101c0a46d..5edeac991da 100644
--- a/compiler/testData/codegen/boxWithStdlib/reflection/parameters/functionParameterNameAndIndex.kt
+++ b/compiler/testData/codegen/boxWithStdlib/reflection/parameters/functionParameterNameAndIndex.kt
@@ -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"
diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java
index 74ec03218ec..d1b59679596 100644
--- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java
+++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java
@@ -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");
diff --git a/core/reflection.jvm/src/kotlin/reflect/KClassExtensions.kt b/core/reflection.jvm/src/kotlin/reflect/KClassExtensions.kt
index 6e8b6c00cde..e37794e2ff4 100644
--- a/core/reflection.jvm/src/kotlin/reflect/KClassExtensions.kt
+++ b/core/reflection.jvm/src/kotlin/reflect/KClassExtensions.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 KClass.functions: Collection>
+ get() = (this as KClassImpl)
+ .getMembers(declaredOnly = false, nonExtensions = true, extensions = true)
+ .filterIsInstance>()
+ .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>
+ get() = (this as KClassImpl)
+ .getMembers(declaredOnly = true, nonExtensions = true, extensions = true)
+ .filterIsInstance>()
+ .toList()
+
/**
* Returns non-extension properties declared in this class and all of its superclasses.
*/
diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt
index 74b8b6fc8ba..b7a58e346f5 100644
--- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt
+++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt
@@ -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(override val jClass: Class) : KCallableContainerImpl(), K
}
.map { descriptor ->
descriptor.accept(object : DeclarationDescriptorVisitorEmptyBodies?, 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(this@KClassImpl, descriptor)
else KProperty1Impl(this@KClassImpl, descriptor)
}
@@ -102,6 +106,12 @@ class KClassImpl(override val jClass: Class) : KCallableContainerImpl(), K
else KProperty2Impl(this@KClassImpl, descriptor)
}
}
+
+ override fun visitFunctionDescriptor(descriptor: FunctionDescriptor, data: Nothing?): KCallable<*>? {
+ if (skipCallable(descriptor)) return null
+
+ return KFunctionImpl(this@KClassImpl, descriptor)
+ }
}, null)
}
.filterNotNull()
diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/RuntimeTypeMapper.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/RuntimeTypeMapper.kt
index 4a960067e1e..74fef9465d1 100644
--- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/RuntimeTypeMapper.kt
+++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/RuntimeTypeMapper.kt
@@ -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 {