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
.extractMethod
;
18 import com
.intellij
.openapi
.diagnostic
.Logger
;
19 import com
.intellij
.openapi
.util
.Key
;
20 import com
.intellij
.psi
.*;
21 import com
.intellij
.psi
.search
.SearchScope
;
22 import com
.intellij
.psi
.search
.searches
.ClassInheritorsSearch
;
23 import com
.intellij
.psi
.search
.searches
.ReferencesSearch
;
24 import com
.intellij
.psi
.util
.PsiTreeUtil
;
25 import com
.intellij
.psi
.util
.RedundantCastUtil
;
26 import com
.intellij
.util
.IncorrectOperationException
;
27 import com
.intellij
.util
.Processor
;
28 import com
.intellij
.util
.containers
.HashMap
;
35 public class ExtractMethodUtil
{
36 private static final Key
<PsiMethod
> RESOLVE_TARGET_KEY
= Key
.create("RESOLVE_TARGET_KEY");
37 private static final Logger LOG
= Logger
.getInstance("com.intellij.refactoring.extractMethod.ExtractMethodUtil");
39 private ExtractMethodUtil() { }
41 static Map
<PsiMethodCallExpression
, PsiMethod
> encodeOverloadTargets(final PsiClass targetClass
,
42 final SearchScope processConflictsScope
,
43 final String overloadName
,
44 final PsiElement extractedFragment
) {
45 final Map
<PsiMethodCallExpression
, PsiMethod
> ret
= new HashMap
<PsiMethodCallExpression
, PsiMethod
>();
46 encodeInClass(targetClass
, overloadName
, extractedFragment
, ret
);
48 ClassInheritorsSearch
.search(targetClass
, processConflictsScope
, true).forEach(new Processor
<PsiClass
>() {
49 public boolean process(PsiClass inheritor
) {
50 encodeInClass(inheritor
, overloadName
, extractedFragment
, ret
);
58 private static void encodeInClass(final PsiClass aClass
,
59 final String overloadName
,
60 final PsiElement extractedFragment
,
61 final Map
<PsiMethodCallExpression
, PsiMethod
> ret
) {
62 final PsiMethod
[] overloads
= aClass
.findMethodsByName(overloadName
, false);
63 for (final PsiMethod overload
: overloads
) {
64 for (final PsiReference ref
: ReferencesSearch
.search(overload
)) {
65 final PsiElement element
= ref
.getElement();
66 final PsiElement parent
= element
.getParent();
67 if (parent
instanceof PsiMethodCallExpression
) {
68 final PsiMethodCallExpression call
= (PsiMethodCallExpression
)parent
;
69 if (PsiTreeUtil
.isAncestor(extractedFragment
, element
, false)) {
70 call
.putCopyableUserData(RESOLVE_TARGET_KEY
, overload
);
72 //we assume element won't be invalidated as a result of extraction
73 ret
.put(call
, overload
);
80 public static void decodeOverloadTargets(Map
<PsiMethodCallExpression
, PsiMethod
> oldResolves
, final PsiMethod extracted
,
81 final PsiElement oldFragment
) {
82 final PsiCodeBlock body
= extracted
.getBody();
84 final JavaRecursiveElementVisitor visitor
= new JavaRecursiveElementVisitor() {
86 @Override public void visitMethodCallExpression(PsiMethodCallExpression expression
) {
87 super.visitMethodCallExpression(expression
);
88 final PsiMethod target
= expression
.getCopyableUserData(RESOLVE_TARGET_KEY
);
90 expression
.putCopyableUserData(RESOLVE_TARGET_KEY
, null);
92 assertSameResolveTarget(target
, expression
, extracted
);
94 catch (IncorrectOperationException e
) {
100 body
.accept(visitor
);
101 oldFragment
.accept(visitor
);
103 for (final Map
.Entry
<PsiMethodCallExpression
, PsiMethod
> entry
: oldResolves
.entrySet()) {
105 assertSameResolveTarget(entry
.getValue(), entry
.getKey(), extracted
);
107 catch (IncorrectOperationException e
) {
113 private static void assertSameResolveTarget(final PsiMethod oldTarget
, final PsiMethodCallExpression call
, final PsiMethod extracted
)
114 throws IncorrectOperationException
{
115 final PsiMethod newTarget
= call
.resolveMethod();
116 final PsiManager manager
= extracted
.getManager();
117 final PsiElementFactory factory
= JavaPsiFacade
.getInstance(manager
.getProject()).getElementFactory();
118 if (!manager
.areElementsEquivalent(oldTarget
, newTarget
)) {
119 final PsiParameter
[] oldParameters
= oldTarget
.getParameterList().getParameters();
120 final PsiMethodCallExpression copy
= (PsiMethodCallExpression
)call
.copy();
121 final PsiExpression
[] args
= copy
.getArgumentList().getExpressions();
122 for (int i
= 0; i
< args
.length
; i
++) {
123 PsiExpression arg
= args
[i
];
124 PsiType paramType
= i
< oldParameters
.length ? oldParameters
[i
].getType() : oldParameters
[oldParameters
.length
- 1].getType();
125 final PsiTypeCastExpression cast
= (PsiTypeCastExpression
)factory
.createExpressionFromText("(a)b", null);
126 final PsiTypeElement typeElement
= cast
.getCastType();
127 assert typeElement
!= null;
128 typeElement
.replace(factory
.createTypeElement(paramType
));
129 final PsiExpression operand
= cast
.getOperand();
130 assert operand
!= null;
131 operand
.replace(arg
);
135 for (int i
= 0; i
< copy
.getArgumentList().getExpressions().length
; i
++) {
136 PsiExpression oldarg
= call
.getArgumentList().getExpressions()[i
];
137 PsiTypeCastExpression cast
= (PsiTypeCastExpression
)copy
.getArgumentList().getExpressions()[i
];
138 if (!RedundantCastUtil
.isCastRedundant(cast
)) {
139 oldarg
.replace(cast
);