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
.openapi
.application
.ApplicationManager
;
19 import com
.intellij
.openapi
.diagnostic
.Logger
;
20 import com
.intellij
.openapi
.project
.Project
;
21 import com
.intellij
.openapi
.ui
.Messages
;
22 import com
.intellij
.psi
.*;
23 import com
.intellij
.psi
.codeStyle
.JavaCodeStyleManager
;
24 import com
.intellij
.psi
.codeStyle
.VariableKind
;
25 import com
.intellij
.psi
.search
.searches
.ClassInheritorsSearch
;
26 import com
.intellij
.psi
.util
.PropertyUtil
;
27 import com
.intellij
.psi
.util
.PsiUtil
;
28 import com
.intellij
.psi
.util
.InheritanceUtil
;
29 import com
.intellij
.refactoring
.HelpID
;
30 import com
.intellij
.refactoring
.JavaRefactoringSettings
;
31 import com
.intellij
.refactoring
.RefactoringBundle
;
32 import com
.intellij
.refactoring
.listeners
.RefactoringElementListener
;
33 import com
.intellij
.refactoring
.util
.*;
34 import com
.intellij
.usageView
.UsageInfo
;
35 import com
.intellij
.util
.IncorrectOperationException
;
36 import com
.intellij
.util
.containers
.HashSet
;
37 import org
.jetbrains
.annotations
.NonNls
;
38 import org
.jetbrains
.annotations
.Nullable
;
40 import java
.util
.ArrayList
;
41 import java
.util
.Collection
;
42 import java
.util
.List
;
45 public class RenameJavaVariableProcessor
extends RenameJavaMemberProcessor
{
46 private static final Logger LOG
= Logger
.getInstance("#com.intellij.refactoring.rename.RenameJavaVariableProcessor");
48 public boolean canProcessElement(final PsiElement element
) {
49 return element
instanceof PsiVariable
;
52 public void renameElement(final PsiElement psiElement
,
54 final UsageInfo
[] usages
, final RefactoringElementListener listener
) throws IncorrectOperationException
{
55 PsiVariable variable
= (PsiVariable
) psiElement
;
56 List
<MemberHidesOuterMemberUsageInfo
> outerHides
= new ArrayList
<MemberHidesOuterMemberUsageInfo
>();
57 List
<MemberHidesStaticImportUsageInfo
> staticImportHides
= new ArrayList
<MemberHidesStaticImportUsageInfo
>();
59 if (variable
instanceof PsiField
) {
60 findCollisionsAgainstNewName((PsiField
) variable
, newName
, staticImportHides
);
63 List
<PsiElement
> occurrencesToCheckForConflict
= new ArrayList
<PsiElement
>();
64 // rename all references
65 for (UsageInfo usage
: usages
) {
66 final PsiElement element
= usage
.getElement();
67 if (element
== null) continue;
69 if (usage
instanceof LocalHidesFieldUsageInfo
) {
70 PsiJavaCodeReferenceElement collidingRef
= (PsiJavaCodeReferenceElement
)element
;
71 PsiElement resolved
= collidingRef
.resolve();
73 if (resolved
instanceof PsiField
) {
74 qualifyMember((PsiField
)resolved
, collidingRef
, newName
);
80 else if (usage
instanceof MemberHidesOuterMemberUsageInfo
) {
81 PsiJavaCodeReferenceElement collidingRef
= (PsiJavaCodeReferenceElement
)element
;
82 PsiField resolved
= (PsiField
)collidingRef
.resolve();
83 outerHides
.add(new MemberHidesOuterMemberUsageInfo(element
, resolved
));
86 final PsiReference ref
;
87 if (usage
instanceof MoveRenameUsageInfo
) {
88 ref
= usage
.getReference();
91 ref
= element
.getReference();
94 PsiElement newElem
= ref
.handleElementRename(newName
);
95 if (variable
instanceof PsiField
) {
96 occurrencesToCheckForConflict
.add(newElem
);
102 variable
.setName(newName
);
103 listener
.elementRenamed(variable
);
105 if (variable
instanceof PsiField
) {
106 for (PsiElement occurrence
: occurrencesToCheckForConflict
) {
107 fixPossibleNameCollisionsForFieldRenaming((PsiField
) variable
, newName
, occurrence
);
111 qualifyOuterMemberReferences(outerHides
);
112 qualifyStaticImportReferences(staticImportHides
);
115 private static void fixPossibleNameCollisionsForFieldRenaming(PsiField field
, String newName
, PsiElement replacedOccurence
) throws IncorrectOperationException
{
116 if (!(replacedOccurence
instanceof PsiReferenceExpression
)) return;
117 PsiElement elem
= ((PsiReferenceExpression
)replacedOccurence
).resolve();
119 if (elem
== null || elem
== field
) {
120 // If reference is unresolved, then field is not hidden by anyone...
124 if (elem
instanceof PsiLocalVariable
|| elem
instanceof PsiParameter
|| (elem
instanceof PsiField
&& elem
!= replacedOccurence
)) {
125 qualifyMember(field
, replacedOccurence
, newName
);
129 public void prepareRenaming(final PsiElement element
, final String newName
, final Map
<PsiElement
, String
> allRenames
) {
130 if (element
instanceof PsiField
) {
131 prepareFieldRenaming((PsiField
)element
, newName
, allRenames
);
135 private static void prepareFieldRenaming(PsiField field
, String newName
, final Map
<PsiElement
, String
> allRenames
) {
136 // search for getters/setters
137 PsiClass aClass
= field
.getContainingClass();
139 Project project
= field
.getProject();
140 final JavaCodeStyleManager manager
= JavaCodeStyleManager
.getInstance(project
);
142 final String propertyName
= manager
.variableNameToPropertyName(field
.getName(), VariableKind
.FIELD
);
143 String newPropertyName
= manager
.variableNameToPropertyName(newName
, VariableKind
.FIELD
);
145 boolean isStatic
= field
.hasModifierProperty(PsiModifier
.STATIC
);
146 PsiMethod getter
= PropertyUtil
.findPropertyGetter(aClass
, propertyName
, isStatic
, false);
147 PsiMethod setter
= PropertyUtil
.findPropertySetter(aClass
, propertyName
, isStatic
, false);
149 boolean shouldRenameSetterParameter
= false;
151 if (setter
!= null) {
152 String parameterName
= manager
.propertyNameToVariableName(propertyName
, VariableKind
.PARAMETER
);
153 PsiParameter setterParameter
= setter
.getParameterList().getParameters()[0];
154 shouldRenameSetterParameter
= parameterName
.equals(setterParameter
.getName());
157 String newGetterName
= "";
159 if (getter
!= null) {
160 String getterId
= getter
.getName();
161 newGetterName
= PropertyUtil
.suggestGetterName(newPropertyName
, field
.getType(), getterId
);
162 if (newGetterName
.equals(getterId
)) {
164 newGetterName
= null;
168 String newSetterName
= "";
169 if (setter
!= null) {
170 newSetterName
= PropertyUtil
.suggestSetterName(newPropertyName
);
171 final String newSetterParameterName
= manager
.propertyNameToVariableName(newPropertyName
, VariableKind
.PARAMETER
);
172 if (newSetterName
.equals(setter
.getName())) {
174 newSetterName
= null;
175 shouldRenameSetterParameter
= false;
177 else if (newSetterParameterName
.equals(setter
.getParameterList().getParameters()[0].getName())) {
178 shouldRenameSetterParameter
= false;
182 if ((getter
!= null || setter
!= null) && askToRenameAccesors(getter
, setter
, newName
, project
)) {
185 shouldRenameSetterParameter
= false;
188 if (getter
!= null) {
189 addOverriddenAndImplemented(aClass
, getter
, newGetterName
, allRenames
);
192 if (setter
!= null) {
193 addOverriddenAndImplemented(aClass
, setter
, newSetterName
, allRenames
);
196 if (shouldRenameSetterParameter
) {
197 PsiParameter parameter
= setter
.getParameterList().getParameters()[0];
198 allRenames
.put(parameter
, manager
.propertyNameToVariableName(newPropertyName
, VariableKind
.PARAMETER
));
202 private static boolean askToRenameAccesors(PsiMethod getter
, PsiMethod setter
, String newName
, final Project project
) {
203 if (ApplicationManager
.getApplication().isUnitTestMode()) return false;
204 String text
= RefactoringMessageUtil
.getGetterSetterMessage(newName
, RefactoringBundle
.message("rename.title"), getter
, setter
);
205 return Messages
.showYesNoDialog(project
, text
, RefactoringBundle
.message("rename.title"), Messages
.getQuestionIcon()) != 0;
208 private static void addOverriddenAndImplemented(PsiClass aClass
, PsiMethod methodPrototype
, String newName
,
209 final Map
<PsiElement
, String
> allRenames
) {
210 final HashSet
<PsiClass
> superClasses
= new HashSet
<PsiClass
>();
211 InheritanceUtil
.getSuperClasses(aClass
, superClasses
, true);
212 superClasses
.add(aClass
);
214 for (PsiClass superClass
: superClasses
) {
215 PsiMethod method
= superClass
.findMethodBySignature(methodPrototype
, false);
217 if (method
!= null) {
218 allRenames
.put(method
, newName
);
223 public void findCollisions(final PsiElement element
, final String newName
, final Map
<?
extends PsiElement
, String
> allRenames
,
224 final List
<UsageInfo
> result
) {
225 if (element
instanceof PsiField
) {
226 PsiField field
= (PsiField
) element
;
227 findMemberHidesOuterMemberCollisions(field
, newName
, result
);
228 findSubmemberHidesFieldCollisions(field
, newName
, result
);
230 else if (element
instanceof PsiLocalVariable
|| element
instanceof PsiParameter
) {
231 JavaUnresolvableLocalCollisionDetector
.findCollisions(element
, newName
, result
);
232 findLocalHidesFieldCollisions(element
, newName
, allRenames
, result
);
236 public void findExistingNameConflicts(final PsiElement element
, final String newName
, final Map
<PsiElement
, String
> conflicts
) {
237 if (element
instanceof PsiCompiledElement
) return;
238 if (element
instanceof PsiField
) {
239 PsiField refactoredField
= (PsiField
)element
;
240 if (newName
.equals(refactoredField
.getName())) return;
241 ConflictsUtil
.checkFieldConflicts(
242 refactoredField
.getContainingClass(),
251 public String
getHelpID(final PsiElement element
) {
252 if (element
instanceof PsiField
){
253 return HelpID
.RENAME_FIELD
;
255 else if (element
instanceof PsiLocalVariable
){
256 return HelpID
.RENAME_VARIABLE
;
258 else if (element
instanceof PsiParameter
){
259 return HelpID
.RENAME_PARAMETER
;
264 public boolean isToSearchInComments(final PsiElement element
) {
265 if (element
instanceof PsiField
){
266 return JavaRefactoringSettings
.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_FIELD
;
268 return JavaRefactoringSettings
.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_VARIABLE
;
271 public void setToSearchInComments(final PsiElement element
, final boolean enabled
) {
272 if (element
instanceof PsiField
){
273 JavaRefactoringSettings
.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_FIELD
= enabled
;
275 JavaRefactoringSettings
.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_VARIABLE
= enabled
;
278 private static void findSubmemberHidesFieldCollisions(final PsiField field
, final String newName
, final List
<UsageInfo
> result
) {
279 if (field
.getContainingClass() == null) return;
280 if (field
.hasModifierProperty(PsiModifier
.PRIVATE
)) return;
281 final PsiClass containingClass
= field
.getContainingClass();
282 Collection
<PsiClass
> inheritors
= ClassInheritorsSearch
.search(containingClass
, containingClass
.getUseScope(), true).findAll();
283 for (PsiClass inheritor
: inheritors
) {
284 PsiField conflictingField
= inheritor
.findFieldByName(newName
, false);
285 if (conflictingField
!= null) {
286 result
.add(new SubmemberHidesMemberUsageInfo(conflictingField
, field
));
291 private static void findLocalHidesFieldCollisions(final PsiElement element
, final String newName
, final Map
<?
extends PsiElement
, String
> allRenames
, final List
<UsageInfo
> result
) {
292 if (!(element
instanceof PsiLocalVariable
) && !(element
instanceof PsiParameter
)) return;
294 PsiClass toplevel
= PsiUtil
.getTopLevelClass(element
);
295 if (toplevel
== null) return;
297 PsiElement scopeElement
;
298 if (element
instanceof PsiLocalVariable
) {
299 scopeElement
= RefactoringUtil
.getVariableScope((PsiLocalVariable
)element
);
302 scopeElement
= ((PsiParameter
) element
).getDeclarationScope();
305 LOG
.assertTrue(scopeElement
!= null);
306 scopeElement
.accept(new JavaRecursiveElementWalkingVisitor() {
307 @Override public void visitReferenceExpression(PsiReferenceExpression expression
) {
308 super.visitReferenceExpression(expression
);
309 if (!expression
.isQualified()) {
310 PsiElement resolved
= expression
.resolve();
311 if (resolved
instanceof PsiField
) {
312 final PsiField field
= (PsiField
)resolved
;
313 String fieldNewName
= allRenames
.containsKey(field
) ? allRenames
.get(field
) : field
.getName();
314 if (newName
.equals(fieldNewName
)) {
315 result
.add(new LocalHidesFieldUsageInfo(expression
, element
));