Skip to content

Commit e7623f7

Browse files
akulk022msridhar
andauthored
JSpecify: handle incorrect method parameter nullability for method reference (#845)
We now report an error for the following test case: ```java class Test { interface A<T1 extends @nullable Object> { String function(T1 o); } static String foo(Object o) { return o.toString(); } static void testPositive() { // we now report an error here, as foo's parameter need to be @nullable A<@nullable Object> p = Test::foo; } static void testNegative() { A<Object> p = Test::foo; } } ``` --------- Co-authored-by: Manu Sridharan <msridhar@gmail.com>
1 parent 2d2b829 commit e7623f7

File tree

3 files changed

+29
-19
lines changed

3 files changed

+29
-19
lines changed

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -879,11 +879,6 @@ public static Nullness getGenericMethodParameterNullness(
879879
VisitorState state,
880880
Config config) {
881881
Type enclosingType = getTypeForSymbol(enclosingSymbol, state);
882-
if (enclosingType == null) {
883-
// we have no additional information from generics, so return NONNULL (presence of a @Nullable
884-
// annotation should have been handled by the caller)
885-
return Nullness.NONNULL;
886-
}
887882
return getGenericMethodParameterNullness(parameterIndex, method, enclosingType, state, config);
888883
}
889884

@@ -904,9 +899,14 @@ public static Nullness getGenericMethodParameterNullness(
904899
public static Nullness getGenericMethodParameterNullness(
905900
int parameterIndex,
906901
Symbol.MethodSymbol method,
907-
Type enclosingType,
902+
@Nullable Type enclosingType,
908903
VisitorState state,
909904
Config config) {
905+
if (enclosingType == null) {
906+
// we have no additional information from generics, so return NONNULL (presence of a top-level
907+
// @Nullable annotation is handled elsewhere)
908+
return Nullness.NONNULL;
909+
}
910910
Type methodType = state.getTypes().memberType(enclosingType, method);
911911
Type paramType = methodType.getParameterTypes().get(parameterIndex);
912912
return getTypeNullness(paramType, config);

nullaway/src/main/java/com/uber/nullaway/NullAway.java

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -731,17 +731,28 @@ private Description checkParamOverriding(
731731
// -XepOpt:NullAway:AcknowledgeRestrictiveAnnotations flag and its handler).
732732
if (isOverriddenMethodAnnotated) {
733733
for (int i = 0; i < superParamSymbols.size(); i++) {
734-
overriddenMethodArgNullnessMap[i] =
735-
Nullness.paramHasNullableAnnotation(overriddenMethod, i, config)
736-
? Nullness.NULLABLE
737-
: (config.isJSpecifyMode()
738-
? GenericsChecks.getGenericMethodParameterNullness(
739-
i,
740-
overriddenMethod,
741-
overridingParamSymbols.get(i).owner.owner,
742-
state,
743-
config)
744-
: Nullness.NONNULL);
734+
Nullness paramNullness;
735+
if (Nullness.paramHasNullableAnnotation(overriddenMethod, i, config)) {
736+
paramNullness = Nullness.NULLABLE;
737+
} else if (config.isJSpecifyMode()) {
738+
// Check if the parameter type is a type variable and the corresponding generic type
739+
// argument is @Nullable
740+
if (memberReferenceTree != null) {
741+
// For a method reference, we get generic type arguments from the javac's inferred type
742+
// for the tree, which seems to properly preserve type-use annotations
743+
paramNullness =
744+
GenericsChecks.getGenericMethodParameterNullness(
745+
i, overriddenMethod, ASTHelpers.getType(memberReferenceTree), state, config);
746+
} else {
747+
// Use the enclosing class of the overriding method to find generic type arguments
748+
paramNullness =
749+
GenericsChecks.getGenericMethodParameterNullness(
750+
i, overriddenMethod, overridingParamSymbols.get(i).owner.owner, state, config);
751+
}
752+
} else {
753+
paramNullness = Nullness.NONNULL;
754+
}
755+
overriddenMethodArgNullnessMap[i] = paramNullness;
745756
}
746757
}
747758

nullaway/src/test/java/com/uber/nullaway/NullAwayJSpecifyGenericsTests.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -429,8 +429,7 @@ public void testForMethodReferenceInAnAssignment() {
429429
" return o.toString();",
430430
" }",
431431
" static void testPositive() {",
432-
" // TODO: we should report an error here, since Test::foo cannot take",
433-
" // a @Nullable parameter. we don't catch this yet",
432+
" // BUG: Diagnostic contains: parameter o of referenced method is @NonNull",
434433
" A<@Nullable Object> p = Test::foo;",
435434
" }",
436435
" static void testNegative() {",

0 commit comments

Comments
 (0)