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 MemberHidesOuterMemberUsageInfo
) {
76 PsiJavaCodeReferenceElement collidingRef
= (PsiJavaCodeReferenceElement
)element
;
77 PsiMethod resolved
= (PsiMethod
)collidingRef
.resolve();
78 outerHides
.add(new MemberHidesOuterMemberUsageInfo(element
, resolved
));
80 else if (!(element
instanceof PsiMethod
)) {
81 final PsiReference ref
;
82 if (usage
instanceof MoveRenameUsageInfo
) {
83 ref
= usage
.getReference();
86 ref
= element
.getReference();
89 renamedReferences
.add(ref
.handleElementRename(newName
));
93 PsiMethod overrider
= (PsiMethod
)element
;
94 methodAndOverriders
.add(overrider
);
95 containingClasses
.add(overrider
.getContainingClass());
99 // do actual rename of method
100 method
.setName(newName
);
101 for (UsageInfo usage
: usages
) {
102 PsiElement element
= usage
.getElement();
103 if (element
instanceof PsiMethod
) {
104 ((PsiMethod
)element
).setName(newName
);
107 listener
.elementRenamed(method
);
109 for (PsiElement element
: renamedReferences
) {
110 fixNameCollisionsWithInnerClassMethod(element
, newName
, methodAndOverriders
, containingClasses
,
111 method
.hasModifierProperty(PsiModifier
.STATIC
));
113 qualifyOuterMemberReferences(outerHides
);
114 qualifyStaticImportReferences(staticImportHides
);
117 private static void fixNameCollisionsWithInnerClassMethod(final PsiElement element
, final String newName
,
118 final Set
<PsiMethod
> methodAndOverriders
, final Set
<PsiClass
> containingClasses
,
119 final boolean isStatic
) throws IncorrectOperationException
{
120 if (!(element
instanceof PsiReferenceExpression
)) return;
121 PsiElement elem
= ((PsiReferenceExpression
)element
).resolve();
123 if (elem
instanceof PsiMethod
) {
124 PsiMethod actualMethod
= (PsiMethod
) elem
;
125 if (!methodAndOverriders
.contains(actualMethod
)) {
126 PsiClass outerClass
= PsiTreeUtil
.getParentOfType(element
, PsiClass
.class);
127 while (outerClass
!= null) {
128 if (containingClasses
.contains(outerClass
)) {
129 qualifyMember(element
, newName
, outerClass
, isStatic
);
132 outerClass
= outerClass
.getContainingClass();
139 public Collection
<PsiReference
> findReferences(final PsiElement element
) {
140 GlobalSearchScope projectScope
= GlobalSearchScope
.projectScope(element
.getProject());
141 return MethodReferencesSearch
.search((PsiMethod
)element
, projectScope
, true).findAll();
144 public void findCollisions(final PsiElement element
, final String newName
, final Map
<?
extends PsiElement
, String
> allRenames
,
145 final List
<UsageInfo
> result
) {
146 final PsiMethod methodToRename
= (PsiMethod
)element
;
147 findSubmemberHidesMemberCollisions(methodToRename
, newName
, result
);
148 findMemberHidesOuterMemberCollisions((PsiMethod
) element
, newName
, result
);
151 public void findExistingNameConflicts(final PsiElement element
, final String newName
, final MultiMap
<PsiElement
, String
> conflicts
) {
152 if (element
instanceof PsiCompiledElement
) return;
153 PsiMethod refactoredMethod
= (PsiMethod
)element
;
154 if (newName
.equals(refactoredMethod
.getName())) return;
155 final PsiMethod prototype
= (PsiMethod
)refactoredMethod
.copy();
157 prototype
.setName(newName
);
159 catch (IncorrectOperationException e
) {
164 ConflictsUtil
.checkMethodConflicts(
165 refactoredMethod
.getContainingClass(),
171 public void prepareRenaming(final PsiElement element
, final String newName
, final Map
<PsiElement
, String
> allRenames
) {
172 final PsiMethod method
= (PsiMethod
) element
;
173 OverridingMethodsSearch
.search(method
, true).forEach(new Processor
<PsiMethod
>() {
174 public boolean process(PsiMethod overrider
) {
175 final String overriderName
= overrider
.getName();
176 final String baseName
= method
.getName();
177 final String newOverriderName
= RefactoringUtil
.suggestNewOverriderName(overriderName
, baseName
, newName
);
178 if (newOverriderName
!= null) {
179 allRenames
.put(overrider
, newOverriderName
);
187 public String
getHelpID(final PsiElement element
) {
188 return HelpID
.RENAME_METHOD
;
191 public boolean isToSearchInComments(final PsiElement psiElement
) {
192 return JavaRefactoringSettings
.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_METHOD
;
195 public void setToSearchInComments(final PsiElement element
, final boolean enabled
) {
196 JavaRefactoringSettings
.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_METHOD
= enabled
;
200 public PsiElement
substituteElementToRename(PsiElement element
, Editor editor
) {
201 PsiMethod psiMethod
= (PsiMethod
)element
;
202 if (psiMethod
.isConstructor()) {
203 PsiClass containingClass
= psiMethod
.getContainingClass();
204 if (containingClass
== null) return null;
205 element
= containingClass
;
206 if (!PsiElementRenameHandler
.canRename(element
.getProject(), editor
, element
)) {
211 return SuperMethodWarningUtil
.checkSuperMethod(psiMethod
, RefactoringBundle
.message("to.rename"));
214 private static void findSubmemberHidesMemberCollisions(final PsiMethod method
, final String newName
, final List
<UsageInfo
> result
) {
215 final PsiClass containingClass
= method
.getContainingClass();
216 if (containingClass
== null) return;
217 if (method
.hasModifierProperty(PsiModifier
.PRIVATE
)) return;
218 Collection
<PsiClass
> inheritors
= ClassInheritorsSearch
.search(containingClass
, containingClass
.getUseScope(), true).findAll();
220 MethodSignature oldSignature
= method
.getSignature(PsiSubstitutor
.EMPTY
);
221 MethodSignature newSignature
= MethodSignatureUtil
.createMethodSignature(newName
, oldSignature
.getParameterTypes(),
222 oldSignature
.getTypeParameters(),
223 oldSignature
.getSubstitutor());
224 for (PsiClass inheritor
: inheritors
) {
225 PsiSubstitutor superSubstitutor
= TypeConversionUtil
.getSuperClassSubstitutor(containingClass
, inheritor
, PsiSubstitutor
.EMPTY
);
226 final PsiMethod
[] methodsByName
= inheritor
.findMethodsByName(newName
, false);
227 for (PsiMethod conflictingMethod
: methodsByName
) {
228 if (newSignature
.equals(conflictingMethod
.getSignature(superSubstitutor
))) {
229 result
.add(new SubmemberHidesMemberUsageInfo(conflictingMethod
, method
));