2 * Copyright 2000-2009 JetBrains s.r.o.
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
.intellij
.codeInspection
.miscGenerics
;
18 import com
.intellij
.codeInsight
.CodeInsightUtilBase
;
19 import com
.intellij
.codeInsight
.daemon
.GroupNames
;
20 import com
.intellij
.codeInspection
.*;
21 import com
.intellij
.openapi
.diagnostic
.Logger
;
22 import com
.intellij
.openapi
.project
.Project
;
23 import com
.intellij
.psi
.*;
24 import com
.intellij
.psi
.util
.PsiUtil
;
25 import com
.intellij
.refactoring
.util
.InlineUtil
;
26 import com
.intellij
.util
.IncorrectOperationException
;
27 import org
.jetbrains
.annotations
.NonNls
;
28 import org
.jetbrains
.annotations
.NotNull
;
29 import org
.jetbrains
.annotations
.Nullable
;
31 import java
.util
.ArrayList
;
32 import java
.util
.List
;
37 public class RedundantArrayForVarargsCallInspection
extends GenericsInspectionToolBase
{
38 private static final Logger LOG
= Logger
.getInstance("#com.intellij.codeInspection.miscGenerics.RedundantArrayForVarargsCallInspection");
39 private final LocalQuickFix myQuickFixAction
= new MyQuickFix();
41 private static class MyQuickFix
implements LocalQuickFix
{
42 public void applyFix(@NotNull Project project
, @NotNull ProblemDescriptor descriptor
) {
43 PsiNewExpression arrayCreation
= (PsiNewExpression
) descriptor
.getPsiElement();
44 if (arrayCreation
== null || !arrayCreation
.isValid()) return;
45 if (!CodeInsightUtilBase
.prepareFileForWrite(arrayCreation
.getContainingFile())) return;
46 InlineUtil
.inlineArrayCreationForVarargs(arrayCreation
);
50 public String
getFamilyName() {
55 public String
getName() {
56 return InspectionsBundle
.message("inspection.redundant.array.creation.quickfix");
60 public ProblemDescriptor
[] getDescriptions(PsiElement place
, final InspectionManager manager
, final boolean isOnTheFly
) {
61 if (!PsiUtil
.isLanguageLevel5OrHigher(place
)) return null;
62 final List
<ProblemDescriptor
> problems
= new ArrayList
<ProblemDescriptor
>();
63 place
.accept(new JavaRecursiveElementWalkingVisitor() {
64 @Override public void visitCallExpression(PsiCallExpression expression
) {
65 super.visitCallExpression(expression
);
66 checkCall(expression
);
69 @Override public void visitEnumConstant(PsiEnumConstant enumConstant
) {
70 super.visitEnumConstant(enumConstant
);
71 checkCall(enumConstant
);
74 @Override public void visitClass(PsiClass aClass
) {
75 //do not go inside to prevent multiple signals of the same problem
78 private void checkCall(PsiCall expression
) {
79 final JavaResolveResult resolveResult
= expression
.resolveMethodGenerics();
80 PsiElement element
= resolveResult
.getElement();
81 final PsiSubstitutor substitutor
= resolveResult
.getSubstitutor();
82 if (element
instanceof PsiMethod
&& ((PsiMethod
)element
).isVarArgs()) {
83 PsiMethod method
= (PsiMethod
)element
;
84 PsiParameter
[] parameters
= method
.getParameterList().getParameters();
85 PsiExpressionList argumentList
= expression
.getArgumentList();
86 if (argumentList
!= null) {
87 PsiExpression
[] args
= argumentList
.getExpressions();
88 if (parameters
.length
== args
.length
) {
89 PsiExpression lastArg
= args
[args
.length
- 1];
90 PsiParameter lastParameter
= parameters
[args
.length
- 1];
91 PsiType lastParamType
= lastParameter
.getType();
92 LOG
.assertTrue(lastParamType
instanceof PsiEllipsisType
);
93 if (lastArg
instanceof PsiNewExpression
&&
94 substitutor
.substitute(((PsiEllipsisType
) lastParamType
).toArrayType()).equals(lastArg
.getType())) {
95 PsiExpression
[] initializers
= getInitializers((PsiNewExpression
)lastArg
);
96 if (initializers
!= null) {
97 if (isSafeToFlatten(expression
, method
, initializers
)) {
98 final ProblemDescriptor descriptor
= manager
.createProblemDescriptor(lastArg
,
99 InspectionsBundle
.message("inspection.redundant.array.creation.for.varargs.call.descriptor"),
101 ProblemHighlightType
.GENERIC_ERROR_OR_WARNING
,
104 problems
.add(descriptor
);
113 private boolean isSafeToFlatten(PsiCall callExpression
, PsiMethod oldRefMethod
, PsiExpression
[] arrayElements
) {
114 if (arrayElements
.length
== 1) {
115 PsiType type
= arrayElements
[0].getType();
116 // change foo(new Object[]{array}) to foo(array) is not safe
117 if (PsiType
.NULL
.equals(type
) || type
instanceof PsiArrayType
) return false;
119 PsiCall copy
= (PsiCall
)callExpression
.copy();
120 PsiExpressionList copyArgumentList
= copy
.getArgumentList();
121 LOG
.assertTrue(copyArgumentList
!= null);
122 PsiExpression
[] args
= copyArgumentList
.getExpressions();
124 args
[args
.length
- 1].delete();
125 if (arrayElements
.length
> 0) {
126 copyArgumentList
.addRange(arrayElements
[0], arrayElements
[arrayElements
.length
- 1]);
128 final JavaResolveResult resolveResult
= copy
.resolveMethodGenerics();
129 return resolveResult
.isValidResult() && resolveResult
.getElement() == oldRefMethod
;
131 catch (IncorrectOperationException e
) {
136 if (problems
.isEmpty()) return null;
137 return problems
.toArray(new ProblemDescriptor
[problems
.size()]);
141 private static PsiExpression
[] getInitializers(final PsiNewExpression newExpression
) {
142 PsiArrayInitializerExpression initializer
= newExpression
.getArrayInitializer();
143 if (initializer
!= null) {
144 return initializer
.getInitializers();
146 PsiExpression
[] dims
= newExpression
.getArrayDimensions();
147 if (dims
.length
> 0) {
148 PsiExpression firstDimension
= dims
[0];
150 JavaPsiFacade
.getInstance(newExpression
.getProject()).getConstantEvaluationHelper().computeConstantExpression(firstDimension
);
151 if (value
instanceof Integer
&& ((Integer
)value
).intValue() == 0) return PsiExpression
.EMPTY_ARRAY
;
158 public String
getGroupDisplayName() {
159 return GroupNames
.VERBOSE_GROUP_NAME
;
163 public String
getDisplayName() {
164 return InspectionsBundle
.message("inspection.redundant.array.creation.display.name");
169 public String
getShortName() {
170 return "RedundantArrayCreation";