2 * Copyright 2003-2008 Dave Griffith, Bas Leijdekkers
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com
.siyeh
.ig
.numeric
;
18 import com
.intellij
.psi
.*;
19 import com
.intellij
.openapi
.project
.Project
;
20 import com
.siyeh
.InspectionGadgetsBundle
;
21 import com
.siyeh
.ig
.BaseInspection
;
22 import com
.siyeh
.ig
.BaseInspectionVisitor
;
23 import com
.siyeh
.ig
.ui
.SingleCheckboxOptionsPanel
;
24 import com
.siyeh
.ig
.psiutils
.ClassUtils
;
25 import org
.jetbrains
.annotations
.NotNull
;
27 import javax
.swing
.JComponent
;
28 import java
.util
.HashMap
;
31 public class CastThatLosesPrecisionInspection
extends BaseInspection
{
33 @SuppressWarnings({"PublicField"})
34 public boolean ignoreIntegerCharCasts
= false;
36 /** @noinspection StaticCollection */
37 private static final Map
<PsiType
, Integer
> s_typePrecisions
=
38 new HashMap
<PsiType
, Integer
>(7);
41 s_typePrecisions
.put(PsiType
.BYTE
, 1);
42 s_typePrecisions
.put(PsiType
.CHAR
, 2);
43 s_typePrecisions
.put(PsiType
.SHORT
, 2);
44 s_typePrecisions
.put(PsiType
.INT
, 3);
45 s_typePrecisions
.put(PsiType
.LONG
, 4);
46 s_typePrecisions
.put(PsiType
.FLOAT
, 5);
47 s_typePrecisions
.put(PsiType
.DOUBLE
, 6);
52 public String
getID() {
53 return "NumericCastThatLosesPrecision";
58 public String
getDisplayName() {
59 return InspectionGadgetsBundle
.message(
60 "cast.that.loses.precision.display.name");
65 public String
buildErrorString(Object
... infos
) {
66 final PsiType operandType
= (PsiType
)infos
[0];
67 return InspectionGadgetsBundle
.message(
68 "cast.that.loses.precision.problem.descriptor",
69 operandType
.getPresentableText());
73 public JComponent
createOptionsPanel() {
74 return new SingleCheckboxOptionsPanel(InspectionGadgetsBundle
.message(
75 "cast.that.loses.precision.option"),
76 this, "ignoreIntegerCharCasts");
80 public BaseInspectionVisitor
buildVisitor() {
81 return new CastThatLosesPrecisionVisitor();
84 private class CastThatLosesPrecisionVisitor
85 extends BaseInspectionVisitor
{
87 @Override public void visitTypeCastExpression(
88 @NotNull PsiTypeCastExpression expression
) {
89 final PsiType castType
= expression
.getType();
90 if (!ClassUtils
.isPrimitiveNumericType(castType
)) {
93 final PsiExpression operand
= expression
.getOperand();
94 if (operand
== null) {
97 final PsiType operandType
= operand
.getType();
98 if (!ClassUtils
.isPrimitiveNumericType(operandType
)) {
101 if (hasLowerPrecision(operandType
, castType
)) {
104 if (ignoreIntegerCharCasts
) {
105 if (operandType
== PsiType
.INT
&&
106 castType
== PsiType
.CHAR
) {
110 final Project project
= expression
.getProject();
111 final JavaPsiFacade psiFacade
= JavaPsiFacade
.getInstance(project
);
112 final PsiConstantEvaluationHelper evaluationHelper
=
113 psiFacade
.getConstantEvaluationHelper();
115 evaluationHelper
.computeConstantExpression(operand
);
117 if (result
instanceof Character
) {
118 result
= Integer
.valueOf(((Character
) result
).charValue());
120 if (result
instanceof Number
) {
121 final Number number
= (Number
)result
;
122 if (valueIsContainableInType(number
, castType
)) {
126 final PsiTypeElement castTypeElement
= expression
.getCastType();
127 if (castTypeElement
== null) {
130 registerError(castTypeElement
, operandType
);
133 private boolean hasLowerPrecision(PsiType operandType
,
135 final Integer operandPrecision
= s_typePrecisions
.get(operandType
);
136 final Integer castPrecision
= s_typePrecisions
.get(castType
);
137 return operandPrecision
<= castPrecision
;
140 private boolean valueIsContainableInType(Number value
,
142 final long longValue
= value
.longValue();
143 final double doubleValue
= value
.doubleValue();
144 if (PsiType
.BYTE
.equals(type
)) {
145 return longValue
>= (long)Byte
.MIN_VALUE
&&
146 longValue
<= (long)Byte
.MAX_VALUE
&&
147 doubleValue
>= (double)Byte
.MIN_VALUE
&&
148 doubleValue
<= (double)Byte
.MAX_VALUE
;
149 } else if (PsiType
.CHAR
.equals(type
)) {
150 return longValue
>= (long)Character
.MIN_VALUE
&&
151 longValue
<= (long)Character
.MAX_VALUE
&&
152 doubleValue
>= (double)Character
.MIN_VALUE
&&
153 doubleValue
<= (double)Character
.MAX_VALUE
;
154 } else if (PsiType
.SHORT
.equals(type
)) {
155 return longValue
>= (long)Short
.MIN_VALUE
&&
156 longValue
<= (long)Short
.MAX_VALUE
&&
157 doubleValue
>= (double)Short
.MIN_VALUE
&&
158 doubleValue
<= (double)Short
.MAX_VALUE
;
159 } else if (PsiType
.INT
.equals(type
)) {
160 return longValue
>= (long)Integer
.MIN_VALUE
&&
161 longValue
<= (long)Integer
.MAX_VALUE
&&
162 doubleValue
>= (double)Integer
.MIN_VALUE
&&
163 doubleValue
<= (double)Integer
.MAX_VALUE
;
164 } else if (PsiType
.LONG
.equals(type
)) {
165 return longValue
>= Long
.MIN_VALUE
&&
166 longValue
<= Long
.MAX_VALUE
&&
167 doubleValue
>= (double)Long
.MIN_VALUE
&&
168 doubleValue
<= (double)Long
.MAX_VALUE
;
169 } else if (PsiType
.FLOAT
.equals(type
)) {
170 return doubleValue
== value
.floatValue();
171 } else if (PsiType
.DOUBLE
.equals(type
)) {