diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/TypeCorrector.java b/java/java-psi-impl/src/com/intellij/psi/impl/TypeCorrector.java index d848a8c04072..69664226764f 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/TypeCorrector.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/TypeCorrector.java @@ -159,6 +159,12 @@ class TypeCorrector extends PsiTypeMapper { return myDelegate.getNullability(); } + @Override + public @NotNull PsiClassType withNullability(@NotNull TypeNullability nullability) { + PsiClassType newDelegate = myDelegate.withNullability(nullability); + return newDelegate == myDelegate ? this : new PsiCorrectedClassType(myLanguageLevel, newDelegate, myResolveResult); + } + @Override public PsiType @NotNull [] getParameters() { return ContainerUtil.map2Array(myDelegate.getParameters(), PsiType.class, type -> { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiConditionalExpressionImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiConditionalExpressionImpl.java index eba1569c9a97..e44ad02689e1 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiConditionalExpressionImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiConditionalExpressionImpl.java @@ -98,8 +98,12 @@ public class PsiConditionalExpressionImpl extends ExpressionPsiElement implement } return TypeConversionUtil.binaryNumericPromotion(type1, type2); } - if (TypeConversionUtil.isNullType(type1) && !(type2 instanceof PsiPrimitiveType)) return type2; - if (TypeConversionUtil.isNullType(type2) && !(type1 instanceof PsiPrimitiveType)) return type1; + if (TypeConversionUtil.isNullType(type1) && !(type2 instanceof PsiPrimitiveType)) { + return type2.withNullability(type2.getNullability().join(type1.getNullability())); + } + if (TypeConversionUtil.isNullType(type2) && !(type1 instanceof PsiPrimitiveType)) { + return type1.withNullability(type2.getNullability().join(type1.getNullability())); + } if (TypeConversionUtil.isAssignable(type1, type2, false)) return type1; if (TypeConversionUtil.isAssignable(type2, type1, false)) return type2; diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/JSpecifyLambdaTernary.java b/java/java-tests/testData/inspection/dataFlow/fixture/JSpecifyLambdaTernary.java new file mode 100644 index 000000000000..bc3fb5eaac6e --- /dev/null +++ b/java/java-tests/testData/inspection/dataFlow/fixture/JSpecifyLambdaTernary.java @@ -0,0 +1,23 @@ +import org.jspecify.annotations.NullMarked; + +import java.util.function.Function; +import java.util.List; + +public class JSpecifyLambdaTernary { + static R process(List list, Function fn) { + return fn.apply(list.get(0)); + } + + @NullMarked + static class Use { + static void processList(List list) { + Integer result = process(list, s -> s == 0 ? null : s); + if (result == null) {} + } + + static void processListNonNumeric(List list) { + String result = process(list, s -> s.isEmpty() ? null : s); + if (result == null) {} + } + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowInspection21Test.java b/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowInspection21Test.java index 0116e6ede2a1..f08c3374875c 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowInspection21Test.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowInspection21Test.java @@ -204,5 +204,10 @@ public class DataFlowInspection21Test extends DataFlowInspectionTestCase { } public void testMutabilityJdk21() { doTest(); } + + public void testJSpecifyLambdaTernary() { + addJSpecifyNullMarked(myFixture); + doTest(); + } } \ No newline at end of file