diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/InspectionGadgetsPlugin.java b/plugins/InspectionGadgets/src/com/siyeh/ig/InspectionGadgetsPlugin.java
index 158b3b80fbe7..f96fcceb0065 100644
--- a/plugins/InspectionGadgets/src/com/siyeh/ig/InspectionGadgetsPlugin.java
+++ b/plugins/InspectionGadgets/src/com/siyeh/ig/InspectionGadgetsPlugin.java
@@ -1101,6 +1101,7 @@ public class InspectionGadgetsPlugin implements ApplicationComponent,
m_inspectionClasses.add(OverlyComplexArithmeticExpressionInspection.class);
m_inspectionClasses.add(PointlessArithmeticExpressionInspection.class);
m_inspectionClasses.add(UnaryPlusInspection.class);
+ m_inspectionClasses.add(UnnecessaryExplicitNumericCastInspection.class);
m_inspectionClasses.add(UnnecessaryUnaryMinusInspection.class);
m_inspectionClasses.add(UnpredictableBigDecimalConstructorCallInspection.class);
}
diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/numeric/UnnecessaryExplicitNumericCastInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/numeric/UnnecessaryExplicitNumericCastInspection.java
new file mode 100644
index 000000000000..acaa5e6d3fdf
--- /dev/null
+++ b/plugins/InspectionGadgets/src/com/siyeh/ig/numeric/UnnecessaryExplicitNumericCastInspection.java
@@ -0,0 +1,252 @@
+/*
+ * Copyright 2011 Bas Leijdekkers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.numeric;
+
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.*;
+import com.intellij.util.IncorrectOperationException;
+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.ExpressionUtils;
+import org.jetbrains.annotations.Nls;
+import org.jetbrains.annotations.NotNull;
+
+public class UnnecessaryExplicitNumericCastInspection extends BaseInspection {
+ @Nls
+ @NotNull
+ @Override
+ public String getDisplayName() {
+ return "Unnecessary explicit numeric cast";
+ }
+
+ @NotNull
+ @Override
+ protected String buildErrorString(Object... infos) {
+ final PsiExpression expression = (PsiExpression) infos[0];
+ return " '" + expression.getText() + "' unnecessarily cast to #ref";
+ }
+
+ @Override
+ protected InspectionGadgetsFix buildFix(Object... infos) {
+ return new UnnecessaryExplicitNumericCastFix();
+ }
+
+ private static class UnnecessaryExplicitNumericCastFix
+ extends InspectionGadgetsFix {
+ @NotNull
+ @Override
+ public String getName() {
+ return "Remove cast";
+ }
+
+ @Override
+ protected void doFix(Project project, ProblemDescriptor descriptor)
+ throws IncorrectOperationException {
+ final PsiElement element = descriptor.getPsiElement();
+ final PsiElement parent = element.getParent();
+ if (!(parent instanceof PsiTypeCastExpression)) {
+ return;
+ }
+ final PsiTypeCastExpression typeCastExpression =
+ (PsiTypeCastExpression) parent;
+ if (isPrimitiveNumericCastNecessary(typeCastExpression)) {
+ return;
+ }
+ final PsiExpression operand = typeCastExpression.getOperand();
+ if (operand == null) {
+ typeCastExpression.delete();
+ } else {
+ typeCastExpression.replace(operand);
+ }
+ }
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new UnnecessaryExplicitNumericCastVisitor();
+ }
+
+ private static class UnnecessaryExplicitNumericCastVisitor
+ extends BaseInspectionVisitor {
+
+ @Override
+ public void visitTypeCastExpression(PsiTypeCastExpression expression) {
+ super.visitTypeCastExpression(expression);
+ final PsiType castType = expression.getType();
+ if (!ClassUtils.isPrimitiveNumericType(castType)) {
+ return;
+ }
+ final PsiExpression operand = expression.getOperand();
+ if (operand == null) {
+ return;
+ }
+ final PsiType operandType = operand.getType();
+ if (operandType == null || operandType.equals(castType)) {
+ return;
+ }
+ if (isPrimitiveNumericCastNecessary(expression)) {
+ return;
+ }
+ final PsiTypeElement typeElement = expression.getCastType();
+ if (typeElement != null) {
+ registerError(typeElement, operand);}
+ }
+ }
+
+ static boolean isPrimitiveNumericCastNecessary(
+ PsiTypeCastExpression expression) {
+ final PsiType type = expression.getType();
+ if (type == null) {
+ return true;
+ }
+ final PsiExpression operand = expression.getOperand();
+ if (operand == null) {
+ return true;
+ }
+ final PsiType operandType = operand.getType();
+ final PsiElement parent = expression.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 PsiExpression rhs = binaryExpression.getROperand();
+ if (rhs == null) {
+ 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;
+ }
+ }
+ } else if (parent instanceof PsiAssignmentExpression) {
+ final PsiAssignmentExpression assignmentExpression =
+ (PsiAssignmentExpression) parent;
+ final PsiType lhsType = assignmentExpression.getType();
+ if (!type.equals(lhsType)) {
+ return true;
+ }
+ return !isHandledByAssignmentConversion(lhsType, operand);
+ } else if (parent instanceof PsiVariable) {
+ final PsiVariable variable = (PsiVariable) parent;
+ final PsiType lhsType = variable.getType();
+ if (!type.equals(lhsType)) {
+ return true;
+ }
+ return !isHandledByAssignmentConversion(lhsType, operand);
+ }
+ return true;
+ }
+
+ static boolean isHandledByAssignmentConversion(PsiType lhsType,
+ PsiExpression operand) {
+ // JLS 5.2 Assignment Conversion
+ final PsiType operandType = operand.getType();
+ if (PsiType.DOUBLE.equals(lhsType)) {
+ 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)) {
+ 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)) {
+ 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)) {
+ if (PsiType.CHAR.equals(operandType) ||
+ PsiType.SHORT.equals(operandType) ||
+ PsiType.BYTE.equals(operandType)) {
+ // widening
+ return true;
+ }
+ } else if (PsiType.SHORT.equals(lhsType)) {
+ if (PsiType.INT.equals(operandType)) {
+ final Object constant =
+ ExpressionUtils.computeConstantExpression(operand);
+ if (!(constant instanceof Integer)) {
+ return false;
+ }
+ final int i = ((Integer) constant).intValue();
+ if (i >= Short.MIN_VALUE && i <= Short.MAX_VALUE) {
+ // narrowing
+ return true;
+ }
+ }
+ } else if (PsiType.CHAR.equals(lhsType)) {
+ if (PsiType.INT.equals(operandType)) {
+ final Object constant =
+ ExpressionUtils.computeConstantExpression(operand);
+ if (!(constant instanceof Integer)) {
+ return false;
+ }
+ final int i = ((Integer) constant).intValue();
+ if (i >= Character.MIN_VALUE && i <= Character.MAX_VALUE) {
+ // narrowing
+ return true;
+ }
+ }
+ } else if (PsiType.BYTE.equals(lhsType)) {
+ if (PsiType.INT.equals(operandType)) {
+ final Object constant =
+ ExpressionUtils.computeConstantExpression(operand);
+ if (!(constant instanceof Integer)) {
+ return false;
+ }
+ final int i = ((Integer) constant).intValue();
+ if (i >= Byte.MIN_VALUE && i <= Byte.MAX_VALUE) {
+ // narrowing
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+}
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
new file mode 100644
index 000000000000..d9894dd1674f
--- /dev/null
+++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/numeric/unnecessary_explicit_numeric_cast/UnnecessaryExplicitNumericCast.java
@@ -0,0 +1,25 @@
+package com.siyeh.igtest.numeric.unnecessary_explicit_numeric_cast;
+
+
+
+
+public class UnnecessaryExplicitNumericCast {
+
+ void a(byte b) {
+ double d = (double) 1;
+ d = (double) 1.0f;
+ d = (double) b;
+ char c = (char) 1;
+ b = (int)7;
+ }
+
+ double b(int a, byte b) {
+ return (double)a * (double) b;
+ }
+
+ public static void main(String[] args) {
+ int i = 10;
+
+ double d = 123.0 / (456.0 * (double) 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
new file mode 100644
index 000000000000..5d779fbe7db2
--- /dev/null
+++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/numeric/unnecessary_explicit_numeric_cast/expected.xml
@@ -0,0 +1,51 @@
+
+
+
+ UnnecessaryExplicitNumericCast.java
+ 9
+ Unnecessary explicit numeric cast
+ '1' unnecessarily cast to <code>double</code>
+
+
+
+ UnnecessaryExplicitNumericCast.java
+ 10
+ Unnecessary explicit numeric cast
+ '1.0f' unnecessarily cast to <code>double</code>
+
+
+
+ UnnecessaryExplicitNumericCast.java
+ 11
+ Unnecessary explicit numeric cast
+ 'b' unnecessarily cast to <code>double</code>
+
+
+
+ UnnecessaryExplicitNumericCast.java
+ 12
+ Unnecessary explicit numeric cast
+ '1' unnecessarily cast to <code>char</code>
+
+
+
+ UnnecessaryExplicitNumericCast.java
+ 17
+ Unnecessary explicit numeric cast
+ 'a' unnecessarily cast to <code>double</code>
+
+
+
+ UnnecessaryExplicitNumericCast.java
+ 17
+ Unnecessary explicit numeric cast
+ 'b' unnecessarily cast to <code>double</code>
+
+
+
+ UnnecessaryExplicitNumericCast.java
+ 23
+ Unnecessary explicit numeric cast
+ 'i' unnecessarily cast to <code>double</code>
+
+
\ No newline at end of file
diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/numeric/UnnecessaryExplicitNumericCastInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/numeric/UnnecessaryExplicitNumericCastInspectionTest.java
new file mode 100644
index 000000000000..e0ff6e706e58
--- /dev/null
+++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/numeric/UnnecessaryExplicitNumericCastInspectionTest.java
@@ -0,0 +1,11 @@
+package com.siyeh.ig.numeric;
+
+import com.siyeh.ig.IGInspectionTestCase;
+
+public class UnnecessaryExplicitNumericCastInspectionTest extends IGInspectionTestCase {
+
+ public void test() throws Exception {
+ doTest("com/siyeh/igtest/numeric/unnecessary_explicit_numeric_cast",
+ new UnnecessaryExplicitNumericCastInspection ());
+ }
+}
\ No newline at end of file