diff --git a/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties b/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties index 84c32b7e5130..f64336fc6054 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties +++ b/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties @@ -1894,3 +1894,6 @@ boolean.variable.always.inverted.display.name=Boolean variable is always inverte boolean.field.always.inverted.problem.descriptor=Boolean field #ref is always inverted boolean.variable.always.inverted.problem.descriptor=Boolean variable #ref 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 #ref +unnecessary.explicit.numeric.cast.quickfix=Remove cast diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/numeric/UnnecessaryExplicitNumericCastInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/numeric/UnnecessaryExplicitNumericCastInspection.java index acaa5e6d3fdf..365d75710597 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/numeric/UnnecessaryExplicitNumericCastInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/numeric/UnnecessaryExplicitNumericCastInspection.java @@ -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 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 #ref"; + 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; } diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryExplicitNumericCast.html b/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryExplicitNumericCast.html index 51a48d5d2687..0330989c2cff 100644 --- a/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryExplicitNumericCast.html +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryExplicitNumericCast.html @@ -1,6 +1,7 @@ - +This inspection reports any primitive numeric casts which would otherwise be inserted +implicitly by the compiler.

New in 11, Powered by InspectionGadgets diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/numeric/unnecessary_explicit_numeric_cast/UnnecessaryExplicitNumericCast.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/numeric/unnecessary_explicit_numeric_cast/UnnecessaryExplicitNumericCast.java index d9894dd1674f..1d0374680be7 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/numeric/unnecessary_explicit_numeric_cast/UnnecessaryExplicitNumericCast.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/numeric/unnecessary_explicit_numeric_cast/UnnecessaryExplicitNumericCast.java @@ -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) {} } diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/numeric/unnecessary_explicit_numeric_cast/expected.xml b/plugins/InspectionGadgets/test/com/siyeh/igtest/numeric/unnecessary_explicit_numeric_cast/expected.xml index 5d779fbe7db2..adf186ebad97 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/numeric/unnecessary_explicit_numeric_cast/expected.xml +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/numeric/unnecessary_explicit_numeric_cast/expected.xml @@ -48,4 +48,49 @@ Unnecessary explicit numeric cast 'i' unnecessarily cast to <code>double</code> + + + UnnecessaryExplicitNumericCast.java + 28 + Unnecessary explicit numeric cast + 'b' unnecessarily cast to <code>int</code> + + + + UnnecessaryExplicitNumericCast.java + 29 + Unnecessary explicit numeric cast + 'b' unnecessarily cast to <code>int</code> + + + + UnnecessaryExplicitNumericCast.java + 30 Unnecessary explicit numeric cast + 'b' unnecessarily cast to <code>int</code> + + + + UnnecessaryExplicitNumericCast.java + 31 Unnecessary explicit numeric cast + 'b' unnecessarily cast to <code>int</code> + + + + UnnecessaryExplicitNumericCast.java + 32 + Unnecessary explicit numeric cast + 'b' unnecessarily cast to <code>int</code> + + + + UnnecessaryExplicitNumericCast.java + 33 Unnecessary explicit numeric cast + 'b' unnecessarily cast to <code>int</code> + + + + UnnecessaryExplicitNumericCast.java + 34 Unnecessary explicit numeric cast + 'b' unnecessarily cast to <code>long</code> + \ No newline at end of file