diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/divideByZero/afterNaN.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/divideByZero/afterNaN.java new file mode 100644 index 000000000000..1d4b64c3ed2c --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/divideByZero/afterNaN.java @@ -0,0 +1,6 @@ +// "Replace with 'NaN'" "true" +class Test { + public void test() { + double nan = Double.NaN; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/divideByZero/beforeInt.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/divideByZero/beforeInt.java new file mode 100644 index 000000000000..91ae03e3dbb1 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/divideByZero/beforeInt.java @@ -0,0 +1,6 @@ +// "Replace with 'NaN'" "false" +class Test { + public void test() { + double nan = 0/0; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/divideByZero/beforeNaN.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/divideByZero/beforeNaN.java new file mode 100644 index 000000000000..e2f17fa10776 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/divideByZero/beforeNaN.java @@ -0,0 +1,6 @@ +// "Replace with 'NaN'" "true" +class Test { + public void test() { + double nan = 0.0/0.0; + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/numeric/DivideByZeroInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/numeric/DivideByZeroInspection.java index 249714cbc795..9add4d58ce2f 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/numeric/DivideByZeroInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/numeric/DivideByZeroInspection.java @@ -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'"; } } } \ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/numeric/DivideByZeroInspectionFixTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/numeric/DivideByZeroInspectionFixTest.java new file mode 100644 index 000000000000..ab0d2066d6f9 --- /dev/null +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/numeric/DivideByZeroInspectionFixTest.java @@ -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(); } +}