-
Notifications
You must be signed in to change notification settings - Fork 291
/
FunctionalInterfaceNullabilityTests.java
155 lines (150 loc) · 7.41 KB
/
FunctionalInterfaceNullabilityTests.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package com.uber.nullaway;
import java.util.Arrays;
import org.junit.Test;
public class FunctionalInterfaceNullabilityTests extends NullAwayTestsBase {
@Test
public void multipleTypeParametersInstantiation() {
defaultCompilationHelper
.addSourceLines(
"NullableFunction.java",
"package com.uber.unannotated;", // As if a third-party lib, since override is invalid
"import javax.annotation.Nullable;",
"import java.util.function.Function;",
"@FunctionalInterface",
"public interface NullableFunction<F, T> extends Function<F, T> {",
" @Override",
" @Nullable",
" T apply(@Nullable F input);",
"}")
.addSourceLines(
"Test.java",
"package com.uber;",
"import javax.annotation.Nullable;",
"import java.util.function.Function;",
"import com.uber.unannotated.NullableFunction;",
"class Test {",
" private static void takesNullableFunction(NullableFunction<String, String> nf) { }",
" private static void takesNonNullableFunction(Function<String, String> f) { }",
" private static void passesNullableFunction() {",
" takesNullableFunction(s -> { return null; });",
" }",
" private static void passesNullableFunctionToNonNull() {",
" takesNonNullableFunction(s -> { return null; });",
" }",
"}")
.addSourceLines(
"TestGuava.java",
"package com.uber;",
"import javax.annotation.Nullable;",
"import com.google.common.base.Function;",
"import com.uber.unannotated.NullableFunction;",
"class TestGuava {",
" private static void takesNullableFunction(NullableFunction<String, String> nf) { }",
" private static void takesNonNullableFunction(Function<String, String> f) { }",
" private static void passesNullableFunction() {",
" takesNullableFunction(s -> { return null; });",
" }",
" private static void passesNullableFunctionToNonNull() {",
" // BUG: Diagnostic contains: returning @Nullable expression",
" takesNonNullableFunction(s -> { return null; });",
" }",
"}")
.doTest();
}
@Test
public void futuresFunctionLambdas() {
// See FluentFutureHandler
defaultCompilationHelper
.addSourceLines(
"TestGuava.java",
"package com.uber;",
"import org.jspecify.annotations.Nullable;",
"import com.google.common.base.Function;",
"import com.google.common.util.concurrent.FluentFuture;",
"import com.google.common.util.concurrent.Futures;",
"import com.google.common.util.concurrent.ListenableFuture;",
"import java.util.concurrent.Executor;",
"class TestGuava {",
" private static ListenableFuture<@Nullable String> fluentFutureCatching(Executor executor) {",
" return FluentFuture",
" .from(Futures.immediateFuture(\"hi\"))",
" .catching(Throwable.class, e -> { return null; }, executor);",
" }",
" private static ListenableFuture<@Nullable String> fluentFutureCatchingAsync(Executor executor) {",
" return FluentFuture",
" .from(Futures.immediateFuture(\"hi\"))",
" .catchingAsync(Throwable.class, e -> { return null; }, executor);",
" }",
" private static ListenableFuture<@Nullable String> fluentFutureTransform(Executor executor) {",
" return FluentFuture",
" .from(Futures.immediateFuture(\"hi\"))",
" .transform(s -> { return null; }, executor);",
" }",
" private static ListenableFuture<@Nullable String> fluentFutureTransformAsync(Executor executor) {",
" return FluentFuture",
" .from(Futures.immediateFuture(\"hi\"))",
" .transformAsync(s -> { return null; }, executor);",
" }",
" private static ListenableFuture<String> fluentFutureTransformNoNull(Executor executor) {",
" return FluentFuture",
" .from(Futures.immediateFuture(\"hi\"))",
" // Should be an error when we have full generics support, false-negative for now",
" .transform(s -> { return s; }, executor);",
" }",
" private static ListenableFuture<String> fluentFutureUnsafe(Executor executor) {",
" return FluentFuture",
" .from(Futures.immediateFuture(\"hi\"))",
" // Should be an error when we have full generics support, false-negative for now",
" .transform(s -> { return null; }, executor);",
" }",
" private static ListenableFuture<@Nullable String> futuresTransform(Executor executor) {",
" return Futures",
" .transform(Futures.immediateFuture(\"hi\"), s -> { return null; }, executor);",
" }",
"}")
.doTest();
}
@Test
public void extraFuturesClassesLambda() {
makeTestHelperWithArgs(
Arrays.asList(
"-d",
temporaryFolder.getRoot().getAbsolutePath(),
"-XepOpt:NullAway:AnnotatedPackages=com.uber",
"-XepOpt:NullAway:ExtraFuturesClasses=com.uber.extra.MyFutures"))
.addSourceLines(
"MyFutures.java",
"package com.uber.extra;",
"import com.google.common.base.Function;",
"import com.google.common.util.concurrent.Futures;",
"import com.google.common.util.concurrent.ListenableFuture;",
"import java.util.concurrent.Executor;",
"public class MyFutures {",
" public static <V> ListenableFuture<V> transform(ListenableFuture<V> future, Function<V, V> function, Executor executor) {",
" return Futures.transform(future, function, executor);",
" }",
"}")
.addSourceLines(
"TestMyFutures.java",
"package com.uber;",
"import org.jspecify.annotations.Nullable;",
"import com.google.common.base.Function;",
"import com.google.common.util.concurrent.FluentFuture;",
"import com.google.common.util.concurrent.Futures;",
"import com.google.common.util.concurrent.ListenableFuture;",
"import java.util.concurrent.Executor;",
"class TestGuava {",
" private static void takeFn(Function<String, String> f) { }",
" private static void passToAnnotatedFunction() {",
" // Normally we get an error since Guava Functions are modeled to have a @NonNull return",
" // BUG: Diagnostic contains: returning @Nullable expression from method",
" takeFn(s -> { return null; });",
" }",
" private static void passToExtraFuturesClass(ListenableFuture<String> f, Executor e) {",
" // here we do not expect an error since MyFutures is in the extra futures classes",
" com.uber.extra.MyFutures.transform(f, u -> { return null; }, e);",
" }",
"}")
.doTest();
}
}