update copyright
[fedora-idea.git] / java / java-impl / src / com / intellij / refactoring / rename / RenameJavaVariableProcessor.java
blobfd7280631e5d98df5a235da5c1175d2738464be0
1 /*
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;
43 import java.util.Map;
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,
53 final String newName,
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);
76 else {
77 // do nothing
80 else if (usage instanceof MemberHidesOuterMemberUsageInfo) {
81 PsiJavaCodeReferenceElement collidingRef = (PsiJavaCodeReferenceElement)element;
82 PsiField resolved = (PsiField)collidingRef.resolve();
83 outerHides.add(new MemberHidesOuterMemberUsageInfo(element, resolved));
85 else {
86 final PsiReference ref;
87 if (usage instanceof MoveRenameUsageInfo) {
88 ref = usage.getReference();
90 else {
91 ref = element.getReference();
93 if (ref != null) {
94 PsiElement newElem = ref.handleElementRename(newName);
95 if (variable instanceof PsiField) {
96 occurrencesToCheckForConflict.add(newElem);
101 // do actual rename
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...
121 return;
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)) {
163 getter = null;
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())) {
173 setter = null;
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)) {
183 getter = null;
184 setter = null;
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(),
243 newName,
244 conflicts
249 @Nullable
250 @NonNls
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;
261 return null;
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);
301 else { // Parameter
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));