diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/java/inliner/StreamChainInliner.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/java/inliner/StreamChainInliner.java
index 9cc4d6e09e61..d9cc535b94b4 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/java/inliner/StreamChainInliner.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/java/inliner/StreamChainInliner.java
@@ -382,8 +382,14 @@ public class StreamChainInliner implements CallInliner {
}
static class OptionalTerminalStep extends TerminalStep {
+ private final boolean myExpectNotNull;
+
OptionalTerminalStep(@NotNull PsiMethodCallExpression call) {
super(call, ArrayUtil.getFirstElement(call.getArgumentList().getExpressions()));
+ String methodName = call.getMethodExpression().getReferenceName();
+ // While findFirst/findAny will work if the found element is definitely not-null,
+ // it's highly suspicious to supply a nullable element there
+ myExpectNotNull = "findFirst".equals(methodName) || "findAny".equals(methodName);
}
@Override
@@ -405,6 +411,11 @@ public class StreamChainInliner implements CallInliner {
DfType source = DfaOptionalSupport.getOptionalValue(true);
builder.pushForWrite(myResult).push(source).assign().splice(2);
}
+
+ @Override
+ boolean expectNotNull() {
+ return myExpectNotNull;
+ }
}
static class MinMaxTerminalStep extends TerminalStep {
diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/StreamFindFirstExpectNotNull.java b/java/java-tests/testData/inspection/dataFlow/fixture/StreamFindFirstExpectNotNull.java
new file mode 100644
index 000000000000..90cb81434809
--- /dev/null
+++ b/java/java-tests/testData/inspection/dataFlow/fixture/StreamFindFirstExpectNotNull.java
@@ -0,0 +1,18 @@
+import org.jetbrains.annotations.*;
+
+import java.util.*;
+import java.util.function.*;
+import java.util.stream.*;
+
+class StreamTypeAnnoInlining {
+ @Nullable
+ private static Object fun(String s) {
+ return null;
+ }
+
+ void test() {
+ Stream.of("a", "b").map(s -> fun(s)).findFirst();
+ Stream.of("a", "b").map(s -> fun(s)).findAny();
+ }
+
+}
diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/StreamInlining.java b/java/java-tests/testData/inspection/dataFlow/fixture/StreamInlining.java
index 8b5bf7e6ef0d..69fabea4e784 100644
--- a/java/java-tests/testData/inspection/dataFlow/fixture/StreamInlining.java
+++ b/java/java-tests/testData/inspection/dataFlow/fixture/StreamInlining.java
@@ -133,7 +133,7 @@ public class StreamInlining {
String blockLambda(List list) {
return list == null ? "" : list.stream().map(s -> {
- return s.equals("abc") ? null : s;
+ return s.equals("abc") ? null : s;
}).findFirst().orElse("");
}
diff --git a/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowInspection8Test.java b/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowInspection8Test.java
index 2efa0ffaabde..14258f20134c 100644
--- a/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowInspection8Test.java
+++ b/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowInspection8Test.java
@@ -206,6 +206,7 @@ public class DataFlowInspection8Test extends DataFlowInspectionTestCase {
setupTypeUseAnnotations("foo", myFixture);
doTest();
}
+ public void testStreamFindFirstExpectNotNull() { doTest(); }
public void testStreamAnyMatchIsNull() { doTest(); }
public void testStreamCustomSumMethod() { doTest(); }
public void testStreamReduceLogicalAnd() { doTest(); }