Save annotations of lambda on SAM's method
Also add tests checking that annotations on 'invoke' methods of common lambdas are saved properly #KT-6932 Fixed
This commit is contained in:
@@ -2209,17 +2209,22 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
|
||||
@Nullable
|
||||
private StackValue genSamInterfaceValue(
|
||||
@NotNull final JetExpression expression,
|
||||
@NotNull JetExpression probablyParenthesizedExpression,
|
||||
@NotNull final JetVisitor<StackValue, StackValue> visitor
|
||||
) {
|
||||
final SamType samType = bindingContext.get(SAM_VALUE, expression);
|
||||
if (samType == null) return null;
|
||||
final JetExpression expression = JetPsiUtil.deparenthesize(probablyParenthesizedExpression);
|
||||
final SamType samType = bindingContext.get(SAM_VALUE, probablyParenthesizedExpression);
|
||||
if (samType == null || expression == null) return null;
|
||||
|
||||
if (expression instanceof JetFunctionLiteralExpression) {
|
||||
return genClosure(((JetFunctionLiteralExpression) expression).getFunctionLiteral(), samType,
|
||||
KotlinSyntheticClass.Kind.SAM_LAMBDA);
|
||||
}
|
||||
|
||||
if (expression instanceof JetNamedFunction) {
|
||||
return genClosure((JetNamedFunction) expression, samType, KotlinSyntheticClass.Kind.SAM_LAMBDA);
|
||||
}
|
||||
|
||||
final Type asmType =
|
||||
state.getSamWrapperClasses().getSamWrapperClass(samType, expression.getContainingJetFile(), getParentCodegen());
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import java.lang.Runnable;
|
||||
|
||||
class Test {
|
||||
public static Class<?> apply(Runnable x) {
|
||||
return x.getClass();
|
||||
}
|
||||
|
||||
public static interface ABC {
|
||||
void apply(String x1, String x2);
|
||||
}
|
||||
|
||||
public static Class<?> applyABC(ABC x) {
|
||||
return x.getClass();
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
import java.lang.annotation.*
|
||||
import java.lang.reflect.Method
|
||||
import kotlin.reflect.jvm.java
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
Retention(RetentionPolicy.RUNTIME)
|
||||
annotation class Ann(val x: String)
|
||||
|
||||
fun testMethod(method: Method, name: String) {
|
||||
assertEquals("OK", method.getAnnotation(javaClass<Ann>()).x, "On method of test named `$name`")
|
||||
|
||||
for ((index, annotations) in method.getParameterAnnotations().withIndex()) {
|
||||
val ann = annotations.filterIsInstance<Ann>().single()
|
||||
assertEquals("OK$index", ann.x, "On parameter $index of test named `$name`")
|
||||
}
|
||||
}
|
||||
|
||||
fun testClass(clazz: Class<*>, name: String) {
|
||||
val invokes = clazz.getDeclaredMethods().single() { !it.isBridge() }
|
||||
testMethod(invokes, name)
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
testClass(Test.apply(@Ann("OK") fun(){}), "1")
|
||||
|
||||
testClass(Test.applyABC(@Ann("OK") fun(@Ann("OK0") x: String, @Ann("OK1") y: String){}), "2")
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import java.lang.Runnable;
|
||||
|
||||
class Test {
|
||||
public static Class<?> apply(Runnable x) {
|
||||
return x.getClass();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import java.lang.annotation.*
|
||||
import java.lang.reflect.Method
|
||||
import kotlin.reflect.jvm.java
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
Retention(RetentionPolicy.RUNTIME)
|
||||
annotation class Ann(val x: String)
|
||||
|
||||
fun testMethod(method: Method, name: String) {
|
||||
assertEquals("OK", method.getAnnotation(javaClass<Ann>()).x, "On method of test named `$name`")
|
||||
|
||||
for ((index, annotations) in method.getParameterAnnotations().withIndex()) {
|
||||
val ann = annotations.filterIsInstance<Ann>().single()
|
||||
assertEquals("OK$index", ann.x, "On parameter $index of test named `$name`")
|
||||
}
|
||||
}
|
||||
|
||||
fun testClass(clazz: Class<*>, name: String) {
|
||||
val invokes = clazz.getDeclaredMethods().single() { !it.isBridge() }
|
||||
testMethod(invokes, name)
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
testClass(Test.apply(@Ann("OK") {}), "1")
|
||||
testClass(Test.apply @Ann("OK") {}, "2")
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import java.lang.annotation.*
|
||||
import java.lang.reflect.Method
|
||||
import kotlin.reflect.jvm.java
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
Retention(RetentionPolicy.RUNTIME)
|
||||
annotation class Ann(val x: String)
|
||||
|
||||
fun foo0(block: () -> Unit) = block.javaClass
|
||||
fun foo1(block: (String) -> Unit) = block.javaClass
|
||||
|
||||
fun testMethod(method: Method, name: String) {
|
||||
assertEquals("OK", method.getAnnotation(javaClass<Ann>()).x, "On method of test named `$name`")
|
||||
|
||||
for ((index, annotations) in method.getParameterAnnotations().withIndex()) {
|
||||
val ann = annotations.filterIsInstance<Ann>().single()
|
||||
assertEquals("OK$index", ann.x, "On parameter $index of test named `$name`")
|
||||
}
|
||||
}
|
||||
|
||||
fun testClass(clazz: Class<*>, name: String) {
|
||||
val invokes = clazz.getDeclaredMethods().single() { !it.isBridge() }
|
||||
testMethod(invokes, name)
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
testClass(foo0( @Ann("OK") fun() {} ), "1")
|
||||
testClass(foo1( @Ann("OK") fun(@Ann("OK0") x: String) {} ), "2")
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import java.lang.annotation.*
|
||||
import java.lang.reflect.Method
|
||||
import kotlin.reflect.jvm.java
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
Retention(RetentionPolicy.RUNTIME)
|
||||
annotation class Ann(val x: String)
|
||||
|
||||
fun foo0(block: () -> Unit) = block.javaClass
|
||||
|
||||
fun testMethod(method: Method, name: String) {
|
||||
assertEquals("OK", method.getAnnotation(javaClass<Ann>()).x, "On method of test named `$name`")
|
||||
|
||||
for ((index, annotations) in method.getParameterAnnotations().withIndex()) {
|
||||
val ann = annotations.filterIsInstance<Ann>().single()
|
||||
assertEquals("OK$index", ann.x, "On parameter $index of test named `$name`")
|
||||
}
|
||||
}
|
||||
|
||||
fun testClass(clazz: Class<*>, name: String) {
|
||||
val invokes = clazz.getDeclaredMethods().single() { !it.isBridge() }
|
||||
testMethod(invokes, name)
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
testClass(foo0([Ann("OK")] { }), "1")
|
||||
testClass(foo0( @Ann("OK") { }), "2")
|
||||
|
||||
testClass(foo0() @Ann("OK") { }, "3")
|
||||
return "OK"
|
||||
}
|
||||
+12
@@ -35,6 +35,18 @@ public class BlackBoxWithJavaCodegenTestGenerated extends AbstractBlackBoxCodege
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxWithJava"), Pattern.compile("^([^\\.]+)$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("annotatedSamFunExpression")
|
||||
public void testAnnotatedSamFunExpression() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/annotatedSamFunExpression/");
|
||||
doTestWithJava(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("annotatedSamLambda")
|
||||
public void testAnnotatedSamLambda() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/annotatedSamLambda/");
|
||||
doTestWithJava(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("classObjectAccessor")
|
||||
public void testClassObjectAccessor() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/classObjectAccessor/");
|
||||
|
||||
+21
@@ -102,6 +102,27 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/annotations/varargInAnnotationParameter.kt");
|
||||
doTestWithStdlib(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/boxWithStdlib/annotations/annotatedLambda")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class AnnotatedLambda extends AbstractBlackBoxCodegenTest {
|
||||
public void testAllFilesPresentInAnnotatedLambda() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxWithStdlib/annotations/annotatedLambda"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("funExpression.kt")
|
||||
public void testFunExpression() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/annotations/annotatedLambda/funExpression.kt");
|
||||
doTestWithStdlib(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("lambda.kt")
|
||||
public void testLambda() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/annotations/annotatedLambda/lambda.kt");
|
||||
doTestWithStdlib(fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/boxWithStdlib/arrays")
|
||||
|
||||
Reference in New Issue
Block a user