Skip to content

Commit 8a30816

Browse files
authored
Merge branch 'master' into infer-generics
2 parents 9f6c91b + f064222 commit 8a30816

File tree

4 files changed

+102
-4
lines changed

4 files changed

+102
-4
lines changed

nullaway/src/main/java/com/uber/nullaway/generics/CheckIdenticalNullabilityVisitor.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,11 @@ public Boolean visitClassType(Type.ClassType lhsType, Type rhsType) {
5555
for (int i = 0; i < lhsTypeArguments.size(); i++) {
5656
Type lhsTypeArgument = lhsTypeArguments.get(i);
5757
Type rhsTypeArgument = rhsTypeArguments.get(i);
58+
if (lhsTypeArgument.getKind().equals(TypeKind.WILDCARD)
59+
|| rhsTypeArgument.getKind().equals(TypeKind.WILDCARD)) {
60+
// TODO Handle wildcard types
61+
continue;
62+
}
5863
boolean isLHSNullableAnnotated = GenericsChecks.isNullableAnnotated(lhsTypeArgument, state);
5964
boolean isRHSNullableAnnotated = GenericsChecks.isNullableAnnotated(rhsTypeArgument, state);
6065
if (isLHSNullableAnnotated != isRHSNullableAnnotated) {

nullaway/src/main/java/com/uber/nullaway/generics/GenericsChecks.java

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import com.sun.source.tree.NewArrayTree;
2020
import com.sun.source.tree.NewClassTree;
2121
import com.sun.source.tree.ParameterizedTypeTree;
22+
import com.sun.source.tree.ParenthesizedTree;
2223
import com.sun.source.tree.Tree;
2324
import com.sun.source.tree.VariableTree;
2425
import com.sun.source.util.TreePath;
@@ -162,12 +163,21 @@ private static boolean[] getTypeParamsWithNullableUpperBound(
162163
*/
163164
public static void checkGenericMethodCallTypeArguments(
164165
Tree tree, VisitorState state, NullAway analysis, Config config, Handler handler) {
165-
List<? extends Tree> typeArguments = ((MethodInvocationTree) tree).getTypeArguments();
166+
List<? extends Tree> typeArguments;
167+
switch (tree.getKind()) {
168+
case METHOD_INVOCATION:
169+
typeArguments = ((MethodInvocationTree) tree).getTypeArguments();
170+
break;
171+
case NEW_CLASS:
172+
typeArguments = ((NewClassTree) tree).getTypeArguments();
173+
break;
174+
default:
175+
throw new RuntimeException("Unexpected tree kind: " + tree.getKind());
176+
}
166177
if (typeArguments.isEmpty()) {
167178
return;
168179
}
169180
// get Nullable annotated type arguments
170-
MethodInvocationTree methodTree = (MethodInvocationTree) tree;
171181
Map<Integer, Tree> nullableTypeArguments = new HashMap<>();
172182
for (int i = 0; i < typeArguments.size(); i++) {
173183
Tree curTypeArg = typeArguments.get(i);
@@ -183,7 +193,8 @@ public static void checkGenericMethodCallTypeArguments(
183193
}
184194
}
185195
}
186-
Symbol.MethodSymbol methodSymbol = ASTHelpers.getSymbol(methodTree);
196+
Symbol.MethodSymbol methodSymbol =
197+
castToNonNull((Symbol.MethodSymbol) ASTHelpers.getSymbol(tree));
187198

188199
// check if type variables are allowed to be Nullable
189200
Type baseType = methodSymbol.asType();
@@ -643,7 +654,12 @@ public static void checkTypeParameterNullnessForConditionalExpression(
643654
ConditionalExpressionTree tree, VisitorState state) {
644655
// hack: sometimes array nullability doesn't get computed correctly for a conditional expression
645656
// on the RHS of an assignment. So, look at the type of the assignment tree.
646-
Tree parent = state.getPath().getParentPath().getLeaf();
657+
TreePath parentPath = state.getPath().getParentPath();
658+
Tree parent = parentPath.getLeaf();
659+
while (parent instanceof ParenthesizedTree) {
660+
parentPath = parentPath.getParentPath();
661+
parent = parentPath.getLeaf();
662+
}
647663
if (parent instanceof AssignmentTree || parent instanceof VariableTree) {
648664
return getTreeType(parent, state);
649665
}

nullaway/src/test/java/com/uber/nullaway/jspecify/GenericMethodTests.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,32 @@ public void issue1035() {
264264
.doTest();
265265
}
266266

267+
@Test
268+
public void issue1138() {
269+
makeHelper()
270+
.addSourceLines(
271+
"Test.java",
272+
"package com.uber;",
273+
"import org.jspecify.annotations.NullMarked;",
274+
"import org.jspecify.annotations.Nullable;",
275+
"@NullMarked",
276+
"class Foo {",
277+
" <T> Foo(T source) {",
278+
" }",
279+
" static <T> Foo createNoTypeArgs(T in) {",
280+
" return new Foo(in);",
281+
" }",
282+
" static Foo createWithTypeArgNegative(String s) {",
283+
" return new <String>Foo(s);",
284+
" }",
285+
" static Foo createWithTypeArgPositive() {",
286+
" // BUG: Diagnostic contains: Type argument cannot be @Nullable, as method <T>Foo(T)'s type variable T is not @Nullable",
287+
" return new <@Nullable String>Foo(null);",
288+
" }",
289+
"}")
290+
.doTest();
291+
}
292+
267293
private CompilationTestHelper makeHelper() {
268294
return makeTestHelperWithArgs(
269295
Arrays.asList(

nullaway/src/test/java/com/uber/nullaway/jspecify/GenericsTests.java

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2045,6 +2045,21 @@ public void issue1093() {
20452045
.doTest();
20462046
}
20472047

2048+
@Test
2049+
public void issue1127() {
2050+
makeHelper()
2051+
.addSourceLines(
2052+
"Main.java",
2053+
"package com.uber;",
2054+
"import org.jspecify.annotations.Nullable;",
2055+
"public class Main {",
2056+
" void arrayAssign(boolean b, @Nullable String @Nullable [] vals) {",
2057+
" @Nullable String[] arr = (b ? vals : null);",
2058+
" }",
2059+
"}")
2060+
.doTest();
2061+
}
2062+
20482063
@Test
20492064
public void nullUnmarkedGenericField() {
20502065
makeHelper()
@@ -2069,6 +2084,42 @@ public void nullUnmarkedGenericField() {
20692084
.doTest();
20702085
}
20712086

2087+
@Test
2088+
public void issue1126() {
2089+
makeHelper()
2090+
.addSourceLines(
2091+
"Test.java",
2092+
"package com.uber;",
2093+
"import org.jspecify.annotations.Nullable;",
2094+
"import java.util.function.Supplier;",
2095+
"public class Test {",
2096+
" static class K<T extends @Nullable Object> {}",
2097+
" void foo(K<@Nullable Object> k) {",
2098+
" K<? extends @Nullable Object> k2 = k;",
2099+
" Supplier<? extends @Nullable Object> s = () -> null;",
2100+
" }",
2101+
"}")
2102+
.addSourceLines(
2103+
"Test2.java",
2104+
"package com.uber;",
2105+
"import java.util.HashMap;",
2106+
"import java.util.Map;",
2107+
"import org.jspecify.annotations.Nullable;",
2108+
"import org.jetbrains.annotations.Contract;",
2109+
"public class Test2 {",
2110+
" @Contract(\"null -> true\")",
2111+
" public static boolean isEmpty(@Nullable Map<?, ? extends @Nullable Object> map) {",
2112+
" return (map == null || map.isEmpty());",
2113+
" }",
2114+
" static void foo() {",
2115+
" Map<String, @Nullable Object> variables = new HashMap<>();",
2116+
" if (isEmpty(variables)) { /* do nothing */ }",
2117+
" variables.toString();",
2118+
" }",
2119+
"}")
2120+
.doTest();
2121+
}
2122+
20722123
private CompilationTestHelper makeHelper() {
20732124
return makeTestHelperWithArgs(
20742125
Arrays.asList(

0 commit comments

Comments
 (0)