DivideByZeroInspection: add fix for 0.0/0.0 (replace with NaN)

Fixes IDEA-117884 Inspection "Divide by zero": Recognize 0.0/0.0
This commit is contained in:
Tagir Valeev
2018-06-18 16:36:10 +07:00
parent e03e71ce9f
commit 048abf37d7
5 changed files with 89 additions and 9 deletions
@@ -0,0 +1,6 @@
// "Replace with 'NaN'" "true"
class Test {
public void test() {
double nan = Double.NaN;
}
}
@@ -0,0 +1,6 @@
// "Replace with 'NaN'" "false"
class Test {
public void test() {
double nan = 0/<caret>0;
}
}
@@ -0,0 +1,6 @@
// "Replace with 'NaN'" "true"
class Test {
public void test() {
double nan = 0.0/<caret>0.0;
}
}
@@ -15,17 +15,24 @@
*/
package com.siyeh.ig.numeric;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.codeInspection.dataFlow.CommonDataflow;
import com.intellij.codeInspection.dataFlow.DfaFactType;
import com.intellij.codeInspection.dataFlow.rangeSet.LongRangeSet;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.ConstantExpressionUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.BaseInspection;
import com.siyeh.ig.BaseInspectionVisitor;
import com.siyeh.ig.InspectionGadgetsFix;
import com.siyeh.ig.psiutils.CommentTracker;
import org.intellij.lang.annotations.Pattern;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class DivideByZeroInspection extends BaseInspection {
private static final LongRangeSet ZERO_RANGE = LongRangeSet.point(0);
@@ -49,6 +56,21 @@ public class DivideByZeroInspection extends BaseInspection {
return InspectionGadgetsBundle.message("divide.by.zero.problem.descriptor");
}
@Nullable
@Override
protected InspectionGadgetsFix buildFix(Object... infos) {
if (infos.length > 0 && infos[0] instanceof PsiBinaryExpression) {
PsiBinaryExpression binOp = (PsiBinaryExpression)infos[0];
if (binOp.getOperationTokenType().equals(JavaTokenType.DIV) && isZero(binOp.getLOperand())) {
PsiType type = binOp.getType();
if (PsiType.DOUBLE.equals(type) || PsiType.FLOAT.equals(type)) {
return new ReplaceWithNaNFix();
}
}
}
return null;
}
@Override
public BaseInspectionVisitor buildVisitor() {
return new DivisionByZeroVisitor();
@@ -67,7 +89,7 @@ public class DivideByZeroInspection extends BaseInspection {
for (int i = 1; i < operands.length; i++) {
final PsiExpression operand = operands[i];
if (isZero(operand)) {
registerError(operand);
registerError(operand, expression);
return;
}
}
@@ -86,15 +108,34 @@ public class DivideByZeroInspection extends BaseInspection {
}
registerError(expression);
}
}
private static boolean isZero(PsiExpression expression) {
final Object value = ConstantExpressionUtil.computeCastTo(expression, PsiType.DOUBLE);
if (value instanceof Double) {
final double constantValue = ((Double)value).doubleValue();
if (constantValue == 0.0) return true;
}
LongRangeSet range = CommonDataflow.getExpressionFact(expression, DfaFactType.RANGE);
return ZERO_RANGE.equals(range);
private static boolean isZero(PsiExpression expression) {
final Object value = ConstantExpressionUtil.computeCastTo(expression, PsiType.DOUBLE);
if (value instanceof Double) {
final double constantValue = ((Double)value).doubleValue();
if (constantValue == 0.0) return true;
}
LongRangeSet range = CommonDataflow.getExpressionFact(expression, DfaFactType.RANGE);
return ZERO_RANGE.equals(range);
}
private static class ReplaceWithNaNFix extends InspectionGadgetsFix {
@Override
protected void doFix(Project project, ProblemDescriptor descriptor) {
PsiBinaryExpression division = PsiTreeUtil.getNonStrictParentOfType(descriptor.getStartElement(), PsiBinaryExpression.class);
if (division == null) return;
PsiType type = division.getType();
if (!(type instanceof PsiPrimitiveType)) return;
String className = ((PsiPrimitiveType)type).getBoxedTypeName();
new CommentTracker().replaceAndRestoreComments(division, className+".NaN");
}
@Nls(capitalization = Nls.Capitalization.Sentence)
@NotNull
@Override
public String getFamilyName() {
return "Replace with 'NaN'";
}
}
}
@@ -0,0 +1,21 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.siyeh.ig.numeric;
import com.intellij.codeInsight.daemon.quickFix.LightQuickFixParameterizedTestCase;
import com.intellij.codeInspection.LocalInspectionTool;
import org.jetbrains.annotations.NotNull;
public class DivideByZeroInspectionFixTest extends LightQuickFixParameterizedTestCase {
@NotNull
@Override
protected LocalInspectionTool[] configureLocalInspectionTools() {
return new LocalInspectionTool[]{new DivideByZeroInspection()};
}
@Override
protected String getBasePath() {
return "/codeInsight/daemonCodeAnalyzer/quickFix/divideByZero";
}
public void test() { doAllTests(); }
}