From fd97383f8a7853bce9406bb69a007850115f9bb7 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Thu, 20 Aug 2015 16:10:12 -0700 Subject: [PATCH] Fix mapping of jvmStatic functions #KT-8800 Fixed --- .../platformStatic/companionObjectFunction.kt | 33 +++++++++++++++++++ .../mapping/platformStatic/objectFunction.kt | 19 +++++++++++ ...lackBoxWithStdlibCodegenTestGenerated.java | 21 ++++++++++++ .../src/kotlin/reflect/jvm/mapping.kt | 27 +++++++++++---- 4 files changed, 94 insertions(+), 6 deletions(-) create mode 100644 compiler/testData/codegen/boxWithStdlib/reflection/mapping/platformStatic/companionObjectFunction.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/reflection/mapping/platformStatic/objectFunction.kt diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/mapping/platformStatic/companionObjectFunction.kt b/compiler/testData/codegen/boxWithStdlib/reflection/mapping/platformStatic/companionObjectFunction.kt new file mode 100644 index 00000000000..2e7784ee1a4 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/reflection/mapping/platformStatic/companionObjectFunction.kt @@ -0,0 +1,33 @@ +import kotlin.platform.platformStatic as static +import kotlin.reflect.jvm.* +import kotlin.test.assertEquals +import kotlin.test.failsWith + +class C { + companion object { + @static fun foo(s: String): Int = s.length() + } +} + +fun box(): String { + val foo = C.Companion::foo + + val j = foo.javaMethod ?: return "Fail: no Java method found for C::foo" + assertEquals(3, j.invoke(C, "abc")) + + val k = j.kotlinFunction ?: return "Fail: no Kotlin function found for Java method C::foo" + assertEquals(3, k.call(C, "def")) + + + val staticMethod = javaClass().getDeclaredMethod("foo", javaClass()) + val k2 = staticMethod.kotlinFunction ?: + return "Fail: no Kotlin function found for static bridge for @jvmStatic method in companion object C::foo" + assertEquals(3, k2.call(C, "ghi")) + + failsWith(javaClass()) { k2.call(null, "")!! } + + val j2 = k2.javaMethod + assertEquals(j, j2) + + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/mapping/platformStatic/objectFunction.kt b/compiler/testData/codegen/boxWithStdlib/reflection/mapping/platformStatic/objectFunction.kt new file mode 100644 index 00000000000..d912ee8a578 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/reflection/mapping/platformStatic/objectFunction.kt @@ -0,0 +1,19 @@ +import kotlin.platform.platformStatic as static +import kotlin.reflect.jvm.* +import kotlin.test.assertEquals + +object O { + @static fun foo(s: String): Int = s.length() +} + +fun box(): String { + val foo = O::foo + + val j = foo.javaMethod ?: return "Fail: no Java method found for O::foo" + assertEquals(3, j.invoke(null, "abc")) + + val k = j.kotlinFunction ?: return "Fail: no Kotlin function found for Java method O::foo" + assertEquals(3, k.call(O, "def")) + + 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 11341758ce5..da19367c738 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java @@ -3396,6 +3396,27 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode doTestWithStdlib(fileName); } + @TestMetadata("compiler/testData/codegen/boxWithStdlib/reflection/mapping/platformStatic") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class PlatformStatic extends AbstractBlackBoxCodegenTest { + public void testAllFilesPresentInPlatformStatic() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxWithStdlib/reflection/mapping/platformStatic"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("companionObjectFunction.kt") + public void testCompanionObjectFunction() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/mapping/platformStatic/companionObjectFunction.kt"); + doTestWithStdlib(fileName); + } + + @TestMetadata("objectFunction.kt") + public void testObjectFunction() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/mapping/platformStatic/objectFunction.kt"); + doTestWithStdlib(fileName); + } + } + @TestMetadata("compiler/testData/codegen/boxWithStdlib/reflection/mapping/types") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/mapping.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/mapping.kt index 9b584af2082..765e23fb253 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/mapping.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/mapping.kt @@ -17,8 +17,12 @@ package kotlin.reflect.jvm import java.lang.reflect.* +import java.util.* import kotlin.reflect.* -import kotlin.reflect.jvm.internal.* +import kotlin.reflect.jvm.internal.KCallableImpl +import kotlin.reflect.jvm.internal.KPackageImpl +import kotlin.reflect.jvm.internal.KPropertyImpl +import kotlin.reflect.jvm.internal.KTypeImpl // Kotlin reflection -> Java reflection @@ -115,15 +119,26 @@ public val Field.kotlinProperty: KProperty<*>? */ public val Method.kotlinFunction: KFunction<*>? get() { - if (isSynthetic()) return null + if (isSynthetic) return null - if (Modifier.isStatic(getModifiers())) { - getDeclaringClass().kotlinPackage?.let { pkg -> - return pkg.functions.firstOrNull { it.javaMethod == this } + if (Modifier.isStatic(modifiers)) { + val kotlinPackage = declaringClass.kotlinPackage + if (kotlinPackage != null) { + return kotlinPackage.functions.firstOrNull { it.javaMethod == this } + } + + // For static bridge method generated for a jvmStatic function in the companion object, also try to find the latter + val companion = declaringClass.kotlin.companionObject + if (companion != null) { + companion.functions.firstOrNull { + val m = it.javaMethod + m != null && m.name == this.name && + Arrays.equals(m.parameterTypes, this.parameterTypes) && m.returnType == this.returnType + }?.let { return it } } } - return getDeclaringClass().kotlin.functions.firstOrNull { it.javaMethod == this } + return declaringClass.kotlin.functions.firstOrNull { it.javaMethod == this } } /**