KT-13440 Bound callable references in reflection

This commit is contained in:
Dmitry Petrov
2016-11-23 18:54:58 +03:00
parent 5879e201cd
commit 3d2696c81b
33 changed files with 1276 additions and 70 deletions
@@ -1,3 +1,6 @@
// TODO investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
class A { class A {
companion object { companion object {
fun ok() = "OK" fun ok() = "OK"
@@ -1,3 +1,6 @@
// TODO investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
object Singleton { object Singleton {
fun ok() = "OK" fun ok() = "OK"
} }
@@ -1,6 +1,3 @@
// TODO: investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
fun Boolean.foo() = 1 fun Boolean.foo() = 1
fun Byte.foo() = 2 fun Byte.foo() = 2
fun Short.foo() = 3 fun Short.foo() = 3
@@ -33,8 +33,9 @@ fun check(lambda: () -> Unit) {
lambda() lambda()
} catch (e: Throwable) { } catch (e: Throwable) {
if (e !is InvocationTargetException && e !is StackOverflowError) { if (e !is InvocationTargetException && e !is StackOverflowError) {
throw AssertionError("The current implementation uses reflection to get the value of the property," + throw RuntimeException("The current implementation uses reflection to get the value of the property," +
"so either InvocationTargetException or StackOverflowError should have happened, but was: ${e}") "so either InvocationTargetException or StackOverflowError should have happened",
e)
} }
return return
} }
@@ -0,0 +1,53 @@
// TODO: investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
// WITH_REFLECT
import kotlin.reflect.*
import kotlin.test.assertEquals
class Host {
companion object {
val x = 1
var y = 2
val xx: Int
get() = x
var yy: Int
get() = y
set(value) { y = value }
}
}
val c_x = Host.Companion::x
val c_xx = Host.Companion::xx
val c_y = Host.Companion::y
val c_yy = Host.Companion::yy
fun box(): String {
assertEquals(1, c_x.getter())
assertEquals(1, c_x.getter.call())
assertEquals(1, c_xx.getter())
assertEquals(1, c_xx.getter.call())
assertEquals(2, c_y.getter())
assertEquals(2, c_y.getter.call())
assertEquals(2, c_yy.getter())
assertEquals(2, c_yy.getter.call())
c_y.setter(10)
assertEquals(10, c_y.getter())
assertEquals(10, c_yy.getter())
c_yy.setter(20)
assertEquals(20, c_y.getter())
assertEquals(20, c_yy.getter())
c_y.setter.call(100)
assertEquals(100, c_yy.getter.call())
c_yy.setter.call(200)
assertEquals(200, c_y.getter.call())
return "OK"
}
@@ -0,0 +1,12 @@
// TODO: investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
// WITH_REFLECT
import kotlin.reflect.*
fun String.foo(x: String) = this + x
fun String?.bar(x: String) = x
fun box() =
(""::foo).call("O") + (null::bar).call("K")
@@ -0,0 +1,45 @@
// TODO: investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
// WITH_REFLECT
import kotlin.reflect.*
import kotlin.test.assertEquals
class C(val x: Int, var y: Int)
val C.xx: Int
get() = x
var C.yy: Int
get() = y
set(value) { y = value }
val c = C(1, 2)
val c_xx = c::xx
val c_y = c::y
val c_yy = c::yy
fun box(): String {
assertEquals(1, c_xx.getter())
assertEquals(1, c_xx.getter.call())
assertEquals(2, c_yy.getter())
assertEquals(2, c_yy.getter.call())
c_y.setter(10)
assertEquals(10, c_yy.getter())
c_yy.setter(20)
assertEquals(20, c_y.getter())
assertEquals(20, c_yy.getter())
c_y.setter.call(100)
assertEquals(100, c_yy.getter.call())
c_yy.setter.call(200)
assertEquals(200, c_y.getter.call())
return "OK"
}
@@ -0,0 +1,16 @@
// TODO: investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
// WITH_REFLECT
class Outer(val x: String) {
inner class Inner(val y: String) {
fun foo() = x + y
}
}
fun box(): String {
val innerCtor = Outer("O")::Inner
val inner = innerCtor.call("K")
return inner.foo()
}
@@ -0,0 +1,40 @@
// TODO: investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
// WITH_REFLECT
// FILE: J.java
public class J {
public final int finalField;
public String mutableField;
public J(int f, String m) {
this.finalField = f;
this.mutableField = m;
}
}
// FILE: K.kt
import kotlin.reflect.*
import kotlin.reflect.jvm.*
import kotlin.test.assertEquals
fun box(): String {
val j = J(0, "")
val jf = j::finalField
val jm = j::mutableField
assertEquals(0, jf.getter())
assertEquals(0, jf.getter.call())
assertEquals("", jm.getter())
assertEquals("", jm.getter.call())
jm.setter("1")
assertEquals("1", j.mutableField)
jm.setter.call("2")
assertEquals("2", j.mutableField)
return "OK"
}
@@ -0,0 +1,35 @@
// TODO: investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
// WITH_REFLECT
// FILE: J.java
public class J {
private final int param;
public J(int param) {
this.param = param;
}
public String foo(int[] arr, Object[] arr2, Integer y) {
return "" + param + arr[0] + arr2[0] + y;
}
}
// FILE: K.kt
import kotlin.reflect.*
import kotlin.reflect.jvm.*
import kotlin.test.assertEquals
fun box(): String {
val f = J(0)::foo
assertEquals(
listOf(IntArray::class.java, Array<Any>::class.java, Integer::class.java),
f.parameters.map { it.type.javaType }
)
assertEquals(String::class.java, f.returnType.javaType)
assertEquals("01A2", f.call(intArrayOf(1), arrayOf("A"), 2))
return "OK"
}
@@ -0,0 +1,53 @@
// TODO: investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
// WITH_REFLECT
import kotlin.reflect.*
import kotlin.test.assertEquals
class Host {
companion object {
@JvmStatic val x = 1
@JvmStatic var y = 2
@JvmStatic val xx: Int
get() = x
@JvmStatic var yy: Int
get() = y
set(value) { y = value }
}
}
val c_x = Host.Companion::x
val c_xx = Host.Companion::xx
val c_y = Host.Companion::y
val c_yy = Host.Companion::yy
fun box(): String {
assertEquals(1, c_x.getter())
assertEquals(1, c_x.getter.call())
assertEquals(1, c_xx.getter())
assertEquals(1, c_xx.getter.call())
assertEquals(2, c_y.getter())
assertEquals(2, c_y.getter.call())
assertEquals(2, c_yy.getter())
assertEquals(2, c_yy.getter.call())
c_y.setter(10)
assertEquals(10, c_y.getter())
assertEquals(10, c_yy.getter())
c_yy.setter(20)
assertEquals(20, c_y.getter())
assertEquals(20, c_yy.getter())
c_y.setter.call(100)
assertEquals(100, c_yy.getter.call())
c_yy.setter.call(200)
assertEquals(200, c_y.getter.call())
return "OK"
}
@@ -0,0 +1,19 @@
// TODO: investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
// WITH_REFLECT
import kotlin.reflect.*
object Host {
@JvmStatic fun foo(x: String) = x
}
class CompanionOwner {
companion object {
@JvmStatic fun bar(x: String) = x
}
}
fun box(): String =
(Host::foo).call("O") + (CompanionOwner.Companion::bar).call("K")
@@ -0,0 +1,51 @@
// TODO: investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
// WITH_REFLECT
import kotlin.reflect.*
import kotlin.test.assertEquals
object Host {
@JvmStatic val x = 1
@JvmStatic var y = 2
@JvmStatic val xx: Int
get() = x
@JvmStatic var yy: Int
get() = y
set(value) { y = value }
}
val c_x = Host::x
val c_xx = Host::xx
val c_y = Host::y
val c_yy = Host::yy
fun box(): String {
assertEquals(1, c_x.getter())
assertEquals(1, c_x.getter.call())
assertEquals(1, c_xx.getter())
assertEquals(1, c_xx.getter.call())
assertEquals(2, c_y.getter())
assertEquals(2, c_y.getter.call())
assertEquals(2, c_yy.getter())
assertEquals(2, c_yy.getter.call())
c_y.setter(10)
assertEquals(10, c_y.getter())
assertEquals(10, c_yy.getter())
c_yy.setter(20)
assertEquals(20, c_y.getter())
assertEquals(20, c_yy.getter())
c_y.setter.call(100)
assertEquals(100, c_yy.getter.call())
c_yy.setter.call(200)
assertEquals(200, c_y.getter.call())
return "OK"
}
@@ -0,0 +1,14 @@
// TODO: investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
// WITH_REFLECT
import kotlin.reflect.*
class C(val k: String) {
fun foo(s: String) = s + k
}
fun box(): String =
C("K")::foo.call("O")
@@ -0,0 +1,50 @@
// TODO: investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
// WITH_REFLECT
import kotlin.reflect.*
import kotlin.test.assertEquals
class C(val x: Int, var y: Int) {
val xx: Int
get() = x
var yy: Int
get() = y
set(value) { y = value }
}
val c = C(1, 2)
val c_x = c::x
val c_xx = c::xx
val c_y = c::y
val c_yy = c::yy
fun box(): String {
assertEquals(1, c_x.getter())
assertEquals(1, c_x.getter.call())
assertEquals(1, c_xx.getter())
assertEquals(1, c_xx.getter.call())
assertEquals(2, c_y.getter())
assertEquals(2, c_y.getter.call())
assertEquals(2, c_yy.getter())
assertEquals(2, c_yy.getter.call())
c_y.setter(10)
assertEquals(10, c_y.getter())
assertEquals(10, c_yy.getter())
c_yy.setter(20)
assertEquals(20, c_y.getter())
assertEquals(20, c_yy.getter())
c_y.setter.call(100)
assertEquals(100, c_yy.getter.call())
c_yy.setter.call(200)
assertEquals(200, c_y.getter.call())
return "OK"
}
@@ -0,0 +1,19 @@
// TODO: investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
// WITH_REFLECT
import kotlin.reflect.*
object Host {
fun foo(x: String) = x
}
class CompanionOwner {
companion object {
fun bar(x: String) = x
}
}
fun box(): String =
(Host::foo).call("O") + (CompanionOwner.Companion::bar).call("K")
@@ -0,0 +1,51 @@
// TODO: investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
// WITH_REFLECT
import kotlin.reflect.*
import kotlin.test.assertEquals
object Host {
val x = 1
var y = 2
val xx: Int
get() = x
var yy: Int
get() = y
set(value) { y = value }
}
val c_x = Host::x
val c_xx = Host::xx
val c_y = Host::y
val c_yy = Host::yy
fun box(): String {
assertEquals(1, c_x.getter())
assertEquals(1, c_x.getter.call())
assertEquals(1, c_xx.getter())
assertEquals(1, c_xx.getter.call())
assertEquals(2, c_y.getter())
assertEquals(2, c_y.getter.call())
assertEquals(2, c_yy.getter())
assertEquals(2, c_yy.getter.call())
c_y.setter(10)
assertEquals(10, c_y.getter())
assertEquals(10, c_yy.getter())
c_yy.setter(20)
assertEquals(20, c_y.getter())
assertEquals(20, c_yy.getter())
c_y.setter.call(100)
assertEquals(100, c_yy.getter.call())
c_yy.setter.call(200)
assertEquals(200, c_y.getter.call())
return "OK"
}
@@ -0,0 +1,13 @@
// TODO: muted automatically, investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
// WITH_REFLECT
import kotlin.test.assertEquals
fun String.extFun(k: String, s: String = "") = this + k + s
fun box(): String {
val sExtFun = "O"::extFun
return sExtFun.callBy(mapOf(sExtFun.parameters[0] to "K"))
}
@@ -0,0 +1,12 @@
// TODO: muted automatically, investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
// WITH_REFLECT
import kotlin.test.assertEquals
val String.plusK: String
get() = this + "K"
fun box(): String =
("O"::plusK).getter.callBy(mapOf())
@@ -0,0 +1,19 @@
// TODO: muted automatically, investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
// WITH_REFLECT
object Host {
@JvmStatic fun concat(s1: String, s2: String, s3: String = "K", s4: String = "x") =
s1 + s2 + s3 + s4
}
fun box(): String {
val concat = Host::concat
val concatParams = concat.parameters
return concat.callBy(mapOf(
concatParams[0] to "",
concatParams[1] to "O",
concatParams[3] to ""
))
}
@@ -5,6 +5,7 @@
import kotlin.test.assertTrue import kotlin.test.assertTrue
import kotlin.test.assertFalse import kotlin.test.assertFalse
import kotlin.test.assertEquals
inline fun Unit.foo( inline fun Unit.foo(
noinline coroutine x: Unit.() -> Continuation<Unit>, noinline coroutine x: Unit.() -> Continuation<Unit>,
@@ -14,14 +15,13 @@ inline fun Unit.foo(
fun box(): String { fun box(): String {
val p = Unit::foo.parameters val p = Unit::foo.parameters
assertEquals(2, p.size)
assertFalse(p[0].isVararg) assertFalse(p[0].isVararg)
assertFalse(p[0].isCoroutine) assertTrue(p[0].isCoroutine)
assertFalse(p[1].isVararg) assertTrue(p[1].isVararg)
assertTrue(p[1].isCoroutine) assertFalse(p[1].isCoroutine)
assertTrue(p[2].isVararg)
assertFalse(p[2].isCoroutine)
return "OK" return "OK"
} }
@@ -0,0 +1,27 @@
// TODO: muted automatically, investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
// WITH_REFLECT
import kotlin.reflect.KParameter
import kotlin.test.assertEquals
class Outer(val s1: String) {
inner class Inner(val s2: String, val s3: String = "K") {
val result = s1 + s2 + s3
}
}
fun KParameter.check(name: String) {
assertEquals(name, this.name!!)
assertEquals(KParameter.Kind.VALUE, this.kind)
}
fun box(): String {
val ctor = Outer("O")::Inner
val ctorPararms = ctor.parameters
ctorPararms[0].check("s2")
ctorPararms[1].check("s3")
return "OK"
}
@@ -0,0 +1,26 @@
// TODO: investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
// WITH_REFLECT
import kotlin.reflect.*
import kotlin.reflect.jvm.*
import kotlin.test.assertEquals
object Host {
fun foo(i: Int, s: String) {}
}
fun box(): String {
val fooParams = Host::foo.parameters
assertEquals(2, fooParams.size)
assertEquals("i", fooParams[0].name)
assertEquals(Int::class.java, fooParams[0].type.javaType)
assertEquals("s", fooParams[1].name)
assertEquals(String::class.java, fooParams[1].type.javaType)
return "OK"
}
@@ -0,0 +1,35 @@
// TODO: investigate should it be ran for JS or not
// IGNORE_BACKEND: JS
// WITH_REFLECT
import kotlin.reflect.*
import kotlin.reflect.jvm.*
import kotlin.test.*
class C {
fun foo() {}
var bar = "OK"
}
fun C.extFun(i: Int) {}
fun KParameter.check(name: String) {
assertEquals(name, this.name!!)
assertEquals(KParameter.Kind.VALUE, this.kind)
}
fun box(): String {
val cFoo = C()::foo
val cBar = C()::bar
val cExtFun = C()::extFun
assertEquals(0, cFoo.parameters.size)
assertEquals(0, cBar.getter.parameters.size)
assertEquals(1, cBar.setter.parameters.size)
assertEquals(1, cExtFun.parameters.size)
cExtFun.parameters[0].check("i")
return "OK"
}
@@ -12348,6 +12348,93 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/simpleTopLevelFunctions.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/simpleTopLevelFunctions.kt");
doTest(fileName); doTest(fileName);
} }
@TestMetadata("compiler/testData/codegen/box/reflection/call/bound")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Bound extends AbstractIrBlackBoxCodegenTest {
public void testAllFilesPresentInBound() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/call/bound"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
}
@TestMetadata("companionObjectPropertyAccessors.kt")
public void testCompanionObjectPropertyAccessors() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/companionObjectPropertyAccessors.kt");
doTest(fileName);
}
@TestMetadata("extensionFunction.kt")
public void testExtensionFunction() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/extensionFunction.kt");
doTest(fileName);
}
@TestMetadata("extensionPropertyAccessors.kt")
public void testExtensionPropertyAccessors() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/extensionPropertyAccessors.kt");
doTest(fileName);
}
@TestMetadata("innerClassConstructor.kt")
public void testInnerClassConstructor() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/innerClassConstructor.kt");
doTest(fileName);
}
@TestMetadata("javaInstanceField.kt")
public void testJavaInstanceField() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/javaInstanceField.kt");
doTest(fileName);
}
@TestMetadata("javaInstanceMethod.kt")
public void testJavaInstanceMethod() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/javaInstanceMethod.kt");
doTest(fileName);
}
@TestMetadata("jvmStaticCompanionObjectPropertyAccessors.kt")
public void testJvmStaticCompanionObjectPropertyAccessors() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/jvmStaticCompanionObjectPropertyAccessors.kt");
doTest(fileName);
}
@TestMetadata("jvmStaticObjectFunction.kt")
public void testJvmStaticObjectFunction() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/jvmStaticObjectFunction.kt");
doTest(fileName);
}
@TestMetadata("jvmStaticObjectPropertyAccessors.kt")
public void testJvmStaticObjectPropertyAccessors() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/jvmStaticObjectPropertyAccessors.kt");
doTest(fileName);
}
@TestMetadata("memberFunction.kt")
public void testMemberFunction() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/memberFunction.kt");
doTest(fileName);
}
@TestMetadata("memberPropertyAccessors.kt")
public void testMemberPropertyAccessors() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/memberPropertyAccessors.kt");
doTest(fileName);
}
@TestMetadata("objectFunction.kt")
public void testObjectFunction() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/objectFunction.kt");
doTest(fileName);
}
@TestMetadata("objectPropertyAccessors.kt")
public void testObjectPropertyAccessors() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/objectPropertyAccessors.kt");
doTest(fileName);
}
}
} }
@TestMetadata("compiler/testData/codegen/box/reflection/callBy") @TestMetadata("compiler/testData/codegen/box/reflection/callBy")
@@ -12358,6 +12445,24 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/callBy"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/callBy"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
} }
@TestMetadata("boundExtensionFunction.kt")
public void testBoundExtensionFunction() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/callBy/boundExtensionFunction.kt");
doTest(fileName);
}
@TestMetadata("boundExtensionPropertyAcessor.kt")
public void testBoundExtensionPropertyAcessor() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/callBy/boundExtensionPropertyAcessor.kt");
doTest(fileName);
}
@TestMetadata("boundJvmStaticInObject.kt")
public void testBoundJvmStaticInObject() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/callBy/boundJvmStaticInObject.kt");
doTest(fileName);
}
@TestMetadata("companionObject.kt") @TestMetadata("companionObject.kt")
public void testCompanionObject() throws Exception { public void testCompanionObject() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/callBy/companionObject.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/callBy/companionObject.kt");
@@ -13546,6 +13651,24 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/parameters"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/parameters"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
} }
@TestMetadata("boundInnerClassConstructor.kt")
public void testBoundInnerClassConstructor() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/parameters/boundInnerClassConstructor.kt");
doTest(fileName);
}
@TestMetadata("boundObjectMemberReferences.kt")
public void testBoundObjectMemberReferences() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/parameters/boundObjectMemberReferences.kt");
doTest(fileName);
}
@TestMetadata("boundReferences.kt")
public void testBoundReferences() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/parameters/boundReferences.kt");
doTest(fileName);
}
@TestMetadata("findParameterByName.kt") @TestMetadata("findParameterByName.kt")
public void testFindParameterByName() throws Exception { public void testFindParameterByName() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/parameters/findParameterByName.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/parameters/findParameterByName.kt");
@@ -332,12 +332,6 @@ public class AdditionalCoroutineBlackBoxCodegenTestGenerated extends AbstractAdd
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/controlFlow"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/controlFlow"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
} }
@TestMetadata("throwInTryWithHandleResult.kt")
public void testThrowInTryWithHandleResult() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/controlFlow/throwInTryWithHandleResult.kt");
doTest(fileName);
}
} }
@TestMetadata("compiler/testData/codegen/box/coroutines/intLikeVarSpilling") @TestMetadata("compiler/testData/codegen/box/coroutines/intLikeVarSpilling")
@@ -12348,6 +12348,93 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/simpleTopLevelFunctions.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/simpleTopLevelFunctions.kt");
doTest(fileName); doTest(fileName);
} }
@TestMetadata("compiler/testData/codegen/box/reflection/call/bound")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Bound extends AbstractBlackBoxCodegenTest {
public void testAllFilesPresentInBound() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/call/bound"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
}
@TestMetadata("companionObjectPropertyAccessors.kt")
public void testCompanionObjectPropertyAccessors() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/companionObjectPropertyAccessors.kt");
doTest(fileName);
}
@TestMetadata("extensionFunction.kt")
public void testExtensionFunction() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/extensionFunction.kt");
doTest(fileName);
}
@TestMetadata("extensionPropertyAccessors.kt")
public void testExtensionPropertyAccessors() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/extensionPropertyAccessors.kt");
doTest(fileName);
}
@TestMetadata("innerClassConstructor.kt")
public void testInnerClassConstructor() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/innerClassConstructor.kt");
doTest(fileName);
}
@TestMetadata("javaInstanceField.kt")
public void testJavaInstanceField() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/javaInstanceField.kt");
doTest(fileName);
}
@TestMetadata("javaInstanceMethod.kt")
public void testJavaInstanceMethod() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/javaInstanceMethod.kt");
doTest(fileName);
}
@TestMetadata("jvmStaticCompanionObjectPropertyAccessors.kt")
public void testJvmStaticCompanionObjectPropertyAccessors() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/jvmStaticCompanionObjectPropertyAccessors.kt");
doTest(fileName);
}
@TestMetadata("jvmStaticObjectFunction.kt")
public void testJvmStaticObjectFunction() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/jvmStaticObjectFunction.kt");
doTest(fileName);
}
@TestMetadata("jvmStaticObjectPropertyAccessors.kt")
public void testJvmStaticObjectPropertyAccessors() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/jvmStaticObjectPropertyAccessors.kt");
doTest(fileName);
}
@TestMetadata("memberFunction.kt")
public void testMemberFunction() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/memberFunction.kt");
doTest(fileName);
}
@TestMetadata("memberPropertyAccessors.kt")
public void testMemberPropertyAccessors() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/memberPropertyAccessors.kt");
doTest(fileName);
}
@TestMetadata("objectFunction.kt")
public void testObjectFunction() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/objectFunction.kt");
doTest(fileName);
}
@TestMetadata("objectPropertyAccessors.kt")
public void testObjectPropertyAccessors() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/objectPropertyAccessors.kt");
doTest(fileName);
}
}
} }
@TestMetadata("compiler/testData/codegen/box/reflection/callBy") @TestMetadata("compiler/testData/codegen/box/reflection/callBy")
@@ -12358,6 +12445,24 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/callBy"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/callBy"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
} }
@TestMetadata("boundExtensionFunction.kt")
public void testBoundExtensionFunction() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/callBy/boundExtensionFunction.kt");
doTest(fileName);
}
@TestMetadata("boundExtensionPropertyAcessor.kt")
public void testBoundExtensionPropertyAcessor() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/callBy/boundExtensionPropertyAcessor.kt");
doTest(fileName);
}
@TestMetadata("boundJvmStaticInObject.kt")
public void testBoundJvmStaticInObject() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/callBy/boundJvmStaticInObject.kt");
doTest(fileName);
}
@TestMetadata("companionObject.kt") @TestMetadata("companionObject.kt")
public void testCompanionObject() throws Exception { public void testCompanionObject() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/callBy/companionObject.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/callBy/companionObject.kt");
@@ -13546,6 +13651,24 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/parameters"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/parameters"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
} }
@TestMetadata("boundInnerClassConstructor.kt")
public void testBoundInnerClassConstructor() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/parameters/boundInnerClassConstructor.kt");
doTest(fileName);
}
@TestMetadata("boundObjectMemberReferences.kt")
public void testBoundObjectMemberReferences() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/parameters/boundObjectMemberReferences.kt");
doTest(fileName);
}
@TestMetadata("boundReferences.kt")
public void testBoundReferences() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/parameters/boundReferences.kt");
doTest(fileName);
}
@TestMetadata("findParameterByName.kt") @TestMetadata("findParameterByName.kt")
public void testFindParameterByName() throws Exception { public void testFindParameterByName() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/parameters/findParameterByName.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/parameters/findParameterByName.kt");
@@ -67,16 +67,30 @@ internal abstract class FunctionCaller<out M : Member?>(
} }
} }
// TODO fix 'callBy' for bound (and non-bound) inner class constructor references
// See https://youtrack.jetbrains.com/issue/KT-14990
class BoundConstructor(constructor: ReflectConstructor<*>, private val boundReceiver: Any?) :
FunctionCaller<ReflectConstructor<*>>(
constructor, constructor.declaringClass, null,
constructor.genericParameterTypes
) {
override fun call(args: Array<*>): Any? {
checkArguments(args)
return member.newInstance(*argsWithReceiver(boundReceiver, args))
}
}
// Methods // Methods
abstract class Method( abstract class Method(
method: ReflectMethod, method: ReflectMethod,
requiresInstance: Boolean = !Modifier.isStatic(method.modifiers) requiresInstance: Boolean = !Modifier.isStatic(method.modifiers),
parameterTypes: Array<Type> = method.genericParameterTypes
) : FunctionCaller<ReflectMethod>( ) : FunctionCaller<ReflectMethod>(
method, method,
method.genericReturnType, method.genericReturnType,
if (requiresInstance) method.declaringClass else null, if (requiresInstance) method.declaringClass else null,
method.genericParameterTypes parameterTypes
) { ) {
private val isVoidMethod = returnType == Void.TYPE private val isVoidMethod = returnType == Void.TYPE
@@ -98,7 +112,7 @@ internal abstract class FunctionCaller<out M : Member?>(
class InstanceMethod(method: ReflectMethod) : Method(method) { class InstanceMethod(method: ReflectMethod) : Method(method) {
override fun call(args: Array<*>): Any? { override fun call(args: Array<*>): Any? {
checkArguments(args) checkArguments(args)
return callMethod(args[0], args.copyOfRange(1, args.size)) return callMethod(args[0], args.dropFirstArg())
} }
} }
@@ -106,7 +120,31 @@ internal abstract class FunctionCaller<out M : Member?>(
override fun call(args: Array<*>): Any? { override fun call(args: Array<*>): Any? {
checkArguments(args) checkArguments(args)
checkObjectInstance(args.firstOrNull()) checkObjectInstance(args.firstOrNull())
return callMethod(null, args.copyOfRange(1, args.size)) return callMethod(null, args.dropFirstArg())
}
}
class BoundStaticMethod(method: ReflectMethod, private val boundReceiver: Any?) :
Method(method, requiresInstance = false, parameterTypes = method.genericParameterTypes.dropFirst()) {
override fun call(args: Array<*>): Any? {
checkArguments(args)
return callMethod(null, argsWithReceiver(boundReceiver, args))
}
}
class BoundInstanceMethod(method: ReflectMethod, private val boundReceiver: Any?) :
Method(method, requiresInstance = false) {
override fun call(args: Array<*>): Any? {
checkArguments(args)
return callMethod(boundReceiver, args)
}
}
class BoundJvmStaticInObject(method: ReflectMethod) :
Method(method, requiresInstance = false) {
override fun call(args: Array<*>): Any? {
checkArguments(args)
return callMethod(null, args)
} }
} }
@@ -161,21 +199,32 @@ internal abstract class FunctionCaller<out M : Member?>(
} }
} }
class ClassCompanionFieldGetter( class ClassCompanionFieldGetter(field: ReflectField, klass: Class<*>) :
field: ReflectField, FunctionCaller<ReflectField>(field, field.genericType, klass, emptyArray()) {
klass: Class<*>
) : FunctionCaller<ReflectField>(
field,
field.genericType,
klass,
emptyArray()
) {
override fun call(args: Array<*>): Any? { override fun call(args: Array<*>): Any? {
checkArguments(args) checkArguments(args)
return member.get(args.first()) return member.get(args.first())
} }
} }
class BoundInstanceFieldGetter(field: ReflectField, private val boundReceiver: Any?) :
FieldGetter(field, requiresInstance = false) {
override fun call(args: Array<*>): Any? {
checkArguments(args)
return member.get(boundReceiver)
}
}
class BoundJvmStaticInObjectFieldGetter(field: ReflectField) : FieldGetter(field, requiresInstance = false)
class BoundClassCompanionFieldGetter(field: ReflectField, private val boundReceiver: Any?) :
FieldGetter(field, requiresInstance = false) {
override fun call(args: Array<*>): Any? {
checkArguments(args)
return member.get(boundReceiver)
}
}
class StaticFieldSetter(field: ReflectField, notNull: Boolean) : FieldSetter(field, notNull) class StaticFieldSetter(field: ReflectField, notNull: Boolean) : FieldSetter(field, notNull)
class InstanceFieldSetter(field: ReflectField, notNull: Boolean) : FieldSetter(field, notNull) class InstanceFieldSetter(field: ReflectField, notNull: Boolean) : FieldSetter(field, notNull)
@@ -187,18 +236,53 @@ internal abstract class FunctionCaller<out M : Member?>(
} }
} }
class ClassCompanionFieldSetter( class ClassCompanionFieldSetter(field: ReflectField, klass: Class<*>) :
field: ReflectField, FunctionCaller<ReflectField>(field, Void.TYPE, klass, arrayOf(field.genericType)) {
klass: Class<*>
) : FunctionCaller<ReflectField>(
field,
Void.TYPE,
klass,
arrayOf(field.genericType)
) {
override fun call(args: Array<*>): Any? { override fun call(args: Array<*>): Any? {
checkArguments(args) checkArguments(args)
return member.set(instanceClass, args.last()) return member.set(null, args.last())
} }
} }
class BoundInstanceFieldSetter(field: ReflectField, notNull: Boolean, private val boundReceiver: Any?) :
FieldSetter(field, notNull, false) {
override fun call(args: Array<*>): Any? {
checkArguments(args)
return member.set(boundReceiver, args.first())
}
}
class BoundJvmStaticInObjectFieldSetter(field: ReflectField, notNull: Boolean) :
FieldSetter(field, notNull, requiresInstance = false) {
override fun call(args: Array<*>): Any? {
checkArguments(args)
return member.set(null, args.last())
}
}
class BoundClassCompanionFieldSetter(field: ReflectField, klass: Class<*>) :
FunctionCaller<ReflectField>(field, Void.TYPE, klass, arrayOf(field.genericType)) {
override fun call(args: Array<*>): Any? {
checkArguments(args)
return member.set(null, args.last())
}
}
companion object {
// TODO lazily allocate array at bound callers?
fun argsWithReceiver(receiver: Any?, args: Array<out Any?>): Array<out Any?> =
arrayOfNulls<Any?>(args.size + 1).apply {
this[0] = receiver
System.arraycopy(args, 0, this, 1, args.size)
}
@Suppress("UNCHECKED_CAST")
inline fun <reified T> Array<out T>.dropFirst(): Array<T> =
if (size <= 1) emptyArray<T>() else copyOfRange(1, size) as Array<T>
@Suppress("UNCHECKED_CAST")
fun Array<*>.dropFirstArg(): Array<Any?> =
(this as Array<Any?>).dropFirst()
}
} }
@@ -35,6 +35,8 @@ internal abstract class KCallableImpl<out R> : KCallable<R> {
abstract val container: KDeclarationContainerImpl abstract val container: KDeclarationContainerImpl
abstract val isBound: Boolean
private val annotations_ = ReflectProperties.lazySoft { descriptor.computeAnnotations() } private val annotations_ = ReflectProperties.lazySoft { descriptor.computeAnnotations() }
override val annotations: List<Annotation> get() = annotations_() override val annotations: List<Annotation> get() = annotations_()
@@ -44,11 +46,11 @@ internal abstract class KCallableImpl<out R> : KCallable<R> {
val result = ArrayList<KParameter>() val result = ArrayList<KParameter>()
var index = 0 var index = 0
if (descriptor.dispatchReceiverParameter != null) { if (descriptor.dispatchReceiverParameter != null && !isBound) {
result.add(KParameterImpl(this, index++, KParameter.Kind.INSTANCE) { descriptor.dispatchReceiverParameter!! }) result.add(KParameterImpl(this, index++, KParameter.Kind.INSTANCE) { descriptor.dispatchReceiverParameter!! })
} }
if (descriptor.extensionReceiverParameter != null) { if (descriptor.extensionReceiverParameter != null && !isBound) {
result.add(KParameterImpl(this, index++, KParameter.Kind.EXTENSION_RECEIVER) { descriptor.extensionReceiverParameter!! }) result.add(KParameterImpl(this, index++, KParameter.Kind.EXTENSION_RECEIVER) { descriptor.extensionReceiverParameter!! })
} }
@@ -50,6 +50,8 @@ internal class KFunctionImpl private constructor(
descriptor descriptor
) )
override val isBound: Boolean get() = boundReceiver != CallableReference.NO_RECEIVER
override val descriptor: FunctionDescriptor by ReflectProperties.lazySoft(descriptorInitialValue) { override val descriptor: FunctionDescriptor by ReflectProperties.lazySoft(descriptorInitialValue) {
container.findFunctionDescriptor(name, signature) container.findFunctionDescriptor(name, signature)
} }
@@ -77,13 +79,15 @@ internal class KFunctionImpl private constructor(
} }
when (member) { when (member) {
is Constructor<*> -> FunctionCaller.Constructor(member) is Constructor<*> ->
createConstructorCaller(member)
is Method -> when { is Method -> when {
!Modifier.isStatic(member.modifiers) -> FunctionCaller.InstanceMethod(member) !Modifier.isStatic(member.modifiers) ->
createInstanceMethodCaller(member)
descriptor.annotations.findAnnotation(JVM_STATIC) != null -> descriptor.annotations.findAnnotation(JVM_STATIC) != null ->
FunctionCaller.JvmStaticInObject(member) createJvmStaticInObjectCaller(member)
else ->
else -> FunctionCaller.StaticMethod(member) createStaticMethodCaller(member)
} }
else -> throw KotlinReflectionInternalError("Call is not yet supported for this function: $descriptor (member = $member)") else -> throw KotlinReflectionInternalError("Call is not yet supported for this function: $descriptor (member = $member)")
} }
@@ -112,21 +116,35 @@ internal class KFunctionImpl private constructor(
} }
when (member) { when (member) {
is Constructor<*> -> FunctionCaller.Constructor(member) is Constructor<*> ->
createConstructorCaller(member)
is Method -> when { is Method -> when {
// Note that static $default methods for @JvmStatic functions are generated differently in objects and companion objects. // Note that static $default methods for @JvmStatic functions are generated differently in objects and companion objects.
// In objects, $default's signature does _not_ contain the additional object instance parameter, // In objects, $default's signature does _not_ contain the additional object instance parameter,
// as opposed to companion objects where the first parameter is the companion object instance. // as opposed to companion objects where the first parameter is the companion object instance.
descriptor.annotations.findAnnotation(JVM_STATIC) != null && descriptor.annotations.findAnnotation(JVM_STATIC) != null &&
!(descriptor.containingDeclaration as ClassDescriptor).isCompanionObject -> !(descriptor.containingDeclaration as ClassDescriptor).isCompanionObject ->
FunctionCaller.JvmStaticInObject(member) createJvmStaticInObjectCaller(member)
else -> FunctionCaller.StaticMethod(member) else ->
createStaticMethodCaller(member)
} }
else -> null else -> null
} }
} }
private fun createStaticMethodCaller(member: Method) =
if (isBound) FunctionCaller.BoundStaticMethod(member, boundReceiver) else FunctionCaller.StaticMethod(member)
private fun createJvmStaticInObjectCaller(member: Method) =
if (isBound) FunctionCaller.BoundJvmStaticInObject(member) else FunctionCaller.JvmStaticInObject(member)
private fun createInstanceMethodCaller(member: Method) =
if (isBound) FunctionCaller.BoundInstanceMethod(member, boundReceiver) else FunctionCaller.InstanceMethod(member)
private fun createConstructorCaller(member: Constructor<*>) =
if (isBound) FunctionCaller.BoundConstructor(member, boundReceiver) else FunctionCaller.Constructor(member)
override fun getArity() = caller.arity override fun getArity() = caller.arity
override val isInline: Boolean override val isInline: Boolean
@@ -17,11 +17,12 @@
package kotlin.reflect.jvm.internal package kotlin.reflect.jvm.internal
import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import kotlin.jvm.internal.CallableReference
import kotlin.reflect.KMutableProperty2 import kotlin.reflect.KMutableProperty2
import kotlin.reflect.KProperty2 import kotlin.reflect.KProperty2
internal open class KProperty2Impl<D, E, out R> : KProperty2<D, E, R>, KPropertyImpl<R> { internal open class KProperty2Impl<D, E, out R> : KProperty2<D, E, R>, KPropertyImpl<R> {
constructor(container: KDeclarationContainerImpl, name: String, signature: String) : super(container, name, signature, null) constructor(container: KDeclarationContainerImpl, name: String, signature: String) : super(container, name, signature, CallableReference.NO_RECEIVER)
constructor(container: KDeclarationContainerImpl, descriptor: PropertyDescriptor) : super(container, descriptor) constructor(container: KDeclarationContainerImpl, descriptor: PropertyDescriptor) : super(container, descriptor)
@@ -37,7 +37,7 @@ internal abstract class KPropertyImpl<out R> private constructor(
override val name: String, override val name: String,
val signature: String, val signature: String,
descriptorInitialValue: PropertyDescriptor?, descriptorInitialValue: PropertyDescriptor?,
private val boundReceiver: Any? = CallableReference.NO_RECEIVER val boundReceiver: Any?
) : KCallableImpl<R>(), KProperty<R> { ) : KCallableImpl<R>(), KProperty<R> {
constructor(container: KDeclarationContainerImpl, name: String, signature: String, boundReceiver: Any?) : this( constructor(container: KDeclarationContainerImpl, name: String, signature: String, boundReceiver: Any?) : this(
container, name, signature, null, boundReceiver container, name, signature, null, boundReceiver
@@ -47,9 +47,12 @@ internal abstract class KPropertyImpl<out R> private constructor(
container, container,
descriptor.name.asString(), descriptor.name.asString(),
RuntimeTypeMapper.mapPropertySignature(descriptor).asString(), RuntimeTypeMapper.mapPropertySignature(descriptor).asString(),
descriptor descriptor,
CallableReference.NO_RECEIVER
) )
override val isBound: Boolean get() = boundReceiver != CallableReference.NO_RECEIVER
private val javaField_ = ReflectProperties.lazySoft { private val javaField_ = ReflectProperties.lazySoft {
val jvmSignature = RuntimeTypeMapper.mapPropertySignature(descriptor) val jvmSignature = RuntimeTypeMapper.mapPropertySignature(descriptor)
when (jvmSignature) { when (jvmSignature) {
@@ -116,6 +119,8 @@ internal abstract class KPropertyImpl<out R> private constructor(
override val defaultCaller: FunctionCaller<*>? get() = null override val defaultCaller: FunctionCaller<*>? get() = null
override val isBound: Boolean get() = property.isBound
override val isInline: Boolean get() = descriptor.isInline override val isInline: Boolean get() = descriptor.isInline
override val isExternal: Boolean get() = descriptor.isExternal override val isExternal: Boolean get() = descriptor.isExternal
override val isOperator: Boolean get() = descriptor.isOperator override val isOperator: Boolean get() = descriptor.isOperator
@@ -169,15 +174,27 @@ private fun KPropertyImpl.Accessor<*, *>.computeCallerForAccessor(isGetter: Bool
fun computeFieldCaller(field: Field): FunctionCaller<Field> = when { fun computeFieldCaller(field: Field): FunctionCaller<Field> = when {
isInsideClassCompanionObject() -> { isInsideClassCompanionObject() -> {
val klass = (descriptor.containingDeclaration as ClassDescriptor).toJavaClass()!! val klass = (descriptor.containingDeclaration as ClassDescriptor).toJavaClass()!!
if (isGetter) FunctionCaller.ClassCompanionFieldGetter(field, klass) if (isGetter)
else FunctionCaller.ClassCompanionFieldSetter(field, klass) if (isBound) FunctionCaller.BoundClassCompanionFieldGetter(field, klass)
else FunctionCaller.ClassCompanionFieldGetter(field, klass)
else
if (isBound) FunctionCaller.BoundClassCompanionFieldSetter(field, klass)
else FunctionCaller.ClassCompanionFieldSetter(field, klass)
} }
!Modifier.isStatic(field.modifiers) -> !Modifier.isStatic(field.modifiers) ->
if (isGetter) FunctionCaller.InstanceFieldGetter(field) if (isGetter)
else FunctionCaller.InstanceFieldSetter(field, isNotNullProperty()) if (isBound) FunctionCaller.BoundInstanceFieldGetter(field, property.boundReceiver)
else FunctionCaller.InstanceFieldGetter(field)
else
if (isBound) FunctionCaller.BoundInstanceFieldSetter(field, isNotNullProperty(), property.boundReceiver)
else FunctionCaller.InstanceFieldSetter(field, isNotNullProperty())
isJvmStaticProperty() -> isJvmStaticProperty() ->
if (isGetter) FunctionCaller.JvmStaticInObjectFieldGetter(field) if (isGetter)
else FunctionCaller.JvmStaticInObjectFieldSetter(field, isNotNullProperty()) if (isBound) FunctionCaller.BoundJvmStaticInObjectFieldGetter(field)
else FunctionCaller.JvmStaticInObjectFieldGetter(field)
else
if (isBound) FunctionCaller.BoundJvmStaticInObjectFieldSetter(field, isNotNullProperty())
else FunctionCaller.JvmStaticInObjectFieldSetter(field, isNotNullProperty())
else -> else ->
if (isGetter) FunctionCaller.StaticFieldGetter(field) if (isGetter) FunctionCaller.StaticFieldGetter(field)
else FunctionCaller.StaticFieldSetter(field, isNotNullProperty()) else FunctionCaller.StaticFieldSetter(field, isNotNullProperty())
@@ -203,9 +220,15 @@ private fun KPropertyImpl.Accessor<*, *>.computeCallerForAccessor(isGetter: Bool
when { when {
accessor == null -> computeFieldCaller(property.javaField!!) accessor == null -> computeFieldCaller(property.javaField!!)
!Modifier.isStatic(accessor.modifiers) -> FunctionCaller.InstanceMethod(accessor) !Modifier.isStatic(accessor.modifiers) ->
isJvmStaticProperty() -> FunctionCaller.JvmStaticInObject(accessor) if (isBound) FunctionCaller.BoundInstanceMethod(accessor, property.boundReceiver)
else -> FunctionCaller.StaticMethod(accessor) else FunctionCaller.InstanceMethod(accessor)
isJvmStaticProperty() ->
if (isBound) FunctionCaller.BoundJvmStaticInObject(accessor)
else FunctionCaller.JvmStaticInObject(accessor)
else ->
if (isBound) FunctionCaller.BoundStaticMethod(accessor, property.boundReceiver)
else FunctionCaller.StaticMethod(accessor)
} }
} }
is JavaField -> { is JavaField -> {
@@ -217,7 +240,8 @@ private fun KPropertyImpl.Accessor<*, *>.computeCallerForAccessor(isGetter: Bool
else jvmSignature.setterMethod ?: throw KotlinReflectionInternalError( else jvmSignature.setterMethod ?: throw KotlinReflectionInternalError(
"No source found for setter of Java method property: ${jvmSignature.getterMethod}" "No source found for setter of Java method property: ${jvmSignature.getterMethod}"
) )
FunctionCaller.InstanceMethod(method) if (isBound) FunctionCaller.BoundInstanceMethod(method, property.boundReceiver)
else FunctionCaller.InstanceMethod(method)
} }
} }
} }
@@ -1877,7 +1877,13 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
@TestMetadata("companionObjectReceiver.kt") @TestMetadata("companionObjectReceiver.kt")
public void testCompanionObjectReceiver() throws Exception { public void testCompanionObjectReceiver() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/companionObjectReceiver.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/companionObjectReceiver.kt");
doTest(fileName); try {
doTest(fileName);
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
} }
@TestMetadata("enumEntryMember.kt") @TestMetadata("enumEntryMember.kt")
@@ -1931,12 +1937,6 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
@TestMetadata("objectReceiver.kt") @TestMetadata("objectReceiver.kt")
public void testObjectReceiver() throws Exception { public void testObjectReceiver() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/objectReceiver.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/objectReceiver.kt");
doTest(fileName);
}
@TestMetadata("primitiveReceiver.kt")
public void testPrimitiveReceiver() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/primitiveReceiver.kt");
try { try {
doTest(fileName); doTest(fileName);
} }
@@ -1946,6 +1946,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
} }
@TestMetadata("primitiveReceiver.kt")
public void testPrimitiveReceiver() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/primitiveReceiver.kt");
doTest(fileName);
}
@TestMetadata("simpleFunction.kt") @TestMetadata("simpleFunction.kt")
public void testSimpleFunction() throws Exception { public void testSimpleFunction() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/simpleFunction.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/simpleFunction.kt");
@@ -14857,6 +14863,171 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
} }
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
} }
@TestMetadata("compiler/testData/codegen/box/reflection/call/bound")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Bound extends AbstractJsCodegenBoxTest {
public void testAllFilesPresentInBound() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/call/bound"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true);
}
@TestMetadata("companionObjectPropertyAccessors.kt")
public void testCompanionObjectPropertyAccessors() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/companionObjectPropertyAccessors.kt");
try {
doTest(fileName);
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
}
@TestMetadata("extensionFunction.kt")
public void testExtensionFunction() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/extensionFunction.kt");
try {
doTest(fileName);
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
}
@TestMetadata("extensionPropertyAccessors.kt")
public void testExtensionPropertyAccessors() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/extensionPropertyAccessors.kt");
try {
doTest(fileName);
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
}
@TestMetadata("innerClassConstructor.kt")
public void testInnerClassConstructor() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/innerClassConstructor.kt");
try {
doTest(fileName);
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
}
@TestMetadata("javaInstanceField.kt")
public void testJavaInstanceField() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/javaInstanceField.kt");
try {
doTest(fileName);
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
}
@TestMetadata("javaInstanceMethod.kt")
public void testJavaInstanceMethod() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/javaInstanceMethod.kt");
try {
doTest(fileName);
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
}
@TestMetadata("jvmStaticCompanionObjectPropertyAccessors.kt")
public void testJvmStaticCompanionObjectPropertyAccessors() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/jvmStaticCompanionObjectPropertyAccessors.kt");
try {
doTest(fileName);
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
}
@TestMetadata("jvmStaticObjectFunction.kt")
public void testJvmStaticObjectFunction() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/jvmStaticObjectFunction.kt");
try {
doTest(fileName);
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
}
@TestMetadata("jvmStaticObjectPropertyAccessors.kt")
public void testJvmStaticObjectPropertyAccessors() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/jvmStaticObjectPropertyAccessors.kt");
try {
doTest(fileName);
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
}
@TestMetadata("memberFunction.kt")
public void testMemberFunction() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/memberFunction.kt");
try {
doTest(fileName);
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
}
@TestMetadata("memberPropertyAccessors.kt")
public void testMemberPropertyAccessors() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/memberPropertyAccessors.kt");
try {
doTest(fileName);
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
}
@TestMetadata("objectFunction.kt")
public void testObjectFunction() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/objectFunction.kt");
try {
doTest(fileName);
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
}
@TestMetadata("objectPropertyAccessors.kt")
public void testObjectPropertyAccessors() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/call/bound/objectPropertyAccessors.kt");
try {
doTest(fileName);
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
}
}
} }
@TestMetadata("compiler/testData/codegen/box/reflection/callBy") @TestMetadata("compiler/testData/codegen/box/reflection/callBy")
@@ -14867,6 +15038,42 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/callBy"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true); KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/callBy"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true);
} }
@TestMetadata("boundExtensionFunction.kt")
public void testBoundExtensionFunction() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/callBy/boundExtensionFunction.kt");
try {
doTest(fileName);
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
}
@TestMetadata("boundExtensionPropertyAcessor.kt")
public void testBoundExtensionPropertyAcessor() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/callBy/boundExtensionPropertyAcessor.kt");
try {
doTest(fileName);
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
}
@TestMetadata("boundJvmStaticInObject.kt")
public void testBoundJvmStaticInObject() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/callBy/boundJvmStaticInObject.kt");
try {
doTest(fileName);
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
}
@TestMetadata("companionObject.kt") @TestMetadata("companionObject.kt")
public void testCompanionObject() throws Exception { public void testCompanionObject() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/callBy/companionObject.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/callBy/companionObject.kt");
@@ -17009,6 +17216,42 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/parameters"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true); KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/parameters"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true);
} }
@TestMetadata("boundInnerClassConstructor.kt")
public void testBoundInnerClassConstructor() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/parameters/boundInnerClassConstructor.kt");
try {
doTest(fileName);
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
}
@TestMetadata("boundObjectMemberReferences.kt")
public void testBoundObjectMemberReferences() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/parameters/boundObjectMemberReferences.kt");
try {
doTest(fileName);
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
}
@TestMetadata("boundReferences.kt")
public void testBoundReferences() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/parameters/boundReferences.kt");
try {
doTest(fileName);
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
}
@TestMetadata("findParameterByName.kt") @TestMetadata("findParameterByName.kt")
public void testFindParameterByName() throws Exception { public void testFindParameterByName() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/parameters/findParameterByName.kt"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/parameters/findParameterByName.kt");