[java-inspections] IDEA-272224. Added quickfix to add cast

GitOrigin-RevId: e2c4722c55bfbe8edd417fb28c5f4c5c415846eb
This commit is contained in:
Mikhail Pyltsin
2022-12-28 10:35:22 +00:00
committed by intellij-monorepo-bot
parent f59c0b2e98
commit fda015b92e
10 changed files with 132 additions and 15 deletions
@@ -838,6 +838,7 @@ confusing.main.method.problem.descriptor=Method named <code>#ref</code> without
upper.case.field.name.not.constant.problem.descriptor=Non-constant field <code>#ref</code> with constant-style name #loc
dollar.sign.in.name.problem.descriptor=Identifier <code>#ref</code> contains '$' #loc
integer.division.in.floating.point.context.problem.descriptor=<code>#ref</code>: integer division in floating-point context #loc
integer.division.in.floating.point.context.quickfix=Cast the dividend to a floating-point type
comparison.of.short.and.char.problem.descriptor=Equality comparison <code>#ref</code> of short and char values #loc
big.decimal.equals.problem.descriptor=<code>#ref()</code> between BigDecimal values should probably be 'compareTo()' #loc
divide.by.zero.problem.descriptor=Division by zero #loc
@@ -15,15 +15,21 @@
*/
package com.siyeh.ig.numeric;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.tree.IElementType;
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 com.siyeh.ig.psiutils.ComparisonUtils;
import com.siyeh.ig.psiutils.ExpectedTypeUtils;
import com.siyeh.ig.psiutils.ParenthesesUtils;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashSet;
import java.util.Set;
@@ -53,6 +59,11 @@ public class IntegerDivisionInFloatingPointContextInspection extends BaseInspect
"integer.division.in.floating.point.context.problem.descriptor");
}
@Override
protected @Nullable InspectionGadgetsFix buildFix(Object... infos) {
return new IntegerDivisionInFloatingPointContextFix();
}
@Override
public BaseInspectionVisitor buildVisitor() {
return new IntegerDivisionInFloatingPointContextVisitor();
@@ -60,7 +71,7 @@ public class IntegerDivisionInFloatingPointContextInspection extends BaseInspect
private static class IntegerDivisionInFloatingPointContextVisitor extends BaseInspectionVisitor {
IntegerDivisionInFloatingPointContextVisitor() {}
IntegerDivisionInFloatingPointContextVisitor() { }
@Override
public void visitPolyadicExpression(@NotNull PsiPolyadicExpression expression) {
@@ -88,22 +99,54 @@ public class IntegerDivisionInFloatingPointContextInspection extends BaseInspect
private static boolean isIntegral(PsiType type) {
return type != null && s_integralTypes.contains(type.getCanonicalText());
}
}
private static @NotNull PsiExpression getContainingExpression(@NotNull PsiExpression expression) {
final PsiElement parent = expression.getParent();
if (parent instanceof PsiBinaryExpression) {
final PsiBinaryExpression binaryExpression = (PsiBinaryExpression)parent;
return !ComparisonUtils.isComparisonOperation(binaryExpression.getOperationTokenType())
? getContainingExpression(binaryExpression)
: expression;
private static class IntegerDivisionInFloatingPointContextFix extends InspectionGadgetsFix {
@Override
protected void doFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
if (!(descriptor.getPsiElement() instanceof PsiBinaryExpression expression)) {
return;
}
else if (parent instanceof PsiPolyadicExpression ||
parent instanceof PsiParenthesizedExpression ||
parent instanceof PsiPrefixExpression ||
parent instanceof PsiConditionalExpression) {
return getContainingExpression((PsiExpression)parent);
final PsiExpression context = getContainingExpression(expression);
final PsiType contextType = ExpectedTypeUtils.findExpectedType(context, true);
String castTo;
if (PsiType.FLOAT.equals(contextType)) {
castTo = "float";
}
return expression;
else if (PsiType.DOUBLE.equals(contextType)) {
castTo = "double";
}
else {
return;
}
PsiExpression operand = expression.getLOperand();
CommentTracker tracker = new CommentTracker();
String text = tracker.text(operand, ParenthesesUtils.TYPE_CAST_PRECEDENCE);
tracker.replace(operand, "((" + castTo + ")" + text + ")");
}
@Override
public @NotNull String getFamilyName() {
return InspectionGadgetsBundle.message("integer.division.in.floating.point.context.quickfix");
}
}
private static @NotNull PsiExpression getContainingExpression(@NotNull PsiExpression expression) {
final PsiElement parent = expression.getParent();
if (parent instanceof PsiBinaryExpression) {
final PsiBinaryExpression binaryExpression = (PsiBinaryExpression)parent;
return !ComparisonUtils.isComparisonOperation(binaryExpression.getOperationTokenType())
? getContainingExpression(binaryExpression)
: expression;
}
else if (parent instanceof PsiPolyadicExpression ||
parent instanceof PsiParenthesizedExpression ||
parent instanceof PsiPrefixExpression ||
parent instanceof PsiConditionalExpression) {
return getContainingExpression((PsiExpression)parent);
}
return expression;
}
}
@@ -5,8 +5,13 @@ Such division is often an error and may have unexpected results
due to the truncation that happens in integer division.
<p><b>Example:</b></p>
<pre><code>
float x = 3.0F + 3/5;
float x = 3.0F + 3 * 2 / 5;
</code></pre>
<p>After the quick-fix is applied:</p>
<pre><code>
float x = 3.0F + ((float) (3 * 2)) /5;
</code></pre>
<!-- tooltip end -->
</body>
</html>
@@ -0,0 +1,7 @@
class ExpectedParenthesizedExpr {
public void test(Integer i) {
double x = 1 + (<caret>(double) (i * 2)) / 5;
System.out.println(x);
}
}
@@ -0,0 +1,7 @@
class ExpectedParenthesizedExpr {
public void test(Integer i) {
double x = 1 + i<caret> * 2 / 5;
System.out.println(x);
}
}
@@ -0,0 +1,7 @@
class SimpleDouble {
public void test(Integer i) {
double x = 1 + ((double) i)<caret> / 5;
System.out.println(x);
}
}
@@ -0,0 +1,7 @@
class SimpleDouble {
public void test(Integer i) {
double x = 1 + i<caret> / 5;
System.out.println(x);
}
}
@@ -0,0 +1,7 @@
class SimpleFloat {
public void test(Integer i) {
float x = 1 + ((float) i) / 5;
System.out.println(x);
}
}
@@ -0,0 +1,7 @@
class SimpleFloat {
public void test(Integer i) {
float x = 1 + i<caret> / 5;
System.out.println(x);
}
}
@@ -0,0 +1,26 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.siyeh.ig.fixes.numeric;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.IGQuickFixesTestCase;
import com.siyeh.ig.numeric.IntegerDivisionInFloatingPointContextInspection;
public class IntegerDivisionInFloatingPointContextFixTest extends IGQuickFixesTestCase {
public void testSimpleFloat() { doTest(); }
public void testSimpleDouble() { doTest(); }
public void testExpectedParenthesizedExpr() { doTest(); }
@Override
protected void setUp() throws Exception {
super.setUp();
final IntegerDivisionInFloatingPointContextInspection inspection = new IntegerDivisionInFloatingPointContextInspection();
myFixture.enableInspections(inspection);
myDefaultHint = InspectionGadgetsBundle.message("integer.division.in.floating.point.context.quickfix");
}
@Override
protected String getRelativePath() {
return "numeric/integer_division_in_floating_point_context";
}
}