IDEA-116910 (Invalid "unnecessary explicit numeric cast" warning)

This commit is contained in:
Bas Leijdekkers
2013-11-25 10:44:25 +01:00
parent f119c2e7c6
commit 7c80f38656
5 changed files with 69 additions and 70 deletions
@@ -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<PsiType, Integer> typePrecisions = new HashMap<PsiType, Integer>(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();
@@ -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;
}
}
@@ -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<PsiType, Integer> typePrecisions = new HashMap<PsiType, Integer>(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);
}
@@ -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;
}
}
@@ -100,4 +100,11 @@
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">Unnecessary explicit numeric cast</problem_class>
<description>''b'' unnecessarily cast to &lt;code&gt;int&lt;/code&gt; #loc</description>
</problem>
<problem>
<file>UnnecessaryExplicitNumericCast.java</file>
<line>59</line>
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">Unnecessary explicit numeric cast</problem_class>
<description>'i()' unnecessarily cast to &lt;code&gt;long&lt;/code&gt; #loc</description>
</problem>
</problems>