diff --git a/checker/src/main/java/org/checkerframework/checker/nullness/NullnessVisitor.java b/checker/src/main/java/org/checkerframework/checker/nullness/NullnessVisitor.java index 369f0d4a6d9d..2539e93f1a80 100644 --- a/checker/src/main/java/org/checkerframework/checker/nullness/NullnessVisitor.java +++ b/checker/src/main/java/org/checkerframework/checker/nullness/NullnessVisitor.java @@ -771,6 +771,33 @@ public Void visitDoWhileLoop(DoWhileLoopTree tree, Void p) { @Override public Void visitConditionalExpression(ConditionalExpressionTree tree, Void p) { checkForNullability(tree.getCondition(), CONDITION_NULLABLE); + // If the overall conditional expression has a primitive Java type but one or both + // operand expressions are reference types, then unboxing will occur as part of + // evaluating the conditional. In that case, check the operand(s) for possible + // nullness (unboxing.of.nullable). + AnnotatedTypeMirror type = atypeFactory.getAnnotatedType(tree); + // Only check for unboxing when javac has chosen a primitive underlying type + // for the conditional expression, but one or both operands are non-primitive. + if (type.getKind().isPrimitive()) { + ExpressionTree trueExpr = tree.getTrueExpression(); + ExpressionTree falseExpr = tree.getFalseExpression(); + boolean trueNeedsUnboxing = !TypesUtils.isPrimitive(TreeUtils.typeOf(trueExpr)); + boolean falseNeedsUnboxing = !TypesUtils.isPrimitive(TreeUtils.typeOf(falseExpr)); + + if (trueNeedsUnboxing) { + if (!checkForNullability(trueExpr, UNBOXING_OF_NULLABLE)) { + // If we reported an unboxing.of.nullable error for the true arm, stop + // further checking to avoid cascading errors. + return null; + } + } + if (falseNeedsUnboxing) { + if (!checkForNullability(falseExpr, UNBOXING_OF_NULLABLE)) { + return null; + } + } + } + return super.visitConditionalExpression(tree, p); } diff --git a/checker/tests/nullness/Issue6849.java b/checker/tests/nullness/Issue6849.java new file mode 100644 index 000000000000..553b9a7d6620 --- /dev/null +++ b/checker/tests/nullness/Issue6849.java @@ -0,0 +1,16 @@ +import java.util.*; +import org.checkerframework.checker.nullness.qual.*; + +public class Issue6849 { + + public static T m(List lst) { + return lst.get(0); + } + + public static void main(String[] args) { + List<@Nullable Integer> lst = new LinkedList<>(); + lst.add(null); + // :: error: [unboxing.of.nullable] + int y = ((true) ? Issue6849.<@Nullable Integer>m(lst) : 10); + } +} diff --git a/docs/manual/contributors.tex b/docs/manual/contributors.tex index fc5a6d8872f5..2eb88be2fa3b 100644 --- a/docs/manual/contributors.tex +++ b/docs/manual/contributors.tex @@ -141,6 +141,7 @@ Steph Dietzel, Stephan Schroevers, Stuart Pernsteiner, +Suvrat Acharya, Suzanne Millstein, Thomas Schweizer, Thomas Wei\ss schuh,