diff --git a/java/java-analysis-impl/resources/messages/InspectionGadgetsBundle.properties b/java/java-analysis-impl/resources/messages/InspectionGadgetsBundle.properties
index 4a35203ee156..1bf2c195962f 100644
--- a/java/java-analysis-impl/resources/messages/InspectionGadgetsBundle.properties
+++ b/java/java-analysis-impl/resources/messages/InspectionGadgetsBundle.properties
@@ -848,6 +848,7 @@ inspection.lossy.conversion.compound.assignment.display.name=Implicit cast from
comparison.of.short.and.char.problem.descriptor=Equality comparison #ref of short and char values #loc
big.decimal.equals.problem.descriptor=#ref() between BigDecimal values should probably be 'compareTo()' #loc
divide.by.zero.problem.descriptor=Division by zero #loc
+divide.by.zero.problem.may.descriptor=Maybe division by zero #loc
non.reproducible.math.call.problem.descriptor=Math.#ref() may produce non-reproducible results #loc
constant.math.call.problem.descriptor=Constant call to #ref() can be simplified #loc
floating.point.equality.problem.descriptor=#ref: floating-point values compared for exact equality #loc
diff --git a/java/java-analysis-impl/src/com/siyeh/ig/numeric/DivideByZeroInspection.java b/java/java-analysis-impl/src/com/siyeh/ig/numeric/DivideByZeroInspection.java
index 9bd765f608a2..2418b0f36c46 100644
--- a/java/java-analysis-impl/src/com/siyeh/ig/numeric/DivideByZeroInspection.java
+++ b/java/java-analysis-impl/src/com/siyeh/ig/numeric/DivideByZeroInspection.java
@@ -18,6 +18,8 @@ package com.siyeh.ig.numeric;
import com.intellij.codeInspection.CommonQuickFixBundle;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.dataFlow.CommonDataflow;
+import com.intellij.codeInspection.dataFlow.rangeSet.LongRangeSet;
+import com.intellij.codeInspection.dataFlow.types.DfIntType;
import com.intellij.codeInspection.dataFlow.types.DfType;
import com.intellij.modcommand.ModPsiUpdater;
import com.intellij.modcommand.PsiUpdateModCommandQuickFix;
@@ -26,6 +28,8 @@ import com.intellij.psi.*;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.ConstantExpressionUtil;
import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.util.ThreeState;
+import com.intellij.util.containers.ContainerUtil;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.BaseInspection;
import com.siyeh.ig.BaseInspectionVisitor;
@@ -35,6 +39,8 @@ import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import java.util.List;
+
public final class DivideByZeroInspection extends BaseInspection {
@Pattern(VALID_ID_PATTERN)
@@ -45,13 +51,18 @@ public final class DivideByZeroInspection extends BaseInspection {
@Override
protected @NotNull String buildErrorString(Object... infos) {
- return InspectionGadgetsBundle.message("divide.by.zero.problem.descriptor");
+ if (infos.length > 1 && infos[1] instanceof ThreeState threeState && threeState == ThreeState.UNSURE) {
+ return InspectionGadgetsBundle.message("divide.by.zero.problem.may.descriptor");
+ }
+ else {
+ return InspectionGadgetsBundle.message("divide.by.zero.problem.descriptor");
+ }
}
@Override
protected @Nullable LocalQuickFix buildFix(Object... infos) {
if (infos.length > 0 && infos[0] instanceof PsiBinaryExpression binOp) {
- if (binOp.getOperationTokenType().equals(JavaTokenType.DIV) && isZero(binOp.getLOperand())) {
+ if (binOp.getOperationTokenType().equals(JavaTokenType.DIV) && isZero(binOp.getLOperand()) == ThreeState.YES) {
PsiType type = binOp.getType();
if (PsiTypes.doubleType().equals(type) || PsiTypes.floatType().equals(type)) {
return new ReplaceWithNaNFix();
@@ -78,8 +89,9 @@ public final class DivideByZeroInspection extends BaseInspection {
final PsiExpression[] operands = expression.getOperands();
for (int i = 1; i < operands.length; i++) {
final PsiExpression operand = operands[i];
- if (isZero(operand)) {
- registerError(operand, expression);
+ ThreeState zero = isZero(operand);
+ if (zero != ThreeState.NO) {
+ registerError(operand, expression, zero);
return;
}
}
@@ -93,22 +105,35 @@ public final class DivideByZeroInspection extends BaseInspection {
return;
}
final IElementType tokenType = expression.getOperationTokenType();
- if (!tokenType.equals(JavaTokenType.DIVEQ) && !tokenType.equals(JavaTokenType.PERCEQ) || !isZero(rhs)) {
+ if (!tokenType.equals(JavaTokenType.DIVEQ) && !tokenType.equals(JavaTokenType.PERCEQ) || isZero(rhs) != ThreeState.YES) {
return;
}
registerError(expression);
}
}
- private static boolean isZero(PsiExpression expression) {
+ private static ThreeState isZero(PsiExpression expression) {
final Object value = ConstantExpressionUtil.computeCastTo(expression, PsiTypes.doubleType());
if (value instanceof Double) {
final double constantValue = ((Double)value).doubleValue();
- return constantValue == 0.0;
+ return constantValue == 0.0 ? ThreeState.YES : ThreeState.NO;
}
DfType dfType = CommonDataflow.getDfType(expression);
Number val = dfType.getConstantOfType(Number.class);
- return val != null && val.doubleValue() == 0.0;
+ if (val != null) {
+ return val.doubleValue() == 0.0 ? ThreeState.YES : ThreeState.NO;
+ }
+ if (dfType instanceof DfIntType dfIntType) {
+ LongRangeSet range = dfIntType.getRange();
+ List ranges = range.asRanges();
+ if (ranges.size() < 4 &&
+ ContainerUtil.exists(ranges, t ->
+ t.getConstantValue() != null && t.getConstantValue() == 0L ||
+ t.max() - t.min() < 2 && t.contains(0L))) {
+ return ThreeState.UNSURE;
+ }
+ }
+ return ThreeState.NO;
}
private static class ReplaceWithNaNFix extends PsiUpdateModCommandQuickFix {
diff --git a/java/java-tests/testData/ig/com/siyeh/igtest/numeric/divide_by_zero/DivideByZero.java b/java/java-tests/testData/ig/com/siyeh/igtest/numeric/divide_by_zero/DivideByZero.java
index 84effcecfe4a..6bdfcf99521e 100644
--- a/java/java-tests/testData/ig/com/siyeh/igtest/numeric/divide_by_zero/DivideByZero.java
+++ b/java/java-tests/testData/ig/com/siyeh/igtest/numeric/divide_by_zero/DivideByZero.java
@@ -54,4 +54,16 @@ public class DivideByZero {
}
}
}
+
+ void testMayBe(String[] args) {
+ int x = 0;
+ if (args.length==1) x = 100;
+ System.out.println(10 / x);
+ }
+
+ void testMayBe2(String[] args) {
+ int x = 0;
+ if (args.length==1) x = 1;
+ System.out.println(10 / x);
+ }
}
\ No newline at end of file