Support mapping between Kotlin functions and JVM methods/constructors
This commit is contained in:
+7
@@ -0,0 +1,7 @@
|
||||
public class javaConstructor {
|
||||
public final String result;
|
||||
|
||||
public javaConstructor(String result) {
|
||||
this.result = result;
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
import kotlin.reflect.*
|
||||
import kotlin.reflect.jvm.*
|
||||
import javaConstructor as J
|
||||
|
||||
fun box(): String {
|
||||
val reference = ::J
|
||||
val javaConstructor = reference.javaConstructor ?: return "Fail: no Constructor for reference"
|
||||
val j = javaConstructor.newInstance("OK")
|
||||
val kotlinConstructor = javaConstructor.kotlinFunction
|
||||
if (reference != kotlinConstructor) return "Fail: reference != kotlinConstructor"
|
||||
return j.result
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
public class javaMethods {
|
||||
public String f(String s) {
|
||||
return s;
|
||||
}
|
||||
|
||||
public static String g(String s) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import kotlin.reflect.*
|
||||
import kotlin.reflect.jvm.*
|
||||
import javaMethods as J
|
||||
|
||||
fun box(): String {
|
||||
val f = J::f
|
||||
val fm = f.javaMethod ?: return "Fail: no Method for f"
|
||||
if (fm.invoke(J(), "abc") != "abc") return "Fail fm"
|
||||
val ff = fm.kotlinFunction ?: return "Fail: no KFunction for fm"
|
||||
if (f != ff) return "Fail f != ff"
|
||||
|
||||
val g = J::g
|
||||
val gm = g.javaMethod ?: return "Fail: no Method for g"
|
||||
if (gm.invoke(null, "ghi") != "ghi") return "Fail gm"
|
||||
val gg = gm.kotlinFunction ?: return "Fail: no KFunction for gm"
|
||||
if (g != gg) return "Fail g != gg"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import kotlin.reflect.*
|
||||
import kotlin.reflect.jvm.*
|
||||
|
||||
class K {
|
||||
class Nested
|
||||
inner class Inner
|
||||
}
|
||||
|
||||
class Secondary {
|
||||
constructor(x: Int) {}
|
||||
}
|
||||
|
||||
fun check(f: KFunction<*>) {
|
||||
assert(f.javaMethod == null, "Fail f method")
|
||||
assert(f.javaConstructor != null, "Fail f constructor")
|
||||
val c = f.javaConstructor!!
|
||||
|
||||
assert(c.kotlinFunction != null, "Fail m function")
|
||||
val ff = c.kotlinFunction!!
|
||||
|
||||
assert(f == ff, "Fail f != ff")
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
check(::K)
|
||||
|
||||
// Workaround KT-8596
|
||||
val nested = K::Nested
|
||||
check(nested)
|
||||
|
||||
check(K::Inner)
|
||||
check(::Secondary)
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import kotlin.reflect.*
|
||||
import kotlin.reflect.jvm.*
|
||||
|
||||
class K {
|
||||
fun foo(s: String): Int = s.length()
|
||||
}
|
||||
fun bar(s: String): Int = s.length()
|
||||
fun String.baz(): Int = this.length()
|
||||
|
||||
fun check(f: KFunction<Int>) {
|
||||
assert(f.javaConstructor == null, "Fail f constructor")
|
||||
assert(f.javaMethod != null, "Fail f method")
|
||||
val m = f.javaMethod!!
|
||||
|
||||
assert(m.kotlinFunction != null, "Fail m function")
|
||||
val ff = m.kotlinFunction!!
|
||||
|
||||
assert(f == ff, "Fail f != ff")
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
check(K::foo)
|
||||
check(::bar)
|
||||
check(String::baz)
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+12
@@ -510,11 +510,23 @@ public class BlackBoxAgainstJavaCodegenTestGenerated extends AbstractBlackBoxCod
|
||||
doTestAgainstJava(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("javaConstructor.kt")
|
||||
public void testJavaConstructor() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxAgainstJava/reflection/mapping/javaConstructor.kt");
|
||||
doTestAgainstJava(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("javaFields.kt")
|
||||
public void testJavaFields() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxAgainstJava/reflection/mapping/javaFields.kt");
|
||||
doTestAgainstJava(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("javaMethods.kt")
|
||||
public void testJavaMethods() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxAgainstJava/reflection/mapping/javaMethods.kt");
|
||||
doTestAgainstJava(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/boxAgainstJava/reflection/properties")
|
||||
|
||||
+12
@@ -3114,12 +3114,24 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxWithStdlib/reflection/mapping"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("constructor.kt")
|
||||
public void testConstructor() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/mapping/constructor.kt");
|
||||
doTestWithStdlib(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("extensionProperty.kt")
|
||||
public void testExtensionProperty() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/mapping/extensionProperty.kt");
|
||||
doTestWithStdlib(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("functions.kt")
|
||||
public void testFunctions() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/mapping/functions.kt");
|
||||
doTestWithStdlib(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("mappedClassIsEqualToClassLiteral.kt")
|
||||
public void testMappedClassIsEqualToClassLiteral() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/mapping/mappedClassIsEqualToClassLiteral.kt");
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@ import java.lang.reflect.Type
|
||||
import java.util.ArrayList
|
||||
|
||||
public abstract class ReflectJavaMember : ReflectJavaElement(), ReflectJavaAnnotationOwner, ReflectJavaModifierListOwner, JavaMember {
|
||||
protected abstract val member: Member
|
||||
internal abstract val member: Member
|
||||
|
||||
override val element: AnnotatedElement get() = member as AnnotatedElement
|
||||
|
||||
|
||||
@@ -75,14 +75,14 @@ abstract class DescriptorBasedProperty<out R> protected constructor(
|
||||
open val javaGetter: Method? by ReflectProperties.lazySoft {
|
||||
val proto = protoData
|
||||
if (proto == null || !proto.signature.hasGetter()) null
|
||||
else container.findMethodBySignature(proto.signature.getGetter(), proto.nameResolver,
|
||||
else container.findMethodBySignature(proto.proto, proto.signature.getGetter(), proto.nameResolver,
|
||||
descriptor.getGetter()?.getVisibility()?.let { Visibilities.isPrivate(it) } ?: false)
|
||||
}
|
||||
|
||||
open val javaSetter: Method? by ReflectProperties.lazySoft {
|
||||
val proto = protoData
|
||||
if (proto == null || !proto.signature.hasSetter()) null
|
||||
else container.findMethodBySignature(proto.signature.getSetter(), proto.nameResolver,
|
||||
else container.findMethodBySignature(proto.proto, proto.signature.getSetter(), proto.nameResolver,
|
||||
descriptor.getSetter()?.getVisibility()?.let { Visibilities.isPrivate(it) } ?: false)
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.serialization.ProtoBuf
|
||||
import org.jetbrains.kotlin.serialization.deserialization.NameResolver
|
||||
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf
|
||||
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf.JvmType.PrimitiveType.*
|
||||
import java.lang.reflect.Constructor
|
||||
import java.lang.reflect.Field
|
||||
import java.lang.reflect.Method
|
||||
import kotlin.reflect.KCallable
|
||||
@@ -141,22 +142,55 @@ abstract class KCallableContainerImpl : KDeclarationContainer {
|
||||
}
|
||||
|
||||
// TODO: check resulting method's return type
|
||||
fun findMethodBySignature(signature: JvmProtoBuf.JvmMethodSignature, nameResolver: NameResolver, declared: Boolean): Method? {
|
||||
fun findMethodBySignature(
|
||||
@suppress("UNUSED_PARAMETER") proto: ProtoBuf.Callable,
|
||||
signature: JvmProtoBuf.JvmMethodSignature,
|
||||
nameResolver: NameResolver,
|
||||
declared: Boolean
|
||||
): Method? {
|
||||
val name = nameResolver.getString(signature.getName())
|
||||
val classLoader = jClass.classLoader
|
||||
val parameterTypes = signature.getParameterTypeList().map { jvmType ->
|
||||
loadJvmType(jvmType, nameResolver, classLoader)
|
||||
}.toTypedArray()
|
||||
if (name == "<init>") return null
|
||||
|
||||
val parameterTypes = loadParameterTypes(nameResolver, signature)
|
||||
|
||||
// Method for a top level function should be the one from the package facade.
|
||||
// This is likely to change after the package part reform.
|
||||
val owner = jClass
|
||||
|
||||
return try {
|
||||
if (declared) jClass.getDeclaredMethod(name, *parameterTypes)
|
||||
else jClass.getMethod(name, *parameterTypes)
|
||||
if (declared) owner.getDeclaredMethod(name, *parameterTypes)
|
||||
else owner.getMethod(name, *parameterTypes)
|
||||
}
|
||||
catch (e: NoSuchMethodException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
fun findConstructorBySignature(
|
||||
signature: JvmProtoBuf.JvmMethodSignature,
|
||||
nameResolver: NameResolver,
|
||||
declared: Boolean
|
||||
): Constructor<*>? {
|
||||
if (nameResolver.getString(signature.getName()) != "<init>") return null
|
||||
|
||||
val parameterTypes = loadParameterTypes(nameResolver, signature)
|
||||
|
||||
return try {
|
||||
if (declared) jClass.getDeclaredConstructor(*parameterTypes)
|
||||
else jClass.getConstructor(*parameterTypes)
|
||||
}
|
||||
catch (e: NoSuchMethodException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadParameterTypes(nameResolver: NameResolver, signature: JvmProtoBuf.JvmMethodSignature): Array<Class<*>> {
|
||||
val classLoader = jClass.classLoader
|
||||
return signature.getParameterTypeList().map { jvmType ->
|
||||
loadJvmType(jvmType, nameResolver, classLoader)
|
||||
}.toTypedArray()
|
||||
}
|
||||
|
||||
// TODO: check resulting field's type
|
||||
fun findFieldBySignature(
|
||||
proto: ProtoBuf.Callable,
|
||||
@@ -166,18 +200,11 @@ abstract class KCallableContainerImpl : KDeclarationContainer {
|
||||
val name = nameResolver.getString(signature.getName())
|
||||
|
||||
val owner =
|
||||
when {
|
||||
proto.hasExtension(JvmProtoBuf.implClassName) -> {
|
||||
val implClassName = nameResolver.getName(proto.getExtension(JvmProtoBuf.implClassName))
|
||||
// TODO: store fq name of impl class name in jvm_descriptors.proto
|
||||
val classId = ClassId(jClass.classId.getPackageFqName(), implClassName)
|
||||
jClass.classLoader.loadClass(classId.asSingleFqName().asString())
|
||||
}
|
||||
signature.getIsStaticInOuter() -> {
|
||||
jClass.getEnclosingClass() ?: throw KotlinReflectionInternalError("Inconsistent metadata for field $name in $jClass")
|
||||
}
|
||||
else -> jClass
|
||||
implClassForCallable(nameResolver, proto) ?:
|
||||
if (signature.getIsStaticInOuter()) {
|
||||
jClass.getEnclosingClass() ?: throw KotlinReflectionInternalError("Inconsistent metadata for field $name in $jClass")
|
||||
}
|
||||
else jClass
|
||||
|
||||
return try {
|
||||
owner.getDeclaredField(name)
|
||||
@@ -187,6 +214,17 @@ abstract class KCallableContainerImpl : KDeclarationContainer {
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the JVM class which contains this callable. This class may be different from the one represented by descriptors
|
||||
// in case of top level functions (their bodies are in package parts), methods with implementations in interfaces, etc.
|
||||
private fun implClassForCallable(nameResolver: NameResolver, proto: ProtoBuf.Callable): Class<*>? {
|
||||
if (!proto.hasExtension(JvmProtoBuf.implClassName)) return null
|
||||
|
||||
val implClassName = nameResolver.getName(proto.getExtension(JvmProtoBuf.implClassName))
|
||||
// TODO: store fq name of impl class name in jvm_descriptors.proto
|
||||
val classId = ClassId(jClass.classId.getPackageFqName(), implClassName)
|
||||
return jClass.classLoader.loadClass(classId.asSingleFqName().asString())
|
||||
}
|
||||
|
||||
private fun loadJvmType(
|
||||
type: JvmProtoBuf.JvmType,
|
||||
nameResolver: NameResolver,
|
||||
|
||||
@@ -18,6 +18,17 @@
|
||||
package kotlin.reflect.jvm.internal
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.load.java.sources.JavaSourceElement
|
||||
import org.jetbrains.kotlin.load.java.structure.reflect.ReflectJavaConstructor
|
||||
import org.jetbrains.kotlin.load.java.structure.reflect.ReflectJavaMethod
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.serialization.ProtoBuf
|
||||
import org.jetbrains.kotlin.serialization.deserialization.NameResolver
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf
|
||||
import java.lang.reflect.Constructor
|
||||
import java.lang.reflect.Method
|
||||
import kotlin.jvm.internal.FunctionImpl
|
||||
import kotlin.reflect.*
|
||||
|
||||
@@ -34,10 +45,57 @@ open class KFunctionImpl protected constructor(
|
||||
container, descriptor.getName().asString(), RuntimeTypeMapper.mapSignature(descriptor), descriptor
|
||||
)
|
||||
|
||||
private data class FunctionProtoData(
|
||||
val proto: ProtoBuf.Callable,
|
||||
val nameResolver: NameResolver,
|
||||
val signature: JvmProtoBuf.JvmMethodSignature
|
||||
)
|
||||
|
||||
override val descriptor: FunctionDescriptor by ReflectProperties.lazySoft<FunctionDescriptor>(descriptorInitialValue) {
|
||||
container.findFunctionDescriptor(name, signature)
|
||||
}
|
||||
|
||||
// null if this is a function declared in a foreign (Java) class
|
||||
private val protoData: FunctionProtoData? by ReflectProperties.lazyWeak {
|
||||
val function = DescriptorUtils.unwrapFakeOverride(descriptor) as? DeserializedCallableMemberDescriptor
|
||||
if (function != null) {
|
||||
val proto = function.proto
|
||||
if (proto.hasExtension(JvmProtoBuf.methodSignature)) {
|
||||
return@lazyWeak FunctionProtoData(proto, function.nameResolver, proto.getExtension(JvmProtoBuf.methodSignature))
|
||||
}
|
||||
}
|
||||
null
|
||||
}
|
||||
|
||||
internal val javaMethod: Method? by ReflectProperties.lazySoft {
|
||||
if (name != "<init>") {
|
||||
val proto = protoData
|
||||
if (proto != null) {
|
||||
container.findMethodBySignature(proto.proto, proto.signature, proto.nameResolver,
|
||||
Visibilities.isPrivate(descriptor.getVisibility()))
|
||||
}
|
||||
else {
|
||||
((descriptor.getOriginal().getSource() as? JavaSourceElement)?.javaElement as? ReflectJavaMethod)?.member
|
||||
}
|
||||
}
|
||||
else null
|
||||
}
|
||||
|
||||
internal val javaConstructor: Constructor<*>? by ReflectProperties.lazySoft {
|
||||
if (name == "<init>") {
|
||||
val proto = protoData
|
||||
if (proto != null) {
|
||||
return@lazySoft container.findConstructorBySignature(
|
||||
proto.signature, proto.nameResolver, Visibilities.isPrivate(descriptor.getVisibility())
|
||||
)
|
||||
}
|
||||
else {
|
||||
((descriptor.getOriginal().getSource() as? JavaSourceElement)?.javaElement as? ReflectJavaConstructor)?.member
|
||||
}
|
||||
}
|
||||
else null
|
||||
}
|
||||
|
||||
override val name: String get() = descriptor.getName().asString()
|
||||
|
||||
override fun getArity(): Int {
|
||||
|
||||
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.builtins.PrimitiveType
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaConstructorDescriptor
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaPropertyDescriptor
|
||||
import org.jetbrains.kotlin.load.java.sources.JavaSourceElement
|
||||
@@ -56,19 +57,31 @@ object RuntimeTypeMapper {
|
||||
|
||||
return StringBuilder {
|
||||
append(method.getName().asString())
|
||||
|
||||
append("(")
|
||||
for (parameter in method.getValueParameters()) {
|
||||
appendJavaType(parameter.getType())
|
||||
}
|
||||
append(")")
|
||||
|
||||
appendParameters(method)
|
||||
appendJavaType(method.getReturnType())
|
||||
}.toString()
|
||||
}
|
||||
else if (function is JavaConstructorDescriptor) {
|
||||
val constructor = (function.getSource() as? JavaSourceElement)?.javaElement as? JavaConstructor ?:
|
||||
throw KotlinReflectionInternalError("Incorrect resolution sequence for Java constructor $function")
|
||||
|
||||
return StringBuilder {
|
||||
append("<init>")
|
||||
appendParameters(constructor)
|
||||
append("V")
|
||||
}.toString()
|
||||
}
|
||||
else throw KotlinReflectionInternalError("Unknown origin of $function (${function.javaClass})")
|
||||
}
|
||||
|
||||
private fun StringBuilder.appendParameters(callable: JavaCallable) {
|
||||
append("(")
|
||||
for (parameter in callable.getValueParameters()) {
|
||||
appendJavaType(parameter.getType())
|
||||
}
|
||||
append(")")
|
||||
}
|
||||
|
||||
// TODO: verify edge cases when it's possible to reference generic functions
|
||||
private tailRecursive fun StringBuilder.appendJavaType(type: JavaType) {
|
||||
when (type) {
|
||||
|
||||
@@ -16,13 +16,12 @@
|
||||
|
||||
package kotlin.reflect.jvm
|
||||
|
||||
import java.lang.reflect.Constructor
|
||||
import java.lang.reflect.Field
|
||||
import java.lang.reflect.Method
|
||||
import java.lang.reflect.Modifier
|
||||
import kotlin.reflect.*
|
||||
import kotlin.reflect.jvm.internal.KClassImpl
|
||||
import kotlin.reflect.jvm.internal.KMutablePropertyImpl
|
||||
import kotlin.reflect.jvm.internal.KPackageImpl
|
||||
import kotlin.reflect.jvm.internal.KPropertyImpl
|
||||
import kotlin.reflect.jvm.internal.*
|
||||
|
||||
// Kotlin reflection -> Java reflection
|
||||
|
||||
@@ -64,6 +63,21 @@ public val KMutableProperty<*>.javaSetter: Method?
|
||||
get() = (this as? KMutablePropertyImpl<*>)?.javaSetter
|
||||
|
||||
|
||||
/**
|
||||
* Returns a Java [Method] instance corresponding to the given Kotlin function,
|
||||
* or `null` if this function is a constructor or cannot be represented by a Java [Method].
|
||||
*/
|
||||
public val KFunction<*>.javaMethod: Method?
|
||||
get() = (this as? KFunctionImpl)?.javaMethod
|
||||
|
||||
/**
|
||||
* Returns a Java [Constructor] instance corresponding to the given Kotlin function,
|
||||
* or `null` if this function is not a constructor or cannot be represented by a Java [Constructor].
|
||||
*/
|
||||
@suppress("UNCHECKED_CAST")
|
||||
public val <T> KFunction<T>.javaConstructor: Constructor<T>?
|
||||
get() = (this as? KFunctionImpl)?.javaConstructor as Constructor<T>?
|
||||
|
||||
|
||||
|
||||
// Java reflection -> Kotlin reflection
|
||||
@@ -82,7 +96,8 @@ public val <T> Class<T>.kotlin: KClass<T>
|
||||
* for more information.
|
||||
*/
|
||||
public val Class<*>.kotlinPackage: KPackage?
|
||||
get() = if (getAnnotation(javaClass<kotlin.jvm.internal.KotlinPackage>()) != null) KPackageImpl(this) else null
|
||||
get() = if (getSimpleName().endsWith("Package") &&
|
||||
getAnnotation(javaClass<kotlin.jvm.internal.KotlinPackage>()) != null) KPackageImpl(this) else null
|
||||
|
||||
|
||||
/**
|
||||
@@ -94,10 +109,38 @@ public val Field.kotlin: KProperty<*>?
|
||||
get() {
|
||||
if (isSynthetic()) return null
|
||||
|
||||
val clazz = getDeclaringClass().kotlin as KClassImpl
|
||||
|
||||
// TODO: fields in package parts
|
||||
// TODO: optimize (search by name)
|
||||
return clazz.properties.firstOrNull { p: KProperty<*> ->
|
||||
(p as KPropertyImpl<*>).javaField == this
|
||||
}
|
||||
return getDeclaringClass().kotlin.properties.firstOrNull { it.javaField == this }
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a [KFunction] instance corresponding to the given Java [Method] instance,
|
||||
* or `null` if this method cannot be represented by a Kotlin function
|
||||
* (for example, if it is a synthetic method).
|
||||
*/
|
||||
public val Method.kotlinFunction: KFunction<*>?
|
||||
get() {
|
||||
if (isSynthetic()) return null
|
||||
|
||||
if (Modifier.isStatic(getModifiers())) {
|
||||
getDeclaringClass().kotlinPackage?.let { pkg ->
|
||||
return pkg.functions.firstOrNull { it.javaMethod == this }
|
||||
}
|
||||
}
|
||||
|
||||
return getDeclaringClass().kotlin.functions.firstOrNull { it.javaMethod == this }
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a [KFunction] instance corresponding to the given Java [Constructor] instance,
|
||||
* or `null` if this constructor cannot be represented by a Kotlin function
|
||||
* (for example, if it is a synthetic constructor).
|
||||
*/
|
||||
public val <T> Constructor<T>.kotlinFunction: KFunction<T>?
|
||||
get() {
|
||||
if (isSynthetic()) return null
|
||||
|
||||
return getDeclaringClass().kotlin.constructors.firstOrNull { it.javaConstructor == this }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user