diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/NullnessUtil.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/NullnessUtil.java index 11f7c09c57ed..c7cf08419542 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/NullnessUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/NullnessUtil.java @@ -122,6 +122,18 @@ public class NullnessUtil { } public static Nullness getExpressionNullness(@Nullable PsiExpression expression) { + return getExpressionNullness(expression, false); + } + + /** + * Tries to determine an expression nullness + * + * @param expression an expression to check + * @param useDataflow whether to use dataflow (more expensive, but may produce more precise result) + * @return expression nullness. UNKNOWN if unable to determine; + * NULLABLE if known to possibly have null value; NOT_NULL if definitely never null. + */ + public static Nullness getExpressionNullness(@Nullable PsiExpression expression, boolean useDataflow) { expression = PsiUtil.skipParenthesizedExprDown(expression); if (expression == null) return Nullness.UNKNOWN; if (expression.textMatches(PsiKeyword.NULL)) return Nullness.NULLABLE; @@ -136,13 +148,13 @@ public class NullnessUtil { PsiExpression thenExpression = ((PsiConditionalExpression)expression).getThenExpression(); PsiExpression elseExpression = ((PsiConditionalExpression)expression).getElseExpression(); if (thenExpression == null || elseExpression == null) return Nullness.UNKNOWN; - Nullness left = getExpressionNullness(thenExpression); + Nullness left = getExpressionNullness(thenExpression, useDataflow); if (left == Nullness.UNKNOWN) return Nullness.UNKNOWN; - Nullness right = getExpressionNullness(elseExpression); + Nullness right = getExpressionNullness(elseExpression, useDataflow); return left == right ? left : Nullness.UNKNOWN; } if (expression instanceof PsiTypeCastExpression) { - return getExpressionNullness(((PsiTypeCastExpression)expression).getOperand()); + return getExpressionNullness(((PsiTypeCastExpression)expression).getOperand(), useDataflow); } if (expression instanceof PsiReferenceExpression) { PsiElement target = ((PsiReferenceExpression)expression).resolve(); @@ -151,10 +163,13 @@ public class NullnessUtil { if (expression instanceof PsiAssignmentExpression) { PsiAssignmentExpression assignment = (PsiAssignmentExpression)expression; if(assignment.getOperationTokenType().equals(JavaTokenType.EQ)) { - return getExpressionNullness(assignment.getRExpression()); + return getExpressionNullness(assignment.getRExpression(), useDataflow); } return Nullness.NOT_NULL; } + if (useDataflow) { + return fromBoolean(CommonDataflow.getExpressionFact(expression, DfaFactType.CAN_BE_NULL)); + } if (expression instanceof PsiMethodCallExpression) { PsiMethod method = ((PsiMethodCallExpression)expression).resolveMethod(); return method != null ? DfaPsiUtil.getElementNullability(expression.getType(), method) : Nullness.UNKNOWN; diff --git a/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/OptionalPostfixTemplate.java b/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/OptionalPostfixTemplate.java index 072bee170b61..e26bb081fc47 100644 --- a/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/OptionalPostfixTemplate.java +++ b/java/java-impl/src/com/intellij/codeInsight/template/postfix/templates/OptionalPostfixTemplate.java @@ -51,7 +51,7 @@ public class OptionalPostfixTemplate extends StringBasedPostfixTemplate { } } - String methodName = Nullness.NOT_NULL.equals(NullnessUtil.getExpressionNullness((PsiExpression)element)) ? "of" : "ofNullable"; + String methodName = Nullness.NOT_NULL.equals(NullnessUtil.getExpressionNullness((PsiExpression)element, true)) ? "of" : "ofNullable"; return "java.util." + className + "." + methodName + "($expr$)"; } } diff --git a/java/java-impl/src/com/intellij/codeInspection/OptionalIsPresentInspection.java b/java/java-impl/src/com/intellij/codeInspection/OptionalIsPresentInspection.java index e72f641ea5fd..f8670487de95 100644 --- a/java/java-impl/src/com/intellij/codeInspection/OptionalIsPresentInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/OptionalIsPresentInspection.java @@ -186,7 +186,7 @@ public class OptionalIsPresentInspection extends AbstractBaseJavaLocalInspection if (!hasNoBadRefs) return ProblemType.NONE; if (!hasOptionalReference.get() || !(lambdaCandidate instanceof PsiExpression)) return ProblemType.INFO; PsiExpression expression = (PsiExpression)lambdaCandidate; - if (falseExpression != null && NullnessUtil.getExpressionNullness(expression) != Nullness.NOT_NULL) { + if (falseExpression != null && NullnessUtil.getExpressionNullness(expression, true) != Nullness.NOT_NULL) { // falseExpression == null is "consumer" case (to be replaced with ifPresent()), // in this case we don't care about expression nullness return ProblemType.INFO; diff --git a/java/java-impl/src/com/intellij/codeInspection/ReplaceNullCheckInspection.java b/java/java-impl/src/com/intellij/codeInspection/ReplaceNullCheckInspection.java index 08be1fac4fdd..af0f111e75ef 100644 --- a/java/java-impl/src/com/intellij/codeInspection/ReplaceNullCheckInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/ReplaceNullCheckInspection.java @@ -292,7 +292,7 @@ public class ReplaceNullCheckInspection extends AbstractBaseJavaLocalInspectionT nonNullDiff = qualifierDiff.getRight(); if(!ExpressionUtils.isReferenceTo(nullDiff, variable)) return null; } - if(NullnessUtil.getExpressionNullness(nonNullDiff) != Nullness.NOT_NULL) return null; + if(NullnessUtil.getExpressionNullness(nonNullDiff, true) != Nullness.NOT_NULL) return null; if(!LambdaGenerationUtil.canBeUncheckedLambda(nonNullDiff)) return null; return new NotNullContext(nonNullDiff, nullDiff, nullBranch, variable, ifStatement, toDelete, false); } @@ -355,7 +355,7 @@ public class ReplaceNullCheckInspection extends AbstractBaseJavaLocalInspectionT if(ClassUtils.isPrimitive(variable.getType())) return null; PsiExpression nullBranch = negated ? ternary.getThenExpression() : ternary.getElseExpression(); if(!ExpressionUtils.isReferenceTo(nullBranch, variable)) return null; - if(NullnessUtil.getExpressionNullness(nonNullBranch) != Nullness.NOT_NULL) return null; + if(NullnessUtil.getExpressionNullness(nonNullBranch, true) != Nullness.NOT_NULL) return null; if(!LambdaGenerationUtil.canBeUncheckedLambda(nonNullBranch)) return null; return new TernaryNotNullContext(ternary, nonNullBranch, variable); }