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
.rename
;
18 import com
.intellij
.ide
.util
.SuperMethodWarningUtil
;
19 import com
.intellij
.openapi
.diagnostic
.Logger
;
20 import com
.intellij
.openapi
.editor
.Editor
;
21 import com
.intellij
.psi
.*;
22 import com
.intellij
.psi
.search
.GlobalSearchScope
;
23 import com
.intellij
.psi
.search
.searches
.ClassInheritorsSearch
;
24 import com
.intellij
.psi
.search
.searches
.MethodReferencesSearch
;
25 import com
.intellij
.psi
.search
.searches
.OverridingMethodsSearch
;
26 import com
.intellij
.psi
.util
.MethodSignature
;
27 import com
.intellij
.psi
.util
.MethodSignatureUtil
;
28 import com
.intellij
.psi
.util
.PsiTreeUtil
;
29 import com
.intellij
.psi
.util
.TypeConversionUtil
;
30 import com
.intellij
.refactoring
.HelpID
;
31 import com
.intellij
.refactoring
.JavaRefactoringSettings
;
32 import com
.intellij
.refactoring
.RefactoringBundle
;
33 import com
.intellij
.refactoring
.listeners
.RefactoringElementListener
;
34 import com
.intellij
.refactoring
.util
.ConflictsUtil
;
35 import com
.intellij
.refactoring
.util
.MoveRenameUsageInfo
;
36 import com
.intellij
.refactoring
.util
.RefactoringUtil
;
37 import com
.intellij
.usageView
.UsageInfo
;
38 import com
.intellij
.util
.IncorrectOperationException
;
39 import com
.intellij
.util
.Processor
;
40 import com
.intellij
.util
.containers
.HashSet
;
41 import com
.intellij
.util
.containers
.MultiMap
;
42 import org
.jetbrains
.annotations
.NonNls
;
43 import org
.jetbrains
.annotations
.NotNull
;
44 import org
.jetbrains
.annotations
.Nullable
;
48 public class RenameJavaMethodProcessor
extends RenameJavaMemberProcessor
{
49 private static final Logger LOG
= Logger
.getInstance("#com.intellij.refactoring.rename.RenameJavaMethodProcessor");
51 public boolean canProcessElement(final PsiElement element
) {
52 return element
instanceof PsiMethod
;
55 public void renameElement(final PsiElement psiElement
,
57 final UsageInfo
[] usages
, final RefactoringElementListener listener
) throws IncorrectOperationException
{
58 PsiMethod method
= (PsiMethod
) psiElement
;
59 Set
<PsiMethod
> methodAndOverriders
= new HashSet
<PsiMethod
>();
60 Set
<PsiClass
> containingClasses
= new HashSet
<PsiClass
>();
61 List
<PsiElement
> renamedReferences
= new ArrayList
<PsiElement
>();
62 List
<MemberHidesOuterMemberUsageInfo
> outerHides
= new ArrayList
<MemberHidesOuterMemberUsageInfo
>();
63 List
<MemberHidesStaticImportUsageInfo
> staticImportHides
= new ArrayList
<MemberHidesStaticImportUsageInfo
>();
65 methodAndOverriders
.add(method
);
66 containingClasses
.add(method
.getContainingClass());
68 findCollisionsAgainstNewName(method
, newName
, staticImportHides
);
70 // do actual rename of overriding/implementing methods and of references to all them
71 for (UsageInfo usage
: usages
) {
72 PsiElement element
= usage
.getElement();
73 if (element
== null) continue;
75 if (usage
instanceof MemberHidesStaticImportUsageInfo
) {
76 staticImportHides
.add((MemberHidesStaticImportUsageInfo
)usage
);
77 } else if (usage
instanceof MemberHidesOuterMemberUsageInfo
) {
78 PsiJavaCodeReferenceElement collidingRef
= (PsiJavaCodeReferenceElement
)element
;
79 PsiMethod resolved
= (PsiMethod
)collidingRef
.resolve();
80 outerHides
.add(new MemberHidesOuterMemberUsageInfo(element
, resolved
));
82 else if (!(element
instanceof PsiMethod
)) {
83 final PsiReference ref
;
84 if (usage
instanceof MoveRenameUsageInfo
) {
85 ref
= usage
.getReference();
88 ref
= element
.getReference();
91 renamedReferences
.add(ref
.handleElementRename(newName
));
95 PsiMethod overrider
= (PsiMethod
)element
;
96 methodAndOverriders
.add(overrider
);
97 containingClasses
.add(overrider
.getContainingClass());
101 // do actual rename of method
102 method
.setName(newName
);
103 for (UsageInfo usage
: usages
) {
104 PsiElement element
= usage
.getElement();
105 if (element
instanceof PsiMethod
) {
106 ((PsiMethod
)element
).setName(newName
);
109 listener
.elementRenamed(method
);
111 for (PsiElement element
: renamedReferences
) {
112 fixNameCollisionsWithInnerClassMethod(element
, newName
, methodAndOverriders
, containingClasses
,
113 method
.hasModifierProperty(PsiModifier
.STATIC
));
115 qualifyOuterMemberReferences(outerHides
);
116 qualifyStaticImportReferences(staticImportHides
);
119 private static void fixNameCollisionsWithInnerClassMethod(final PsiElement element
, final String newName
,
120 final Set
<PsiMethod
> methodAndOverriders
, final Set
<PsiClass
> containingClasses
,
121 final boolean isStatic
) throws IncorrectOperationException
{
122 if (!(element
instanceof PsiReferenceExpression
)) return;
123 PsiElement elem
= ((PsiReferenceExpression
)element
).resolve();
125 if (elem
instanceof PsiMethod
) {
126 PsiMethod actualMethod
= (PsiMethod
) elem
;
127 if (!methodAndOverriders
.contains(actualMethod
)) {
128 PsiClass outerClass
= PsiTreeUtil
.getParentOfType(element
, PsiClass
.class);
129 while (outerClass
!= null) {
130 if (containingClasses
.contains(outerClass
)) {
131 qualifyMember(element
, newName
, outerClass
, isStatic
);
134 outerClass
= outerClass
.getContainingClass();
141 public Collection
<PsiReference
> findReferences(final PsiElement element
) {
142 GlobalSearchScope projectScope
= GlobalSearchScope
.projectScope(element
.getProject());
143 return MethodReferencesSearch
.search((PsiMethod
)element
, projectScope
, true).findAll();
146 public void findCollisions(final PsiElement element
, final String newName
, final Map
<?
extends PsiElement
, String
> allRenames
,
147 final List
<UsageInfo
> result
) {
148 final PsiMethod methodToRename
= (PsiMethod
)element
;
149 findSubmemberHidesMemberCollisions(methodToRename
, newName
, result
);
150 findMemberHidesOuterMemberCollisions((PsiMethod
) element
, newName
, result
);
151 findCollisionsAgainstNewName(methodToRename
, newName
, result
);
154 public void findExistingNameConflicts(final PsiElement element
, final String newName
, final MultiMap
<PsiElement
, String
> conflicts
) {
155 if (element
instanceof PsiCompiledElement
) return;
156 PsiMethod refactoredMethod
= (PsiMethod
)element
;
157 if (newName
.equals(refactoredMethod
.getName())) return;
158 final PsiMethod prototype
= (PsiMethod
)refactoredMethod
.copy();
160 prototype
.setName(newName
);
162 catch (IncorrectOperationException e
) {
167 ConflictsUtil
.checkMethodConflicts(
168 refactoredMethod
.getContainingClass(),
174 public void prepareRenaming(final PsiElement element
, final String newName
, final Map
<PsiElement
, String
> allRenames
) {
175 final PsiMethod method
= (PsiMethod
) element
;
176 OverridingMethodsSearch
.search(method
, true).forEach(new Processor
<PsiMethod
>() {
177 public boolean process(PsiMethod overrider
) {
178 final String overriderName
= overrider
.getName();
179 final String baseName
= method
.getName();
180 final String newOverriderName
= RefactoringUtil
.suggestNewOverriderName(overriderName
, baseName
, newName
);
181 if (newOverriderName
!= null) {
182 allRenames
.put(overrider
, newOverriderName
);
190 public String
getHelpID(final PsiElement element
) {
191 return HelpID
.RENAME_METHOD
;
194 public boolean isToSearchInComments(final PsiElement psiElement
) {
195 return JavaRefactoringSettings
.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_METHOD
;
198 public void setToSearchInComments(final PsiElement element
, final boolean enabled
) {
199 JavaRefactoringSettings
.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_METHOD
= enabled
;
203 public PsiElement
substituteElementToRename(PsiElement element
, Editor editor
) {
204 PsiMethod psiMethod
= (PsiMethod
)element
;
205 if (psiMethod
.isConstructor()) {
206 PsiClass containingClass
= psiMethod
.getContainingClass();
207 if (containingClass
== null) return null;
208 element
= containingClass
;
209 if (!PsiElementRenameHandler
.canRename(element
.getProject(), editor
, element
)) {
214 return SuperMethodWarningUtil
.checkSuperMethod(psiMethod
, RefactoringBundle
.message("to.rename"));
217 private static void findSubmemberHidesMemberCollisions(final PsiMethod method
, final String newName
, final List
<UsageInfo
> result
) {
218 final PsiClass containingClass
= method
.getContainingClass();
219 if (containingClass
== null) return;
220 if (method
.hasModifierProperty(PsiModifier
.PRIVATE
)) return;
221 Collection
<PsiClass
> inheritors
= ClassInheritorsSearch
.search(containingClass
, containingClass
.getUseScope(), true).findAll();
223 MethodSignature oldSignature
= method
.getSignature(PsiSubstitutor
.EMPTY
);
224 MethodSignature newSignature
= MethodSignatureUtil
.createMethodSignature(newName
, oldSignature
.getParameterTypes(),
225 oldSignature
.getTypeParameters(),
226 oldSignature
.getSubstitutor());
227 for (PsiClass inheritor
: inheritors
) {
228 PsiSubstitutor superSubstitutor
= TypeConversionUtil
.getSuperClassSubstitutor(containingClass
, inheritor
, PsiSubstitutor
.EMPTY
);
229 final PsiMethod
[] methodsByName
= inheritor
.findMethodsByName(newName
, false);
230 for (PsiMethod conflictingMethod
: methodsByName
) {
231 if (newSignature
.equals(conflictingMethod
.getSignature(superSubstitutor
))) {
232 result
.add(new SubmemberHidesMemberUsageInfo(conflictingMethod
, method
));