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:
Denis Zharkov
2015-05-12 10:45:06 +03:00
parent e078eaf15b
commit e98b9ea84e
9 changed files with 180 additions and 3 deletions
@@ -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();
}
}
@@ -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"
}
@@ -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/");
@@ -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")