"Unnecessary explicit numeric cast" inspection improvements

This commit is contained in:
Bas Leijdekkers
2011-05-25 12:14:14 +02:00
parent a21de1ecdb
commit a8e358eb9e
5 changed files with 180 additions and 54 deletions
@@ -1894,3 +1894,6 @@ boolean.variable.always.inverted.display.name=Boolean variable is always inverte
boolean.field.always.inverted.problem.descriptor=Boolean field <code>#ref</code> is always inverted
boolean.variable.always.inverted.problem.descriptor=Boolean variable <code>#ref</code> is always inverted
boolean.variable.always.inverted.quickfix=Invert ''{0}''
unnecessary.explicit.numeric.cast.display.name=Unnecessary explicit numeric cast
unnecessary.explicit.numeric.cast.problem.descriptor=''{0}'' unnecessarily cast to <code>#ref</code>
unnecessary.explicit.numeric.cast.quickfix=Remove cast
@@ -18,28 +18,57 @@ 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.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.IncorrectOperationException;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.BaseInspection;
import com.siyeh.ig.BaseInspectionVisitor;
import com.siyeh.ig.InspectionGadgetsFix;
import com.siyeh.ig.psiutils.ClassUtils;
import com.siyeh.ig.psiutils.ExpectedTypeUtils;
import com.siyeh.ig.psiutils.ExpressionUtils;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import java.util.HashSet;
import java.util.Set;
public class UnnecessaryExplicitNumericCastInspection extends BaseInspection {
private static final Set<IElementType> binaryPromotionOperators = new HashSet();
static {
binaryPromotionOperators.add(JavaTokenType.ASTERISK);
binaryPromotionOperators.add(JavaTokenType.DIV);
binaryPromotionOperators.add(JavaTokenType.PERC);
binaryPromotionOperators.add(JavaTokenType.PLUS);
binaryPromotionOperators.add(JavaTokenType.MINUS);
binaryPromotionOperators.add(JavaTokenType.LT);
binaryPromotionOperators.add(JavaTokenType.LE);
binaryPromotionOperators.add(JavaTokenType.GT);
binaryPromotionOperators.add(JavaTokenType.GE);
binaryPromotionOperators.add(JavaTokenType.EQEQ);
binaryPromotionOperators.add(JavaTokenType.NE);
binaryPromotionOperators.add(JavaTokenType.AND);
binaryPromotionOperators.add(JavaTokenType.XOR);
binaryPromotionOperators.add(JavaTokenType.OR);
}
@Nls
@NotNull
@Override
public String getDisplayName() {
return "Unnecessary explicit numeric cast";
return InspectionGadgetsBundle.message(
"unnecessary.explicit.numeric.cast.display.name");
}
@NotNull
@Override
protected String buildErrorString(Object... infos) {
final PsiExpression expression = (PsiExpression) infos[0];
return " '" + expression.getText() + "' unnecessarily cast to <code>#ref</code>";
return InspectionGadgetsBundle.message(
"unnecessary.explicit.numeric.cast.problem.descriptor",
expression.getText());
}
@Override
@@ -49,10 +78,12 @@ public class UnnecessaryExplicitNumericCastInspection extends BaseInspection {
private static class UnnecessaryExplicitNumericCastFix
extends InspectionGadgetsFix {
@NotNull
@Override
public String getName() {
return "Remove cast";
return InspectionGadgetsBundle.message(
"unnecessary.explicit.numeric.cast.quickfix");
}
@Override
@@ -111,8 +142,8 @@ public class UnnecessaryExplicitNumericCastInspection extends BaseInspection {
static boolean isPrimitiveNumericCastNecessary(
PsiTypeCastExpression expression) {
final PsiType type = expression.getType();
if (type == null) {
final PsiType castType = expression.getType();
if (castType == null) {
return true;
}
final PsiExpression operand = expression.getOperand();
@@ -120,97 +151,129 @@ public class UnnecessaryExplicitNumericCastInspection extends BaseInspection {
return true;
}
final PsiType operandType = operand.getType();
final PsiElement parent = expression.getParent();
PsiElement parent = expression.getParent();
while (parent instanceof PsiParenthesizedExpression) {
parent = parent.getParent();
}
if (parent instanceof PsiBinaryExpression) {
if (PsiType.INT.equals(type)) {
return PsiType.LONG.equals(operandType) ||
PsiType.FLOAT.equals(operandType) ||
PsiType.DOUBLE.equals(operandType);
}
if (PsiType.LONG.equals(type) || PsiType.FLOAT.equals(type) ||
PsiType.DOUBLE.equals(type)) {
final PsiBinaryExpression binaryExpression =
(PsiBinaryExpression) parent;
final PsiExpression lhs = binaryExpression.getLOperand();
final PsiBinaryExpression binaryExpression =
(PsiBinaryExpression) parent;
final IElementType tokenType =
binaryExpression.getOperationTokenType();
if (binaryPromotionOperators.contains(tokenType)) {
if (PsiType.INT.equals(castType)) {
return PsiType.LONG.equals(operandType) ||
PsiType.FLOAT.equals(operandType) ||
PsiType.DOUBLE.equals(operandType);
}
if (PsiType.LONG.equals(castType) ||
PsiType.FLOAT.equals(castType) ||
PsiType.DOUBLE.equals(castType)) {
final PsiExpression lhs = binaryExpression.getLOperand();
final PsiExpression rhs = binaryExpression.getROperand();
if (rhs == null) {
return true;
}
if (expression == lhs) {
final PsiType rhsType = rhs.getType();
if (castType.equals(rhsType)) {
return false;
}
} else if (expression == rhs) {
final PsiType lhsType = lhs.getType();
if (castType.equals(lhsType)) {
return false;
}
} else {
assert false;
}
}
} else if (JavaTokenType.GTGT.equals(tokenType) ||
JavaTokenType.GTGTGT.equals(tokenType) ||
JavaTokenType.LTLT.equals(tokenType)) {
final PsiExpression rhs = binaryExpression.getROperand();
if (rhs == null) {
if (PsiTreeUtil.isAncestor(rhs, expression, false)) {
return false;
}
if (PsiType.LONG.equals(castType)) {
return true;
}
if (expression == lhs) {
final PsiType rhsType = rhs.getType();
if (type.equals(rhsType)) {
return false;
}
} else if (expression == rhs) {
final PsiType lhsType = lhs.getType();
if (type.equals(lhsType)) {
return false;
}
} else {
assert false;
}
return !isLegalWideningConversion(operand, PsiType.INT);
}
return true;
} else if (parent instanceof PsiAssignmentExpression) {
final PsiAssignmentExpression assignmentExpression =
(PsiAssignmentExpression) parent;
final PsiType lhsType = assignmentExpression.getType();
if (!type.equals(lhsType)) {
if (!castType.equals(lhsType)) {
return true;
}
return !isHandledByAssignmentConversion(lhsType, operand);
return !isLegalAssignmentConversion(operand, lhsType);
} else if (parent instanceof PsiVariable) {
final PsiVariable variable = (PsiVariable) parent;
final PsiType lhsType = variable.getType();
if (!type.equals(lhsType)) {
if (!castType.equals(lhsType)) {
return true;
}
return !isHandledByAssignmentConversion(lhsType, operand);
return !isLegalAssignmentConversion(operand, lhsType);
} else {
final PsiType expectedType =
ExpectedTypeUtils.findExpectedType(expression, false);
if (!castType.equals(expectedType)) {
return true;
}
return !isLegalWideningConversion(operand, castType);
}
return true;
}
static boolean isHandledByAssignmentConversion(PsiType lhsType,
PsiExpression operand) {
// JLS 5.2 Assignment Conversion
final PsiType operandType = operand.getType();
if (PsiType.DOUBLE.equals(lhsType)) {
public static boolean isLegalWideningConversion(
PsiExpression expression, PsiType requiredType) {
final PsiType operandType = expression.getType();
if (PsiType.DOUBLE.equals(requiredType)) {
if (PsiType.FLOAT.equals(operandType) ||
PsiType.LONG.equals(operandType) ||
PsiType.INT.equals(operandType) ||
PsiType.CHAR.equals(operandType) ||
PsiType.SHORT.equals(operandType) ||
PsiType.BYTE.equals(operandType)) {
// widening
return true;
}
} else if (PsiType.FLOAT.equals(lhsType)) {
} else if (PsiType.FLOAT.equals(requiredType)) {
if (PsiType.LONG.equals(operandType) ||
PsiType.INT.equals(operandType) ||
PsiType.CHAR.equals(operandType) ||
PsiType.SHORT.equals(operandType) ||
PsiType.BYTE.equals(operandType)) {
// widening
return true;
}
} else if (PsiType.LONG.equals(lhsType)) {
} else if (PsiType.LONG.equals(requiredType)) {
if (PsiType.INT.equals(operandType) ||
PsiType.CHAR.equals(operandType) ||
PsiType.SHORT.equals(operandType) ||
PsiType.BYTE.equals(operandType)) {
// widening
return true;
}
} else if (PsiType.INT.equals(lhsType)) {
} else if (PsiType.INT.equals(requiredType)) {
if (PsiType.CHAR.equals(operandType) ||
PsiType.SHORT.equals(operandType) ||
PsiType.BYTE.equals(operandType)) {
// widening
return true;
}
} else if (PsiType.SHORT.equals(lhsType)) {
}
return false;
}
public static boolean isLegalAssignmentConversion(
PsiExpression expression, PsiType assignmentType) {
// JLS 5.2 Assignment Conversion
final PsiType operandType = expression.getType();
if (isLegalWideningConversion(expression, assignmentType)) {
return true;
} else if (PsiType.SHORT.equals(assignmentType)) {
if (PsiType.INT.equals(operandType)) {
final Object constant =
ExpressionUtils.computeConstantExpression(operand);
ExpressionUtils.computeConstantExpression(expression);
if (!(constant instanceof Integer)) {
return false;
}
@@ -220,10 +283,10 @@ public class UnnecessaryExplicitNumericCastInspection extends BaseInspection {
return true;
}
}
} else if (PsiType.CHAR.equals(lhsType)) {
} else if (PsiType.CHAR.equals(assignmentType)) {
if (PsiType.INT.equals(operandType)) {
final Object constant =
ExpressionUtils.computeConstantExpression(operand);
ExpressionUtils.computeConstantExpression(expression);
if (!(constant instanceof Integer)) {
return false;
}
@@ -233,10 +296,10 @@ public class UnnecessaryExplicitNumericCastInspection extends BaseInspection {
return true;
}
}
} else if (PsiType.BYTE.equals(lhsType)) {
} else if (PsiType.BYTE.equals(assignmentType)) {
if (PsiType.INT.equals(operandType)) {
final Object constant =
ExpressionUtils.computeConstantExpression(operand);
ExpressionUtils.computeConstantExpression(expression);
if (!(constant instanceof Integer)) {
return false;
}
@@ -1,6 +1,7 @@
<html>
<body>
This inspection reports any primitive numeric casts which would otherwise be inserted
implicitly by the compiler.
<p>
<small>New in 11, Powered by InspectionGadgets</small>
</body>
@@ -22,4 +22,18 @@ public class UnnecessaryExplicitNumericCast {
double d = 123.0 / (456.0 * (double) i);
}
void unary() {
byte b = 2;
int a[] = new int[(int)b];
final int c = a[((int) b)];
int[] a2 = new int[]{(int)b};
int[] a3 = {(int)b};
final int result = (int) b << 1;
c((int)b);
new UnnecessaryExplicitNumericCast((long)b);
}
void c(int i) {}
UnnecessaryExplicitNumericCast(long i) {}
}
@@ -48,4 +48,49 @@
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Unnecessary explicit numeric cast</problem_class>
<description>'i' unnecessarily cast to &lt;code&gt;double&lt;/code&gt;</description>
</problem>
<problem>
<file>UnnecessaryExplicitNumericCast.java</file>
<line>28</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Unnecessary explicit numeric cast</problem_class>
<description>'b' unnecessarily cast to &lt;code&gt;int&lt;/code&gt;</description>
</problem>
<problem>
<file>UnnecessaryExplicitNumericCast.java</file>
<line>29</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Unnecessary explicit numeric cast</problem_class>
<description>'b' unnecessarily cast to &lt;code&gt;int&lt;/code&gt;</description>
</problem>
<problem>
<file>UnnecessaryExplicitNumericCast.java</file>
<line>30</line> <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Unnecessary explicit numeric cast</problem_class>
<description>'b' unnecessarily cast to &lt;code&gt;int&lt;/code&gt;</description>
</problem>
<problem>
<file>UnnecessaryExplicitNumericCast.java</file>
<line>31</line> <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Unnecessary explicit numeric cast</problem_class>
<description>'b' unnecessarily cast to &lt;code&gt;int&lt;/code&gt;</description>
</problem>
<problem>
<file>UnnecessaryExplicitNumericCast.java</file>
<line>32</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Unnecessary explicit numeric cast</problem_class>
<description>'b' unnecessarily cast to &lt;code&gt;int&lt;/code&gt;</description>
</problem>
<problem>
<file>UnnecessaryExplicitNumericCast.java</file>
<line>33</line> <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Unnecessary explicit numeric cast</problem_class>
<description>'b' unnecessarily cast to &lt;code&gt;int&lt;/code&gt;</description>
</problem>
<problem>
<file>UnnecessaryExplicitNumericCast.java</file>
<line>34</line> <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Unnecessary explicit numeric cast</problem_class>
<description>'b' unnecessarily cast to &lt;code&gt;long&lt;/code&gt;</description>
</problem>
</problems>