[java-dfa] Report when nullable value is passed to findFirst()

Fixes IDEA-289362 NPE could be detected on findFirst on a stream with nullable elements

GitOrigin-RevId: 2d27d29eacdb2612608060d423646184a9093f51
This commit is contained in:
Tagir Valeev
2022-02-25 11:10:31 +00:00
committed by intellij-monorepo-bot
parent e9a60bebf9
commit 67ae5c45e2
4 changed files with 31 additions and 1 deletions
@@ -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 {
@@ -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 -> <warning descr="Function may return null, but it's not allowed here">fun(s)</warning>).findFirst();
Stream.of("a", "b").map(s -> <warning descr="Function may return null, but it's not allowed here">fun(s)</warning>).findAny();
}
}
@@ -133,7 +133,7 @@ public class StreamInlining {
String blockLambda(List<String> list) {
return list == null ? "" : list.stream().map(s -> {
return s.equals("abc") ? null : s;
return s.equals("abc") ? <warning descr="Function may return null, but it's not allowed here">null</warning> : s;
}).findFirst().orElse("");
}
@@ -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(); }