Skip to content

Commit dd0fe71

Browse files
authored
JSpecify: view type as super in generic method inference (#1177)
1 parent 2c8049c commit dd0fe71

File tree

3 files changed

+35
-10
lines changed

3 files changed

+35
-10
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,7 @@ public void checkTypeParameterNullnessForAssignability(
454454
// generic method call with no explicit generic arguments
455455
// update inferred type arguments based on the assignment context
456456
InferSubstitutionViaAssignmentContextVisitor inferVisitor =
457-
new InferSubstitutionViaAssignmentContextVisitor(config);
457+
new InferSubstitutionViaAssignmentContextVisitor(state, config);
458458
Type returnType = methodSymbol.getReturnType();
459459
returnType.accept(inferVisitor, lhsType);
460460

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

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.uber.nullaway.generics;
22

3+
import com.google.common.base.Verify;
4+
import com.google.errorprone.VisitorState;
35
import com.sun.tools.javac.code.Type;
46
import com.sun.tools.javac.code.Types;
57
import com.uber.nullaway.Config;
@@ -15,24 +17,29 @@
1517
public class InferSubstitutionViaAssignmentContextVisitor
1618
extends Types.DefaultTypeVisitor<Void, Type> {
1719

20+
private final VisitorState state;
1821
private final Config config;
1922
private final Map<TypeVariable, Type> inferredSubstitution = new LinkedHashMap<>();
2023

21-
InferSubstitutionViaAssignmentContextVisitor(Config config) {
24+
InferSubstitutionViaAssignmentContextVisitor(VisitorState state, Config config) {
25+
this.state = state;
2226
this.config = config;
2327
}
2428

2529
@Override
2630
public Void visitClassType(Type.ClassType rhsType, Type lhsType) {
27-
com.sun.tools.javac.util.List<Type> rhsTypeArguments = rhsType.getTypeArguments();
31+
Type rhsTypeAsSuper = state.getTypes().asSuper(rhsType, lhsType.tsym);
32+
if (rhsTypeAsSuper == null || rhsTypeAsSuper.isRaw() || lhsType.isRaw()) {
33+
return null;
34+
}
35+
com.sun.tools.javac.util.List<Type> rhsTypeArguments = rhsTypeAsSuper.getTypeArguments();
2836
com.sun.tools.javac.util.List<Type> lhsTypeArguments = lhsType.getTypeArguments();
29-
// recursively visit the type arguments
30-
if (!rhsTypeArguments.isEmpty() && !lhsTypeArguments.isEmpty()) {
31-
for (int i = 0; i < rhsTypeArguments.size(); i++) {
32-
Type rhsTypeArg = rhsTypeArguments.get(i);
33-
Type lhsTypeArg = lhsTypeArguments.get(i);
34-
rhsTypeArg.accept(this, lhsTypeArg);
35-
}
37+
int numTypeArgs = rhsTypeArguments.size();
38+
Verify.verify(numTypeArgs == lhsTypeArguments.size());
39+
for (int i = 0; i < numTypeArgs; i++) {
40+
Type rhsTypeArg = rhsTypeArguments.get(i);
41+
Type lhsTypeArg = lhsTypeArguments.get(i);
42+
rhsTypeArg.accept(this, lhsTypeArg);
3643
}
3744
return null;
3845
}

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,24 @@ public void nullableAnnotOnMethodTypeVarUse() {
488488
.doTest();
489489
}
490490

491+
@Test
492+
public void issue1176() {
493+
makeHelper()
494+
.addSourceLines(
495+
"Foo.java",
496+
"package com.uber;",
497+
"import java.util.Set;",
498+
"import java.util.concurrent.CompletableFuture;",
499+
"import java.util.concurrent.ConcurrentHashMap;",
500+
"class Foo {",
501+
" final Set<CompletableFuture<?>> f;",
502+
" public Foo() {",
503+
" f = ConcurrentHashMap.newKeySet();",
504+
" }",
505+
"}")
506+
.doTest();
507+
}
508+
491509
private CompilationTestHelper makeHelper() {
492510
return makeTestHelperWithArgs(
493511
Arrays.asList(

0 commit comments

Comments
 (0)