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
.refactoring
.util
;
18 import com
.intellij
.codeInsight
.ChangeContextUtil
;
19 import com
.intellij
.openapi
.diagnostic
.Logger
;
20 import com
.intellij
.openapi
.util
.Comparing
;
21 import com
.intellij
.openapi
.util
.text
.StringUtil
;
22 import com
.intellij
.psi
.*;
23 import com
.intellij
.psi
.util
.PsiTreeUtil
;
24 import com
.intellij
.psi
.util
.RedundantCastUtil
;
25 import com
.intellij
.util
.Function
;
26 import com
.intellij
.util
.IncorrectOperationException
;
27 import org
.jetbrains
.annotations
.NonNls
;
29 import java
.util
.Arrays
;
34 public class InlineUtil
{
35 private static final Logger LOG
= Logger
.getInstance("com.intellij.refactoring.util.InlineUtil");
37 private InlineUtil() {}
39 public static PsiExpression
inlineVariable(PsiVariable variable
, PsiExpression initializer
, PsiJavaCodeReferenceElement ref
)
40 throws IncorrectOperationException
{
41 PsiManager manager
= initializer
.getManager();
43 PsiClass thisClass
= RefactoringUtil
.getThisClass(initializer
);
44 PsiClass refParent
= RefactoringUtil
.getThisClass(ref
);
45 final PsiType varType
= variable
.getType();
46 initializer
= RefactoringUtil
.convertInitializerToNormalExpression(initializer
, varType
);
48 ChangeContextUtil
.encodeContextInfo(initializer
, false);
49 PsiExpression expr
= (PsiExpression
)ref
.replace(initializer
);
50 PsiType exprType
= expr
.getType();
51 if (exprType
!= null && !varType
.equals(exprType
)) {
52 boolean matchedTypes
= false;
53 //try explicit type arguments
54 final PsiElementFactory elementFactory
= JavaPsiFacade
.getInstance(manager
.getProject()).getElementFactory();
55 if (expr
instanceof PsiCallExpression
&& ((PsiCallExpression
)expr
).getTypeArguments().length
== 0) {
56 final JavaResolveResult resolveResult
= ((PsiCallExpression
)initializer
).resolveMethodGenerics();
57 final PsiElement resolved
= resolveResult
.getElement();
58 if (resolved
instanceof PsiMethod
) {
59 final PsiTypeParameter
[] typeParameters
= ((PsiMethod
)resolved
).getTypeParameters();
60 if (typeParameters
.length
> 0) {
61 final PsiCallExpression copy
= (PsiCallExpression
)expr
.copy();
62 for (final PsiTypeParameter typeParameter
: typeParameters
) {
63 final PsiType substituted
= resolveResult
.getSubstitutor().substitute(typeParameter
);
64 if (substituted
== null) break;
65 copy
.getTypeArgumentList().add(elementFactory
.createTypeElement(substituted
));
67 if (varType
.equals(copy
.getType())) {
68 ((PsiCallExpression
)expr
).getTypeArgumentList().replace(copy
.getTypeArgumentList());
69 if (expr
instanceof PsiMethodCallExpression
) {
70 final PsiReferenceExpression methodExpression
= ((PsiMethodCallExpression
)expr
).getMethodExpression();
71 final PsiExpression qualifierExpression
= methodExpression
.getQualifierExpression();
72 if (qualifierExpression
== null) {
73 if (((PsiMethod
)resolved
).getModifierList().hasModifierProperty(PsiModifier
.STATIC
)) {
74 methodExpression
.setQualifierExpression(elementFactory
.createReferenceExpression(thisClass
));
76 methodExpression
.setQualifierExpression(createThisExpression(manager
, thisClass
, refParent
));
87 if (varType
instanceof PsiEllipsisType
&& ((PsiEllipsisType
)varType
).getComponentType().equals(exprType
)) { //convert vararg to array
89 final PsiExpressionList argumentList
= PsiTreeUtil
.getParentOfType(expr
, PsiExpressionList
.class);
90 LOG
.assertTrue(argumentList
!= null);
91 final PsiExpression
[] arguments
= argumentList
.getExpressions();
93 @NonNls final StringBuilder builder
= new StringBuilder("new ");
94 builder
.append(exprType
.getCanonicalText());
95 builder
.append("[]{");
96 builder
.append(StringUtil
.join(Arrays
.asList(arguments
), new Function
<PsiExpression
, String
>() {
97 public String
fun(final PsiExpression expr
) {
98 return expr
.getText();
103 expr
.replace(JavaPsiFacade
.getInstance(manager
.getProject()).getElementFactory().createExpressionFromText(builder
.toString(), argumentList
));
107 PsiTypeCastExpression cast
= (PsiTypeCastExpression
)elementFactory
.createExpressionFromText("(t)a", null);
108 PsiTypeElement castTypeElement
= cast
.getCastType();
109 assert castTypeElement
!= null;
110 castTypeElement
.replace(variable
.getTypeElement());
111 final PsiExpression operand
= cast
.getOperand();
112 assert operand
!= null;
113 operand
.replace(expr
);
114 PsiExpression exprCopy
= (PsiExpression
)expr
.copy();
115 cast
= (PsiTypeCastExpression
)expr
.replace(cast
);
116 if (!RedundantCastUtil
.isCastRedundant(cast
)) {
120 PsiElement toReplace
= cast
;
121 while (toReplace
.getParent() instanceof PsiParenthesizedExpression
) {
122 toReplace
= toReplace
.getParent();
124 expr
= (PsiExpression
)toReplace
.replace(exprCopy
);
130 ChangeContextUtil
.clearContextInfo(initializer
);
132 PsiThisExpression thisAccessExpr
= createThisExpression(manager
, thisClass
, refParent
);
134 return (PsiExpression
)ChangeContextUtil
.decodeContextInfo(expr
, thisClass
, thisAccessExpr
);
137 private static PsiThisExpression
createThisExpression(PsiManager manager
, PsiClass thisClass
, PsiClass refParent
) {
138 PsiThisExpression thisAccessExpr
= null;
139 if (Comparing
.equal(thisClass
, refParent
))
142 thisAccessExpr
= RefactoringUtil
.createThisExpression(manager
, null);
148 if (!(thisClass
instanceof PsiAnonymousClass
)) {
149 thisAccessExpr
= RefactoringUtil
.createThisExpression(manager
, thisClass
);
152 return thisAccessExpr
;
155 public static void tryToInlineArrayCreationForVarargs(final PsiExpression expr
) {
156 if (expr
instanceof PsiNewExpression
&& ((PsiNewExpression
)expr
).getArrayInitializer() != null) {
157 if (expr
.getParent() instanceof PsiExpressionList
) {
158 final PsiExpressionList exprList
= (PsiExpressionList
)expr
.getParent();
159 if (exprList
.getParent() instanceof PsiCall
) {
160 if (isSafeToInlineVarargsArgument((PsiCall
)exprList
.getParent())) {
161 inlineArrayCreationForVarargs(((PsiNewExpression
)expr
));
168 public static void inlineArrayCreationForVarargs(final PsiNewExpression arrayCreation
) {
169 PsiExpressionList argumentList
= (PsiExpressionList
)arrayCreation
.getParent();
170 if (argumentList
== null) return;
171 PsiExpression
[] args
= argumentList
.getExpressions();
172 PsiArrayInitializerExpression arrayInitializer
= arrayCreation
.getArrayInitializer();
174 if (arrayInitializer
== null) {
175 arrayCreation
.delete();
179 PsiExpression
[] initializers
= arrayInitializer
.getInitializers();
180 if (initializers
.length
> 0) {
181 argumentList
.addRange(initializers
[0], initializers
[initializers
.length
- 1]);
183 args
[args
.length
- 1].delete();
185 catch (IncorrectOperationException e
) {
190 private static boolean isSafeToInlineVarargsArgument(PsiCall expression
) {
191 final JavaResolveResult resolveResult
= expression
.resolveMethodGenerics();
192 PsiElement element
= resolveResult
.getElement();
193 final PsiSubstitutor substitutor
= resolveResult
.getSubstitutor();
194 if (element
instanceof PsiMethod
&& ((PsiMethod
)element
).isVarArgs()) {
195 PsiMethod method
= (PsiMethod
)element
;
196 PsiParameter
[] parameters
= method
.getParameterList().getParameters();
197 PsiExpressionList argumentList
= expression
.getArgumentList();
198 if (argumentList
!= null) {
199 PsiExpression
[] args
= argumentList
.getExpressions();
200 if (parameters
.length
== args
.length
) {
201 PsiExpression lastArg
= args
[args
.length
- 1];
202 PsiParameter lastParameter
= parameters
[args
.length
- 1];
203 PsiType lastParamType
= lastParameter
.getType();
204 LOG
.assertTrue(lastParamType
instanceof PsiEllipsisType
);
205 if (lastArg
instanceof PsiNewExpression
) {
206 final PsiType lastArgType
= lastArg
.getType();
207 if (lastArgType
!= null && substitutor
.substitute(((PsiEllipsisType
)lastParamType
).toArrayType()).isAssignableFrom(lastArgType
)) {
208 PsiArrayInitializerExpression arrayInitializer
= ((PsiNewExpression
)lastArg
).getArrayInitializer();
209 PsiExpression
[] initializers
= arrayInitializer
!= null ? arrayInitializer
.getInitializers() : PsiExpression
.EMPTY_ARRAY
;
210 if (isSafeToFlatten(expression
, method
, initializers
)) {
222 private static boolean isSafeToFlatten(PsiCall callExpression
, PsiMethod oldRefMethod
, PsiExpression
[] arrayElements
) {
223 PsiCall copy
= (PsiCall
)callExpression
.copy();
224 PsiExpressionList copyArgumentList
= copy
.getArgumentList();
225 LOG
.assertTrue(copyArgumentList
!= null);
226 PsiExpression
[] args
= copyArgumentList
.getExpressions();
228 args
[args
.length
- 1].delete();
229 if (arrayElements
.length
> 0) {
230 copyArgumentList
.addRange(arrayElements
[0], arrayElements
[arrayElements
.length
- 1]);
232 return copy
.resolveMethod() == oldRefMethod
;
234 catch (IncorrectOperationException e
) {