IDEA-382900 [java-dfa] False positive null check inspection for Optional

Space-RevId: 1e8a9a958d359c00479687ccac4877b19a039cd8

GitOrigin-RevId: d4987256123b7a71c42f882138fec18b2ec34d91
This commit is contained in:
Tagir Valeev
2026-01-23 17:19:03 +00:00
committed by intellij-monorepo-bot
parent cb3dd0a29b
commit 5b3f88ca2c
4 changed files with 66 additions and 2 deletions
@@ -0,0 +1,53 @@
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
class NullTest {
enum StatusEnum {
OK(1, "OK"), ERROR(2, "ERROR");
final Integer code;
final String msg;
StatusEnum(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
}
public static StatusEnum getInstance(Integer code) {
return Arrays.stream(StatusEnum.values())
.filter(it -> Objects.equals(it.code, code))
.findFirst()
.orElse(null);
}
public void test2() {
StatusEnum instance = getInstance(11);
if (instance == null) {
System.out.println("Instance not found");
return;
}
System.out.println(instance);
}
static String getString(List<String> list) {
return list.stream()
.findFirst()
.orElseGet(() -> null);
}
void testOrElseGet() {
if (getString(List.of()) == null) {
return;
}
}
static void main() {
new NullTest().test2();
}
}
@@ -229,11 +229,11 @@ public final class Optional</*<# @NotNull #>*/T> {
return this.isEmpty() ? Stream.empty() : Stream.of(this.value);
}
/*<# @Contract(value = "!null -> !null", pure = true) #>*//*<# @Flow(sourceIsContainer = true) #>*/public T orElse(/*<# @Flow(targetIsContainer = true) #>*//*<# @Nullable #>*/T other) {
/*<# @Contract(value = "!null -> !null", pure = true) #>*//*<# @Flow(sourceIsContainer = true) #>*/public /*<# @Nullable #>*/T orElse(/*<# @Flow(targetIsContainer = true) #>*//*<# @Nullable #>*/T other) {
return (T)(this.value != null ? this.value : other);
}
public T orElseGet(Supplier<? extends T> supplier) {
public /*<# @UnknownNullability #>*/T orElseGet(Supplier<? extends /*<# @Nullable #>*/T> supplier) {
return (T)(this.value != null ? this.value : supplier.get());
}
@@ -254,4 +254,8 @@ public class DataFlowInspection21Test extends DataFlowInspectionTestCase {
setupTypeUseAnnotations("org.jspecify.annotations", myFixture);
doTest();
}
public void testOptionalInference() {
doTestWith((dfi, cvi) -> dfi.SUGGEST_NULLABLE_ANNOTATIONS = false);
}
}
@@ -4433,6 +4433,7 @@
</annotation>
</item>
<item name='java.util.Optional T orElse(T)'>
<annotation name='org.jetbrains.annotations.Nullable'/>
<annotation name='org.jetbrains.annotations.Contract'>
<val name="value" val="&quot;!null -&gt; !null&quot;"/>
<val name="pure" val="true"/>
@@ -4447,6 +4448,12 @@
<val name="targetIsContainer" val="true"/>
</annotation>
</item>
<item name='java.util.Optional T orElseGet(java.util.function.Supplier&lt;? extends T&gt;)'>
<annotation name='org.jetbrains.annotations.UnknownNullability'/>
</item>
<item name='java.util.Optional T orElseGet(java.util.function.Supplier&lt;? extends T&gt;) 0'>
<annotation name='org.jetbrains.annotations.Nullable' typePath="/1/*"/>
</item>
<item name='java.util.Optional T orElseThrow(java.util.function.Supplier&lt;? extends X&gt;) 0'>
<annotation name='org.jetbrains.annotations.NotNull'/>
<annotation name='org.jetbrains.annotations.NotNull' typePath="/1/*"/>