From 7c80f38656a1fdaba78d26a4c752fa772cc45fbb Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Mon, 25 Nov 2013 10:44:25 +0100 Subject: [PATCH] IDEA-116910 (Invalid "unnecessary explicit numeric cast" warning) --- .../CastThatLosesPrecisionInspection.java | 34 ++-------- ...ecessaryExplicitNumericCastInspection.java | 67 ++++++++----------- .../src/com/siyeh/ig/psiutils/TypeUtils.java | 21 ++++++ .../UnnecessaryExplicitNumericCast.java | 10 +++ .../expected.xml | 7 ++ 5 files changed, 69 insertions(+), 70 deletions(-) diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/numeric/CastThatLosesPrecisionInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/numeric/CastThatLosesPrecisionInspection.java index d45abb156159..01829b05d6cb 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/numeric/CastThatLosesPrecisionInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/numeric/CastThatLosesPrecisionInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2012 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2013 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,29 +24,13 @@ import com.siyeh.ig.BaseInspectionVisitor; import com.siyeh.ig.psiutils.ClassUtils; import com.siyeh.ig.psiutils.ExpressionUtils; import com.siyeh.ig.psiutils.MethodUtils; +import com.siyeh.ig.psiutils.TypeUtils; import org.jetbrains.annotations.NotNull; import javax.swing.*; -import java.util.HashMap; -import java.util.Map; public class CastThatLosesPrecisionInspection extends BaseInspection { - /** - * @noinspection StaticCollection - */ - private static final Map typePrecisions = new HashMap(7); - - static { - typePrecisions.put(PsiType.BYTE, 1); - typePrecisions.put(PsiType.CHAR, 2); - typePrecisions.put(PsiType.SHORT, 2); - typePrecisions.put(PsiType.INT, 3); - typePrecisions.put(PsiType.LONG, 4); - typePrecisions.put(PsiType.FLOAT, 5); - typePrecisions.put(PsiType.DOUBLE, 6); - } - @SuppressWarnings({"PublicField"}) public boolean ignoreIntegerCharCasts = false; @@ -81,8 +65,7 @@ public class CastThatLosesPrecisionInspection extends BaseInspection { return new CastThatLosesPrecisionVisitor(); } - private class CastThatLosesPrecisionVisitor - extends BaseInspectionVisitor { + private class CastThatLosesPrecisionVisitor extends BaseInspectionVisitor { @Override public void visitTypeCastExpression(@NotNull PsiTypeCastExpression expression) { @@ -95,10 +78,7 @@ public class CastThatLosesPrecisionInspection extends BaseInspection { return; } final PsiType operandType = operand.getType(); - if (!ClassUtils.isPrimitiveNumericType(operandType)) { - return; - } - if (hasLowerPrecision(operandType, castType)) { + if (!ClassUtils.isPrimitiveNumericType(operandType) || !TypeUtils.isNarrowingConversion(operandType, castType)) { return; } if (ignoreIntegerCharCasts) { @@ -129,12 +109,6 @@ public class CastThatLosesPrecisionInspection extends BaseInspection { registerError(castTypeElement, operandType); } - private boolean hasLowerPrecision(PsiType operandType, PsiType castType) { - final Integer operandPrecision = typePrecisions.get(operandType); - final Integer castPrecision = typePrecisions.get(castType); - return operandPrecision.intValue() <= castPrecision.intValue(); - } - private boolean valueIsContainableInType(Number value, PsiType type) { final long longValue = value.longValue(); final double doubleValue = value.doubleValue(); diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/numeric/UnnecessaryExplicitNumericCastInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/numeric/UnnecessaryExplicitNumericCastInspection.java index f7eeccffb09d..a850823e8624 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/numeric/UnnecessaryExplicitNumericCastInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/numeric/UnnecessaryExplicitNumericCastInspection.java @@ -28,6 +28,7 @@ import com.siyeh.ig.InspectionGadgetsFix; import com.siyeh.ig.psiutils.ClassUtils; import com.siyeh.ig.psiutils.ExpectedTypeUtils; import com.siyeh.ig.psiutils.ExpressionUtils; +import com.siyeh.ig.psiutils.TypeUtils; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; @@ -158,17 +159,21 @@ public class UnnecessaryExplicitNumericCastInspection extends BaseInspection { final PsiPolyadicExpression polyadicExpression = (PsiPolyadicExpression)parent; final IElementType tokenType = polyadicExpression.getOperationTokenType(); if (binaryPromotionOperators.contains(tokenType)) { + if (TypeUtils.isNarrowingConversion(operandType, castType)) { + return true; + } 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[] operands = polyadicExpression.getOperands(); for (PsiExpression operand1 : operands) { - if (!PsiTreeUtil.isAncestor(operand1, expression, false)) { - final PsiType type = operand1.getType(); - if (castType.equals(type)) { - return false; - } + if (PsiTreeUtil.isAncestor(operand1, expression, false)) { + continue; + } + final PsiType type = operand1.getType(); + if (castType.equals(type)) { + return false; } } } @@ -283,49 +288,31 @@ public class UnnecessaryExplicitNumericCastInspection extends BaseInspection { 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(expression); - if (!(constant instanceof Integer)) { - return false; - } - final int i = ((Integer)constant).intValue(); - if (i >= Short.MIN_VALUE && i <= Short.MAX_VALUE) { - // narrowing - return true; - } - } + if (PsiType.SHORT.equals(assignmentType)) { + return canValueBeContained(expression, Short.MIN_VALUE, Short.MAX_VALUE); } else if (PsiType.CHAR.equals(assignmentType)) { - if (PsiType.INT.equals(operandType)) { - final Object constant = ExpressionUtils.computeConstantExpression(expression); - if (!(constant instanceof Integer)) { - return false; - } - final int i = ((Integer)constant).intValue(); - if (i >= Character.MIN_VALUE && i <= Character.MAX_VALUE) { - // narrowing - return true; - } - } + return canValueBeContained(expression, Character.MIN_VALUE, Character.MAX_VALUE); } else if (PsiType.BYTE.equals(assignmentType)) { - if (PsiType.INT.equals(operandType)) { - final Object constant = ExpressionUtils.computeConstantExpression(expression); - 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 canValueBeContained(expression, Byte.MIN_VALUE, Byte.MAX_VALUE); } return false; } + + private static boolean canValueBeContained(PsiExpression expression, int lowerBound, int upperBound) { + final PsiType expressionType = expression.getType(); + if (!PsiType.INT.equals(expressionType)) { + return false; + } + final Object constant = ExpressionUtils.computeConstantExpression(expression); + if (!(constant instanceof Integer)) { + return false; + } + final int i = ((Integer)constant).intValue(); + return i >= lowerBound && i <= upperBound; + } } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/TypeUtils.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/TypeUtils.java index 34110a4cc702..51a650461481 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/TypeUtils.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/TypeUtils.java @@ -23,8 +23,23 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.HashMap; +import java.util.Map; + public class TypeUtils { + private static final Map typePrecisions = new HashMap(7); + + static { + typePrecisions.put(PsiType.BYTE, 1); + typePrecisions.put(PsiType.CHAR, 2); + typePrecisions.put(PsiType.SHORT, 2); + typePrecisions.put(PsiType.INT, 3); + typePrecisions.put(PsiType.LONG, 4); + typePrecisions.put(PsiType.FLOAT, 5); + typePrecisions.put(PsiType.DOUBLE, 6); + } + private TypeUtils() {} public static boolean typeEquals(@NonNls @NotNull String typeName, @Nullable PsiType targetType) { @@ -50,6 +65,12 @@ public class TypeUtils { return getType(CommonClassNames.JAVA_LANG_STRING, context); } + public static boolean isNarrowingConversion(PsiType operandType, PsiType castType) { + final Integer operandPrecision = typePrecisions.get(operandType); + final Integer castPrecision = typePrecisions.get(castType); + return operandPrecision.intValue() > castPrecision.intValue(); + } + public static boolean isJavaLangObject(@Nullable PsiType targetType) { return typeEquals(CommonClassNames.JAVA_LANG_OBJECT, targetType); } 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 9468de1baf32..26cc95afef11 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 @@ -53,4 +53,14 @@ public class UnnecessaryExplicitNumericCast { float x = 2; target((int) x); // this line complains: 'x' unnecessarily cast to 'int' } + + void a(float angleFromTo) { + float f = (float) Math.cos(0.5) * 1.0f; // necessary + final long l = (long) i() * 9L; + float angle2 = angleFromTo + (float) (Math.PI / 2); + } + + int i() { + return 10; + } } 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 19f2cadeff52..1e24f7ab3d58 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 @@ -100,4 +100,11 @@ Unnecessary explicit numeric cast ''b'' unnecessarily cast to <code>int</code> #loc + + + UnnecessaryExplicitNumericCast.java + 59 + Unnecessary explicit numeric cast + 'i()' unnecessarily cast to <code>long</code> #loc + \ No newline at end of file