diff --git a/java-frontend/src/main/java/org/sonar/java/se/FlowComputation.java b/java-frontend/src/main/java/org/sonar/java/se/FlowComputation.java index 41e91718d8a..f7b5660523f 100644 --- a/java-frontend/src/main/java/org/sonar/java/se/FlowComputation.java +++ b/java-frontend/src/main/java/org/sonar/java/se/FlowComputation.java @@ -385,8 +385,7 @@ List flowFromLearnedAssociation(LearnedAssociat for (Constraint constraint : constraints) { String symbolName = learnedAssociation.symbol().name(); String msg; - if ((ObjectConstraint.NULL == constraint && assigningNullFromTernary(node)) - || (assigningFromMethodInvocation(node) && assignedFromYieldWithUncertainResult(constraint, node))) { + if (assigningNullFromTernary(node) || (assigningFromMethodInvocation(node) && assignedFromYieldWithUncertainResult(constraint, node))) { msg = IMPLIES_CAN_BE_MSG; } else { msg = IMPLIES_IS_MSG; @@ -443,7 +442,7 @@ private boolean isTernaryWithNullBranch(@Nullable ExpressionTree expressionTree) ExpressionTree expr = ExpressionUtils.skipParentheses(expressionTree); if (expr.is(Tree.Kind.CONDITIONAL_EXPRESSION)) { ConditionalExpressionTree cet = (ConditionalExpressionTree) expr; - return ExpressionUtils.isNullLiteral(cet.trueExpression()) || ExpressionUtils.isNullLiteral(cet.falseExpression()); + return ExpressionUtils.isNullLiteral(cet.trueExpression()) ^ ExpressionUtils.isNullLiteral(cet.falseExpression()); } return false; } diff --git a/java-frontend/src/test/files/se/FlowMessagesBranch.java b/java-frontend/src/test/files/se/FlowMessagesBranch.java index f5be81c1de9..3f39d69faa6 100644 --- a/java-frontend/src/test/files/se/FlowMessagesBranch.java +++ b/java-frontend/src/test/files/se/FlowMessagesBranch.java @@ -1,4 +1,4 @@ -abstract class A { +class A { void foo(Object a, Object b) { if (a == null // flow@npe1 {{Implies 'a' can be null.}} @@ -23,4 +23,26 @@ void qix(Object a) { o.toString(); // flow@npe3 {{'o' is dereferenced.}} } + void gul(Object a) { + Object o = a != null ? null : null; // flow@npe4 {{Implies 'o' is null.}} + // Noncompliant@+1 [[flows=npe4]] {{A "NullPointerException" could be thrown; "o" is nullable here.}} + o.toString(); // flow@npe4 {{'o' is dereferenced.}} + } + + void dag(Object a) { + Object o = a == null ? null : a.toString(); // flow@npe5 {{Implies 'o' can be null.}} + // Noncompliant@+1 [[flows=npe5]] {{A "NullPointerException" could be thrown; "o" is nullable here.}} + o.toString(); // flow@npe5 {{'o' is dereferenced.}} + } + + void cro(Object a) { + Object o = a != null ? a.toString() : foo(); // flow@npe6 {{'foo()' returns null.}} flow@npe6 {{Implies 'o' is null.}} + // Noncompliant@+1 [[flows=npe6]] {{A "NullPointerException" could be thrown; "o" is nullable here.}} + o.toString(); // flow@npe6 {{'o' is dereferenced.}} + } + + static Object foo() { + return null; + } + }