| import org.checkerframework.checker.guieffect.qual.AlwaysSafe; |
| import org.checkerframework.checker.guieffect.qual.PolyUI; |
| import org.checkerframework.checker.guieffect.qual.PolyUIEffect; |
| import org.checkerframework.checker.guieffect.qual.PolyUIType; |
| import org.checkerframework.checker.guieffect.qual.UI; |
| import org.checkerframework.checker.guieffect.qual.UIEffect; |
| |
| public class Java8Lambdas { |
| |
| private interface SafeFunctionalInterface<T> { |
| public void executeAlwaysSafe(T arg); |
| } |
| |
| private interface UIFunctionalInterface<T> { |
| @UIEffect |
| public void executeUI(T arg); |
| } |
| |
| @PolyUIType |
| private interface PolymorphicFunctionalInterface<T> { |
| @PolyUIEffect |
| public void executePolymorphic(T arg); |
| } |
| |
| private static class LambdaRunner { |
| private final UIElement arg; |
| |
| public LambdaRunner(UIElement arg) { |
| this.arg = arg; |
| } |
| |
| public void doSafe(SafeFunctionalInterface<UIElement> func) { |
| func.executeAlwaysSafe(this.arg); |
| } |
| |
| @UIEffect |
| public void doUI(UIFunctionalInterface<UIElement> func) { |
| func.executeUI(this.arg); |
| } |
| |
| // Needs to be @UIEffect, because the functional interface method is @UIEffect |
| public void unsafeDoUI(UIFunctionalInterface<UIElement> func) { |
| // :: error: (call.ui) |
| func.executeUI(this.arg); |
| } |
| |
| public void doEither(@PolyUI PolymorphicFunctionalInterface<UIElement> func) { |
| // In a real program some intelligent dispatch could be done here to avoid running on UI |
| // thread unless needed. |
| arg.runOnUIThread( |
| new IAsyncUITask() { |
| final UIElement e2 = arg; |
| |
| @Override |
| public void doStuff() { // should inherit UI effect |
| func.executePolymorphic(e2); // should be okay |
| } |
| }); |
| } |
| |
| public void doUISafely(@UI PolymorphicFunctionalInterface<UIElement> func) { |
| // In a real program some intelligent dispatch could be done here to avoid running on UI |
| // thread unless needed. |
| arg.runOnUIThread( |
| new IAsyncUITask() { |
| final UIElement e2 = arg; |
| |
| @Override |
| public void doStuff() { // should inherit UI effect |
| func.executePolymorphic(e2); // should be okay |
| } |
| }); |
| } |
| } |
| |
| @PolyUIType |
| private static class PolymorphicLambdaRunner { |
| private final UIElement arg; |
| |
| public PolymorphicLambdaRunner(UIElement arg) { |
| this.arg = arg; |
| } |
| |
| @PolyUIEffect |
| public void doEither(@PolyUI PolymorphicFunctionalInterface<UIElement> func) { |
| func.executePolymorphic(this.arg); |
| } |
| } |
| |
| public static void safeContextTestCases(UIElement elem) { |
| LambdaRunner runner = new LambdaRunner(elem); |
| runner.doSafe(e -> e.repaint()); |
| // :: error: (call.ui) |
| runner.doSafe(e -> e.dangerous()); // Not allowed in doSafe |
| // :: error: (call.ui) |
| runner.doUI(e -> e.repaint()); // Not allowed in safe context |
| // :: error: (call.ui) |
| runner.doUI(e -> e.dangerous()); // Not allowed in safe context |
| runner.doEither(e -> e.repaint()); |
| runner.doEither(e -> e.dangerous()); |
| runner.doUISafely(e -> e.dangerous()); |
| @AlwaysSafe PolymorphicLambdaRunner safePolymorphicLambdaRunner = new PolymorphicLambdaRunner(elem); |
| safePolymorphicLambdaRunner.doEither(e -> e.repaint()); |
| // This next two are ok for this patch since the behavior is the same (no report) for |
| // lambdas as for annon classes. However, shouldn't this be (argument) |
| // just because safePolymorphicLambdaRunner is not an @UI PolymorphicLambdaRunner ? Or, |
| // failing that (call.ui) since doEither is @PolyUIEffect ? |
| safePolymorphicLambdaRunner.doEither(e -> e.dangerous()); |
| safePolymorphicLambdaRunner.doEither( |
| new @UI PolymorphicFunctionalInterface<UIElement>() { |
| public void executePolymorphic(UIElement arg) { |
| arg.dangerous(); |
| } |
| }); |
| @UI PolymorphicLambdaRunner uiPolymorphicLambdaRunner = new @UI PolymorphicLambdaRunner(elem); |
| // :: error: (call.ui) |
| uiPolymorphicLambdaRunner.doEither( |
| e -> e.repaint()); // Safe at runtime, but not by the type system! |
| // :: error: (call.ui) |
| uiPolymorphicLambdaRunner.doEither(e -> e.dangerous()); |
| PolymorphicFunctionalInterface<UIElement> func1 = e -> e.repaint(); |
| // :: error: (assignment) |
| PolymorphicFunctionalInterface<UIElement> func2 = e -> e.dangerous(); // Incompatible types! |
| PolymorphicFunctionalInterface<UIElement> func2p = |
| // :: error: (assignment) |
| (new @UI PolymorphicFunctionalInterface<UIElement>() { |
| public void executePolymorphic(UIElement arg) { |
| arg.dangerous(); |
| } |
| }); |
| @UI PolymorphicFunctionalInterface<UIElement> func3 = e -> e.dangerous(); |
| safePolymorphicLambdaRunner.doEither(func1); |
| safePolymorphicLambdaRunner.doEither(func2); |
| // :: error: (call.ui) |
| uiPolymorphicLambdaRunner.doEither(func1); |
| // :: error: (call.ui) |
| uiPolymorphicLambdaRunner.doEither(func2); |
| // :: error: (call.ui) |
| uiPolymorphicLambdaRunner.doEither(func3); |
| } |
| |
| @UIEffect |
| public static void uiContextTestCases(UIElement elem) { |
| LambdaRunner runner = new LambdaRunner(elem); |
| // :: error: (call.ui) |
| runner.doSafe(e -> e.dangerous()); |
| runner.doUI(e -> e.repaint()); |
| runner.doUI(e -> e.dangerous()); |
| PolymorphicLambdaRunner safePolymorphicLambdaRunner = new PolymorphicLambdaRunner(elem); |
| // No error, why? :: error: (argument) |
| safePolymorphicLambdaRunner.doEither(e -> e.dangerous()); |
| @UI PolymorphicLambdaRunner uiPolymorphicLambdaRunner = new @UI PolymorphicLambdaRunner(elem); |
| uiPolymorphicLambdaRunner.doEither(e -> e.dangerous()); |
| } |
| |
| public @UI PolymorphicFunctionalInterface<UIElement> returnLambdasTest1() { |
| return e -> e.dangerous(); |
| } |
| |
| // This should be an error without an @UI annotation on the return type. No? |
| public PolymorphicFunctionalInterface<UIElement> returnLambdasTest2() { |
| // :: error: (return) |
| return e -> { |
| e.dangerous(); |
| }; |
| } |
| |
| // Just to check |
| public PolymorphicFunctionalInterface<UIElement> returnLambdasTest3() { |
| // :: error: (return) |
| return (new @UI PolymorphicFunctionalInterface<UIElement>() { |
| public void executePolymorphic(UIElement arg) { |
| arg.dangerous(); |
| } |
| }); |
| } |
| } |