diff --git a/nullaway/src/main/java/com/uber/nullaway/NullAway.java b/nullaway/src/main/java/com/uber/nullaway/NullAway.java index 4104da418d..3d17824579 100644 --- a/nullaway/src/main/java/com/uber/nullaway/NullAway.java +++ b/nullaway/src/main/java/com/uber/nullaway/NullAway.java @@ -639,12 +639,14 @@ private Description checkReturnExpression( return Description.NO_MATCH; } if (mayBeNullExpr(state, retExpr)) { - String message = "returning @Nullable expression from method with @NonNull return type"; + final ErrorMessage errorMessage = + new ErrorMessage( + MessageTypes.RETURN_NULLABLE, + "returning @Nullable expression from method with @NonNull return type"); + handler.onPrepareErrorMessage(retExpr, state, errorMessage); + return errorBuilder.createErrorDescriptionForNullAssignment( - new ErrorMessage(MessageTypes.RETURN_NULLABLE, message), - retExpr, - state.getPath(), - buildDescription(tree)); + errorMessage, retExpr, state.getPath(), buildDescription(tree)); } return Description.NO_MATCH; } diff --git a/nullaway/src/test/java/com/uber/nullaway/NullAwayTest.java b/nullaway/src/test/java/com/uber/nullaway/NullAwayTest.java index d167482205..3010628a26 100644 --- a/nullaway/src/test/java/com/uber/nullaway/NullAwayTest.java +++ b/nullaway/src/test/java/com/uber/nullaway/NullAwayTest.java @@ -1551,6 +1551,70 @@ public void OptionalEmptinessUncheckedTest() { .doTest(); } + @Test + public void OptionalEmptinessRxPositiveTest() { + compilationHelper + .setArgs( + Arrays.asList( + "-d", + temporaryFolder.getRoot().getAbsolutePath(), + "-XepOpt:NullAway:AnnotatedPackages=com.uber,io.reactivex", + "-XepOpt:NullAway:UnannotatedSubPackages=com.uber.lib.unannotated", + "-XepOpt:NullAway:CheckOptionalEmptiness=true")) + .addSourceLines( + "TestPositive.java", + "package com.uber;", + "import java.util.Optional;", + "import io.reactivex.Observable;", + "public class TestPositive {", + " private static boolean perhaps() { return Math.random() > 0.5; }", + " void foo(Observable> observable) {", + " observable", + " .filter(optional -> optional.isPresent() || perhaps())", + " // BUG: Diagnostic contains: Optional optional can be empty", + " .map(optional -> optional.get().toString());", + " observable", + " .filter(optional -> optional.isPresent() || perhaps())", + " // BUG: Diagnostic contains: Optional optional can be empty", + " .map(optional -> optional.get())", + " .map(irr -> irr.toString());", + " }", + "}") + .doTest(); + } + + @Test + public void OptionalEmptinessRxNegativeTest() { + compilationHelper + .setArgs( + Arrays.asList( + "-d", + temporaryFolder.getRoot().getAbsolutePath(), + "-XepOpt:NullAway:AnnotatedPackages=com.uber", + "-XepOpt:NullAway:UnannotatedSubPackages=com.uber.lib.unannotated", + "-XepOpt:NullAway:CheckOptionalEmptiness=true")) + .addSourceLines( + "TestNegative.java", + "package com.uber;", + "import java.util.Optional;", + "import io.reactivex.Observable;", + "public class TestNegative {", + " private static boolean perhaps() { return Math.random() > 0.5; }", + " void foo(Observable> observable) {", + " observable", + " .filter(optional -> optional.isPresent())", + " .map(optional -> optional.get().toString());", + " observable", + " .filter(optional -> optional.isPresent() && perhaps())", + " .map(optional -> optional.get().toString());", + " observable", + " .filter(optional -> optional.isPresent() && perhaps())", + " .map(optional -> optional.get());", + " }", + "}") + .doTest(); + } + @Test public void testCastToNonNull() { compilationHelper