2 * Copyright 2003-2009 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
.jdk15
;
18 import com
.intellij
.codeInspection
.ProblemDescriptor
;
19 import com
.intellij
.openapi
.project
.Project
;
20 import com
.intellij
.psi
.*;
21 import com
.intellij
.psi
.util
.PsiUtil
;
22 import com
.intellij
.psi
.util
.PsiTreeUtil
;
23 import com
.intellij
.util
.IncorrectOperationException
;
24 import com
.siyeh
.InspectionGadgetsBundle
;
25 import com
.siyeh
.ig
.BaseInspection
;
26 import com
.siyeh
.ig
.BaseInspectionVisitor
;
27 import com
.siyeh
.ig
.InspectionGadgetsFix
;
28 import com
.siyeh
.ig
.psiutils
.MethodCallUtils
;
29 import org
.jetbrains
.annotations
.NonNls
;
30 import org
.jetbrains
.annotations
.NotNull
;
31 import org
.jetbrains
.annotations
.Nullable
;
33 import java
.util
.HashMap
;
36 public class UnnecessaryBoxingInspection
extends BaseInspection
{
38 @NonNls static final Map
<String
, String
> s_boxingArgs
=
39 new HashMap
<String
, String
>(9);
42 s_boxingArgs
.put("java.lang.Integer", "int");
43 s_boxingArgs
.put("java.lang.Short", "short");
44 s_boxingArgs
.put("java.lang.Boolean", "boolean");
45 s_boxingArgs
.put("java.lang.Long", "long");
46 s_boxingArgs
.put("java.lang.Byte", "byte");
47 s_boxingArgs
.put("java.lang.Float", "float");
48 s_boxingArgs
.put("java.lang.Double", "double");
49 s_boxingArgs
.put("java.lang.Long", "long");
50 s_boxingArgs
.put("java.lang.Character", "char");
55 public String
getDisplayName() {
56 return InspectionGadgetsBundle
.message(
57 "unnecessary.boxing.display.name");
61 public boolean isEnabledByDefault() {
67 protected String
buildErrorString(Object
... infos
) {
68 return InspectionGadgetsBundle
.message(
69 "unnecessary.boxing.problem.descriptor");
73 public InspectionGadgetsFix
buildFix(Object
... infos
) {
74 return new UnnecessaryBoxingFix();
77 private static class UnnecessaryBoxingFix
extends InspectionGadgetsFix
{
80 public String
getName() {
81 return InspectionGadgetsBundle
.message(
82 "unnecessary.boxing.remove.quickfix");
86 public void doFix(@NotNull Project project
, ProblemDescriptor descriptor
)
87 throws IncorrectOperationException
{
88 final PsiCallExpression expression
=
89 (PsiCallExpression
)descriptor
.getPsiElement();
90 final PsiType boxedType
= expression
.getType();
91 final PsiExpressionList argList
= expression
.getArgumentList();
92 assert argList
!= null;
93 final PsiExpression
[] args
= argList
.getExpressions();
94 final PsiType argType
= args
[0].getType();
95 final String cast
= getCastString(argType
, boxedType
);
96 final String newExpression
= args
[0].getText();
97 replaceExpression(expression
, cast
+ newExpression
);
100 private static String
getCastString(PsiType fromType
,
102 final String toTypeText
= toType
.getCanonicalText();
103 final String fromTypeText
= fromType
.getCanonicalText();
104 final String unboxedType
= s_boxingArgs
.get(toTypeText
);
105 if (fromTypeText
.equals(unboxedType
)) {
109 return '(' + unboxedType
+ ')';
115 public BaseInspectionVisitor
buildVisitor() {
116 return new UnnecessaryBoxingVisitor();
119 private static class UnnecessaryBoxingVisitor
120 extends BaseInspectionVisitor
{
122 @Override public void visitNewExpression(
123 @NotNull PsiNewExpression expression
) {
124 if (!PsiUtil
.isLanguageLevel5OrHigher(expression
)) {
127 super.visitNewExpression(expression
);
128 final PsiType constructorType
= expression
.getType();
129 if (constructorType
== null) {
132 final String constructorTypeText
=
133 constructorType
.getCanonicalText();
134 if (!s_boxingArgs
.containsKey(constructorTypeText
)) {
137 final PsiMethod constructor
= expression
.resolveConstructor();
138 if (constructor
== null) {
141 final PsiParameterList parameterList
=
142 constructor
.getParameterList();
143 if (parameterList
.getParametersCount() != 1) {
146 final PsiParameter
[] parameters
= parameterList
.getParameters();
147 final PsiParameter arg
= parameters
[0];
148 final PsiType argumentType
= arg
.getType();
149 final String argumentTypeText
= argumentType
.getCanonicalText();
150 final String boxableConstructorType
=
151 s_boxingArgs
.get(constructorTypeText
);
152 if (!boxableConstructorType
.equals(argumentTypeText
)) {
155 if (!canBeUnboxed(expression
)) {
158 registerError(expression
);
161 @Override public void visitMethodCallExpression(
162 PsiMethodCallExpression expression
) {
163 if (!PsiUtil
.isLanguageLevel5OrHigher(expression
)) {
166 super.visitMethodCallExpression(expression
);
167 final PsiExpressionList argumentList
= expression
.getArgumentList();
168 final PsiExpression
[] expressions
= argumentList
.getExpressions();
169 if (expressions
.length
!= 1) {
172 if (!(expressions
[0].getType() instanceof PsiPrimitiveType
)) {
175 final PsiReferenceExpression methodExpression
=
176 expression
.getMethodExpression();
178 final String referenceName
= methodExpression
.getReferenceName();
179 if (referenceName
== null || !referenceName
.equals("valueOf")) {
182 final PsiExpression qualifierExpression
=
183 methodExpression
.getQualifierExpression();
184 if (!(qualifierExpression
instanceof PsiReferenceExpression
)) {
187 final PsiReferenceExpression referenceExpression
=
188 (PsiReferenceExpression
)qualifierExpression
;
189 final String canonicalText
= referenceExpression
.getCanonicalText();
190 if (s_boxingArgs
.get(canonicalText
) == null) {
193 if (!canBeUnboxed(expression
)) {
196 registerError(expression
);
199 private static boolean canBeUnboxed(PsiExpression expression
) {
200 PsiElement parent
= expression
.getParent();
201 while (parent
instanceof PsiParenthesizedExpression
) {
202 parent
= parent
.getParent();
204 if (parent
instanceof PsiExpressionStatement
||
205 parent
instanceof PsiReferenceExpression
) {
207 } else if (parent
instanceof PsiTypeCastExpression
) {
208 final PsiTypeCastExpression castExpression
=
209 (PsiTypeCastExpression
)parent
;
210 final PsiType castType
= castExpression
.getType();
211 if (castType
instanceof PsiClassType
) {
212 final PsiClassType classType
= (PsiClassType
)castType
;
213 final PsiClass aClass
= classType
.resolve();
214 if (aClass
instanceof PsiTypeParameter
) {
218 } else if (parent
instanceof PsiConditionalExpression
) {
219 final PsiConditionalExpression conditionalExpression
=
220 (PsiConditionalExpression
)parent
;
221 final PsiExpression thenExpression
=
222 conditionalExpression
.getThenExpression();
223 final PsiExpression elseExpression
=
224 conditionalExpression
.getElseExpression();
225 if (elseExpression
== null || thenExpression
== null) {
228 if (PsiTreeUtil
.isAncestor(thenExpression
, expression
, false)) {
229 final PsiType type
= elseExpression
.getType();
230 return type
instanceof PsiPrimitiveType
;
231 } else if (PsiTreeUtil
.isAncestor(elseExpression
, expression
,
233 final PsiType type
= thenExpression
.getType();
234 return type
instanceof PsiPrimitiveType
;
239 final PsiMethodCallExpression containingMethodCallExpression
=
240 getParentMethodCallExpression(expression
);
241 return containingMethodCallExpression
== null ||
242 isSameMethodCalledWithoutBoxing(
243 containingMethodCallExpression
, expression
);
247 private static PsiMethodCallExpression
getParentMethodCallExpression(
248 @NotNull PsiElement expression
) {
249 final PsiElement parent
= expression
.getParent();
250 if (parent
instanceof PsiParenthesizedExpression
||
251 parent
instanceof PsiExpressionList
) {
252 return getParentMethodCallExpression(parent
);
253 } else if (parent
instanceof PsiMethodCallExpression
) {
254 return (PsiMethodCallExpression
)parent
;
260 private static boolean isSameMethodCalledWithoutBoxing(
261 @NotNull PsiMethodCallExpression methodCallExpression
,
262 @NotNull PsiExpression boxingExpression
) {
263 final PsiExpressionList argumentList
=
264 methodCallExpression
.getArgumentList();
265 final PsiExpression
[] expressions
= argumentList
.getExpressions();
266 final PsiReferenceExpression methodExpression
=
267 methodCallExpression
.getMethodExpression();
268 final PsiElement element
= methodExpression
.resolve();
269 if (!(element
instanceof PsiMethod
)) {
272 final PsiMethod originalMethod
= (PsiMethod
)element
;
273 final String name
= originalMethod
.getName();
274 final PsiClass containingClass
=
275 originalMethod
.getContainingClass();
276 if (containingClass
== null) {
279 final PsiType
[] types
= new PsiType
[expressions
.length
];
280 for (int i
= 0; i
< expressions
.length
; i
++) {
281 final PsiExpression expression
= expressions
[i
];
282 final PsiType type
= expression
.getType();
283 if (boxingExpression
.equals(expression
)) {
284 final PsiPrimitiveType unboxedType
=
285 PsiPrimitiveType
.getUnboxedType(type
);
286 if (unboxedType
== null) {
289 types
[i
] = unboxedType
;
294 final PsiMethod
[] methods
=
295 containingClass
.findMethodsByName(name
, true);
296 for (PsiMethod method
: methods
) {
297 if (!originalMethod
.equals(method
)) {
298 if (MethodCallUtils
.isApplicable(method
,
299 PsiSubstitutor
.EMPTY
, types
)) {