rename conflict: local variable hided by a field in an inner class (IDEA-20700)
[fedora-idea.git] / java / java-impl / src / com / intellij / refactoring / changeSignature / ChangeSignatureProcessor.java
blob909b200d8e67d2baa23a288b11cce7e4ffea8248
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.
17 /**
18 * created at Sep 17, 2001
19 * @author Jeka
21 package com.intellij.refactoring.changeSignature;
23 import com.intellij.codeInsight.ExceptionUtil;
24 import com.intellij.openapi.application.ApplicationManager;
25 import com.intellij.openapi.diagnostic.Logger;
26 import com.intellij.openapi.project.Project;
27 import com.intellij.openapi.ui.DialogWrapper;
28 import com.intellij.openapi.ui.Messages;
29 import com.intellij.openapi.util.Comparing;
30 import com.intellij.openapi.util.Ref;
31 import com.intellij.psi.*;
32 import com.intellij.psi.codeStyle.CodeStyleManager;
33 import com.intellij.psi.codeStyle.JavaCodeStyleManager;
34 import com.intellij.psi.codeStyle.VariableKind;
35 import com.intellij.psi.javadoc.PsiDocTagValue;
36 import com.intellij.psi.scope.processor.VariablesProcessor;
37 import com.intellij.psi.scope.util.PsiScopesUtil;
38 import com.intellij.psi.search.GlobalSearchScope;
39 import com.intellij.psi.search.searches.MethodReferencesSearch;
40 import com.intellij.psi.search.searches.OverridingMethodsSearch;
41 import com.intellij.psi.search.searches.ReferencesSearch;
42 import com.intellij.psi.util.*;
43 import com.intellij.psi.xml.XmlElement;
44 import com.intellij.refactoring.BaseRefactoringProcessor;
45 import com.intellij.refactoring.RefactoringBundle;
46 import com.intellij.refactoring.rename.JavaUnresolvableLocalCollisionDetector;
47 import com.intellij.refactoring.rename.RenameUtil;
48 import com.intellij.refactoring.rename.UnresolvableCollisionUsageInfo;
49 import com.intellij.refactoring.ui.ConflictsDialog;
50 import com.intellij.refactoring.util.*;
51 import com.intellij.refactoring.util.usageInfo.DefaultConstructorImplicitUsageInfo;
52 import com.intellij.refactoring.util.usageInfo.NoConstructorClassUsageInfo;
53 import com.intellij.usageView.UsageInfo;
54 import com.intellij.usageView.UsageViewDescriptor;
55 import com.intellij.usageView.UsageViewUtil;
56 import com.intellij.util.IncorrectOperationException;
57 import com.intellij.util.VisibilityUtil;
58 import com.intellij.util.containers.HashSet;
59 import com.intellij.util.containers.MultiMap;
60 import org.jetbrains.annotations.NotNull;
62 import java.util.*;
64 public class ChangeSignatureProcessor extends BaseRefactoringProcessor {
65 private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.changeSignature.ChangeSignatureProcessor");
67 @Modifier private final String myNewVisibility;
68 private final ChangeInfoImpl myChangeInfo;
69 private final PsiManager myManager;
70 private final PsiElementFactory myFactory;
71 private final boolean myGenerateDelegate;
72 private final Set<PsiMethod> myPropagateParametersMethods;
73 private final Set<PsiMethod> myPropagateExceptionsMethods;
75 public ChangeSignatureProcessor(Project project,
76 PsiMethod method,
77 final boolean generateDelegate,
78 @Modifier String newVisibility,
79 String newName,
80 PsiType newType,
81 @NotNull ParameterInfoImpl[] parameterInfo) {
82 this(project, method, generateDelegate, newVisibility, newName,
83 newType != null ? CanonicalTypes.createTypeWrapper(newType) : null,
84 parameterInfo, null, null, null);
87 public ChangeSignatureProcessor(Project project,
88 PsiMethod method,
89 final boolean generateDelegate,
90 String newVisibility,
91 String newName,
92 PsiType newType,
93 ParameterInfoImpl[] parameterInfo,
94 ThrownExceptionInfo[] exceptionInfos) {
95 this(project, method, generateDelegate, newVisibility, newName,
96 newType != null ? CanonicalTypes.createTypeWrapper(newType) : null,
97 parameterInfo, exceptionInfos, null, null);
100 public ChangeSignatureProcessor(Project project,
101 PsiMethod method,
102 boolean generateDelegate,
103 String newVisibility,
104 String newName,
105 CanonicalTypes.Type newType,
106 @NotNull ParameterInfoImpl[] parameterInfo,
107 ThrownExceptionInfo[] thrownExceptions,
108 Set<PsiMethod> propagateParametersMethods,
109 Set<PsiMethod> propagateExceptionsMethods) {
110 super(project);
111 myManager = PsiManager.getInstance(project);
112 myFactory = JavaPsiFacade.getInstance(myManager.getProject()).getElementFactory();
113 myGenerateDelegate = generateDelegate;
115 myPropagateParametersMethods = propagateParametersMethods != null ? propagateParametersMethods : new HashSet<PsiMethod>();
116 myPropagateExceptionsMethods = propagateExceptionsMethods != null ? propagateExceptionsMethods : new HashSet<PsiMethod>();
118 LOG.assertTrue(method.isValid());
119 if (newVisibility == null) {
120 myNewVisibility = VisibilityUtil.getVisibilityModifier(method.getModifierList());
121 } else {
122 myNewVisibility = newVisibility;
125 myChangeInfo = new ChangeInfoImpl(myNewVisibility, method, newName, newType, parameterInfo, thrownExceptions);
126 LOG.assertTrue(myChangeInfo.getMethod().isValid());
129 protected UsageViewDescriptor createUsageViewDescriptor(UsageInfo[] usages) {
130 return new ChangeSignatureViewDescriptor(myChangeInfo.getMethod());
133 @NotNull
134 protected UsageInfo[] findUsages() {
135 ArrayList<UsageInfo> result = new ArrayList<UsageInfo>();
136 final PsiMethod method = myChangeInfo.getMethod();
138 findSimpleUsages(method, result);
140 final UsageInfo[] usageInfos = result.toArray(new UsageInfo[result.size()]);
141 return UsageViewUtil.removeDuplicatedUsages(usageInfos);
144 private void findSimpleUsages(final PsiMethod method, final ArrayList<UsageInfo> result) {
145 PsiMethod[] overridingMethods = findSimpleUsagesWithoutParameters(method, result, true, true, true);
146 findUsagesInCallers (result);
148 //Parameter name changes are not propagated
149 findParametersUsage(method, result, overridingMethods);
152 private PsiMethod[] findSimpleUsagesWithoutParameters(final PsiMethod method,
153 final ArrayList<UsageInfo> result,
154 boolean isToModifyArgs,
155 boolean isToThrowExceptions,
156 boolean isOriginal) {
158 GlobalSearchScope projectScope = GlobalSearchScope.projectScope(myProject);
159 PsiMethod[] overridingMethods = OverridingMethodsSearch.search(method, method.getUseScope(), true).toArray(PsiMethod.EMPTY_ARRAY);
161 for (PsiMethod overridingMethod : overridingMethods) {
162 result.add(new OverriderUsageInfo(overridingMethod, method, isOriginal, isToModifyArgs, isToThrowExceptions));
165 boolean needToChangeCalls = !myGenerateDelegate && (myChangeInfo.isNameChanged || myChangeInfo.isParameterSetOrOrderChanged || myChangeInfo.isExceptionSetOrOrderChanged || myChangeInfo.isVisibilityChanged/*for checking inaccessible*/);
166 if (needToChangeCalls) {
167 int parameterCount = method.getParameterList().getParametersCount();
169 PsiReference[] refs = MethodReferencesSearch.search(method, projectScope, true).toArray(PsiReference.EMPTY_ARRAY);
170 for (PsiReference ref : refs) {
171 PsiElement element = ref.getElement();
172 boolean isToCatchExceptions = isToThrowExceptions && needToCatchExceptions(RefactoringUtil.getEnclosingMethod(element));
173 if (!isToCatchExceptions) {
174 if (RefactoringUtil.isMethodUsage(element)) {
175 PsiExpressionList list = RefactoringUtil.getArgumentListByMethodReference(element);
176 if (!method.isVarArgs() && list.getExpressions().length != parameterCount) continue;
179 if (RefactoringUtil.isMethodUsage(element)) {
180 result.add(new MethodCallUsageInfo(element, isToModifyArgs, isToCatchExceptions));
182 else if (element instanceof PsiDocTagValue) {
183 result.add(new UsageInfo(ref.getElement()));
185 else if (element instanceof PsiMethod && ((PsiMethod)element).isConstructor()) {
186 DefaultConstructorImplicitUsageInfo implicitUsageInfo = new DefaultConstructorImplicitUsageInfo((PsiMethod)element,
187 ((PsiMethod)element).getContainingClass(), method);
188 result.add(implicitUsageInfo);
190 else if(element instanceof PsiClass) {
191 LOG.assertTrue(method.isConstructor());
192 final PsiClass psiClass = (PsiClass)element;
193 if (shouldPropagateToNonPhysicalMethod(method, result, psiClass, myPropagateParametersMethods)) continue;
194 if (shouldPropagateToNonPhysicalMethod(method, result, psiClass, myPropagateExceptionsMethods)) continue;
195 result.add(new NoConstructorClassUsageInfo(psiClass));
197 else if (ref instanceof PsiCallReference) {
198 result.add(new CallReferenceUsageInfo((PsiCallReference) ref));
200 else {
201 result.add(new MoveRenameUsageInfo(element, ref, method));
205 //if (method.isConstructor() && parameterCount == 0) {
206 // RefactoringUtil.visitImplicitConstructorUsages(method.getContainingClass(),
207 // new DefaultConstructorUsageCollector(result));
210 else if (myChangeInfo.isParameterTypesChanged) {
211 PsiReference[] refs = MethodReferencesSearch.search(method, projectScope, true).toArray(PsiReference.EMPTY_ARRAY);
212 for (PsiReference reference : refs) {
213 final PsiElement element = reference.getElement();
214 if (element instanceof PsiDocTagValue) {
215 result.add(new UsageInfo(reference));
217 else if (element instanceof XmlElement) {
218 result.add(new MoveRenameUsageInfo(reference, method));
223 // Conflicts
224 detectLocalsCollisionsInMethod(method, result, isOriginal);
225 for (final PsiMethod overridingMethod : overridingMethods) {
226 detectLocalsCollisionsInMethod(overridingMethod, result, isOriginal);
229 return overridingMethods;
232 private static boolean shouldPropagateToNonPhysicalMethod(PsiMethod method, ArrayList<UsageInfo> result, PsiClass containingClass, final Set<PsiMethod> propagateMethods) {
233 for (PsiMethod psiMethod : propagateMethods) {
234 if (!psiMethod.isPhysical() && Comparing.strEqual(psiMethod.getName(), containingClass.getName())) {
235 result.add(new DefaultConstructorImplicitUsageInfo(psiMethod, containingClass, method));
236 return true;
239 return false;
242 private void findUsagesInCallers(final ArrayList<UsageInfo> usages) {
243 for (PsiMethod caller : myPropagateParametersMethods) {
244 usages.add(new CallerUsageInfo(caller, true, myPropagateExceptionsMethods.contains(caller)));
246 for (PsiMethod caller : myPropagateExceptionsMethods) {
247 usages.add(new CallerUsageInfo(caller, myPropagateParametersMethods.contains(caller), true));
249 Set<PsiMethod> merged = new HashSet<PsiMethod>();
250 merged.addAll(myPropagateParametersMethods);
251 merged.addAll(myPropagateExceptionsMethods);
252 for (final PsiMethod method : merged) {
253 findSimpleUsagesWithoutParameters(method, usages, myPropagateParametersMethods.contains(method),
254 myPropagateExceptionsMethods.contains(method), false);
258 private boolean needToChangeCalls() {
259 return myChangeInfo.isNameChanged || myChangeInfo.isParameterSetOrOrderChanged || myChangeInfo.isExceptionSetOrOrderChanged;
262 private boolean needToCatchExceptions(PsiMethod caller) {
263 return myChangeInfo.isExceptionSetOrOrderChanged && !myPropagateExceptionsMethods.contains(caller);
266 private void detectLocalsCollisionsInMethod(final PsiMethod method,
267 final ArrayList<UsageInfo> result,
268 boolean isOriginal) {
269 final PsiParameter[] parameters = method.getParameterList().getParameters();
270 final Set<PsiParameter> deletedOrRenamedParameters = new HashSet<PsiParameter>();
271 if (isOriginal) {
272 deletedOrRenamedParameters.addAll(Arrays.asList(parameters));
273 for (ParameterInfoImpl parameterInfo : myChangeInfo.newParms) {
274 if (parameterInfo.oldParameterIndex >= 0) {
275 final PsiParameter parameter = parameters[parameterInfo.oldParameterIndex];
276 if (parameterInfo.getName().equals(parameter.getName())) {
277 deletedOrRenamedParameters.remove(parameter);
283 for (ParameterInfoImpl parameterInfo : myChangeInfo.newParms) {
284 final int oldParameterIndex = parameterInfo.oldParameterIndex;
285 final String newName = parameterInfo.getName();
286 if (oldParameterIndex >= 0) {
287 if (isOriginal) { //Name changes take place only in primary method
288 final PsiParameter parameter = parameters[oldParameterIndex];
289 if (!newName.equals(parameter.getName())) {
290 JavaUnresolvableLocalCollisionDetector.visitLocalsCollisions(parameter, newName, method.getBody(), null, new JavaUnresolvableLocalCollisionDetector.CollidingVariableVisitor() {
291 public void visitCollidingElement(final PsiVariable collidingVariable) {
292 if (!deletedOrRenamedParameters.contains(collidingVariable)) {
293 result.add(new RenamedParameterCollidesWithLocalUsageInfo(parameter, collidingVariable, method));
300 else {
301 JavaUnresolvableLocalCollisionDetector.visitLocalsCollisions(method, newName, method.getBody(), null, new JavaUnresolvableLocalCollisionDetector.CollidingVariableVisitor() {
302 public void visitCollidingElement(PsiVariable collidingVariable) {
303 if (!deletedOrRenamedParameters.contains(collidingVariable)) {
304 result.add(new NewParameterCollidesWithLocalUsageInfo(collidingVariable, collidingVariable, method));
312 private void findParametersUsage(final PsiMethod method, ArrayList<UsageInfo> result, PsiMethod[] overriders) {
313 PsiParameter[] parameters = method.getParameterList().getParameters();
314 for (ParameterInfoImpl info : myChangeInfo.newParms) {
315 if (info.oldParameterIndex >= 0) {
316 PsiParameter parameter = parameters[info.oldParameterIndex];
317 if (!info.getName().equals(parameter.getName())) {
318 addParameterUsages(parameter, result, info);
320 for (PsiMethod overrider : overriders) {
321 PsiParameter parameter1 = overrider.getParameterList().getParameters()[info.oldParameterIndex];
322 if (parameter.getName().equals(parameter1.getName())) {
323 addParameterUsages(parameter1, result, info);
331 protected void refreshElements(PsiElement[] elements) {
332 boolean condition = elements.length == 1 && elements[0] instanceof PsiMethod;
333 LOG.assertTrue(condition);
334 myChangeInfo.updateMethod((PsiMethod) elements[0]);
337 private void addMethodConflicts(MultiMap<PsiElement, String> conflicts) {
338 String newMethodName = myChangeInfo.newName;
340 try {
341 PsiMethod prototype;
342 PsiManager manager = PsiManager.getInstance(myProject);
343 PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory();
344 final PsiMethod method = myChangeInfo.getMethod();
345 final CanonicalTypes.Type returnType = myChangeInfo.newReturnType;
346 if (returnType != null) {
347 prototype = factory.createMethod(newMethodName, returnType.getType(method, manager));
349 else {
350 prototype = factory.createConstructor();
351 prototype.setName(newMethodName);
353 ParameterInfoImpl[] parameters = myChangeInfo.newParms;
356 for (ParameterInfoImpl info : parameters) {
357 final PsiType parameterType = info.createType(method, manager);
358 PsiParameter param = factory.createParameter(info.getName(), parameterType);
359 prototype.getParameterList().add(param);
362 ConflictsUtil.checkMethodConflicts(
363 method.getContainingClass(),
364 method,
365 prototype, conflicts);
367 catch (IncorrectOperationException e) {
368 LOG.error(e);
373 protected boolean preprocessUsages(Ref<UsageInfo[]> refUsages) {
374 MultiMap<PsiElement, String> conflictDescriptions = new MultiMap<PsiElement, String>();
375 UsageInfo[] usagesIn = refUsages.get();
376 addMethodConflicts(conflictDescriptions);
377 RenameUtil.addConflictDescriptions(usagesIn, conflictDescriptions);
378 Set<UsageInfo> usagesSet = new HashSet<UsageInfo>(Arrays.asList(usagesIn));
379 RenameUtil.removeConflictUsages(usagesSet);
380 if (myChangeInfo.isVisibilityChanged) {
381 try {
382 addInaccessibilityDescriptions(usagesSet, conflictDescriptions);
384 catch (IncorrectOperationException e) {
385 LOG.error(e);
389 if (myPrepareSuccessfulSwingThreadCallback != null && !conflictDescriptions.isEmpty()) {
390 ConflictsDialog dialog = new ConflictsDialog(myProject, conflictDescriptions);
391 dialog.show();
392 if (!dialog.isOK()){
393 if (dialog.isShowConflicts()) prepareSuccessful();
394 return false;
398 if (myChangeInfo.isReturnTypeChanged) {
399 askToRemoveCovariantOverriders (usagesSet);
402 refUsages.set(usagesSet.toArray(new UsageInfo[usagesSet.size()]));
403 prepareSuccessful();
404 return true;
407 private void addInaccessibilityDescriptions(Set<UsageInfo> usages, MultiMap<PsiElement, String> conflictDescriptions) throws IncorrectOperationException {
408 PsiMethod method = myChangeInfo.getMethod();
409 PsiModifierList modifierList = (PsiModifierList)method.getModifierList().copy();
410 VisibilityUtil.setVisibility(modifierList, myNewVisibility);
412 for (Iterator<UsageInfo> iterator = usages.iterator(); iterator.hasNext();) {
413 UsageInfo usageInfo = iterator.next();
414 PsiElement element = usageInfo.getElement();
415 if (element != null) {
416 if (element instanceof PsiReferenceExpression) {
417 PsiClass accessObjectClass = null;
418 PsiExpression qualifier = ((PsiReferenceExpression)element).getQualifierExpression();
419 if (qualifier != null) {
420 accessObjectClass = (PsiClass)PsiUtil.getAccessObjectClass(qualifier).getElement();
423 if (!JavaPsiFacade.getInstance(element.getProject()).getResolveHelper()
424 .isAccessible(method, modifierList, element, accessObjectClass, null)) {
425 String message =
426 RefactoringBundle.message("0.with.1.visibility.is.not.accesible.from.2",
427 RefactoringUIUtil.getDescription(method, true),
428 myNewVisibility,
429 RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(element), true));
430 conflictDescriptions.putValue(method, message);
431 if (!needToChangeCalls()) {
432 iterator.remove();
440 private void askToRemoveCovariantOverriders(Set<UsageInfo> usages) {
441 if (PsiUtil.isLanguageLevel5OrHigher(myChangeInfo.getMethod())) {
442 List<UsageInfo> covariantOverriderInfos = new ArrayList<UsageInfo>();
443 for (UsageInfo usageInfo : usages) {
444 if (usageInfo instanceof OverriderUsageInfo) {
445 final OverriderUsageInfo info = (OverriderUsageInfo)usageInfo;
446 PsiMethod overrider = info.getElement();
447 PsiMethod baseMethod = info.getBaseMethod();
448 PsiSubstitutor substitutor = calculateSubstitutor(overrider, baseMethod);
449 PsiType type;
450 try {
451 type = substitutor.substitute(myChangeInfo.newReturnType.getType(myChangeInfo.getMethod(), myManager));
453 catch (IncorrectOperationException e) {
454 LOG.error(e);
455 return;
457 final PsiType overriderType = overrider.getReturnType();
458 if (overriderType != null && type.isAssignableFrom(overriderType)) {
459 covariantOverriderInfos.add(usageInfo);
464 // to be able to do filtering
465 preprocessCovariantOverriders(covariantOverriderInfos);
467 if (!covariantOverriderInfos.isEmpty()) {
468 if (ApplicationManager.getApplication().isUnitTestMode() || !isProcessCovariantOverriders()) {
469 for (UsageInfo usageInfo : covariantOverriderInfos) {
470 usages.remove(usageInfo);
477 protected void preprocessCovariantOverriders(final List<UsageInfo> covariantOverriderInfos) {
480 protected boolean isProcessCovariantOverriders() {
481 return Messages.showYesNoDialog(myProject, RefactoringBundle.message("do.you.want.to.process.overriding.methods.with.covariant.return.type"),
482 ChangeSignatureHandler.REFACTORING_NAME, Messages.getQuestionIcon())
483 == DialogWrapper.OK_EXIT_CODE;
486 protected void performRefactoring(UsageInfo[] usages) {
487 PsiElementFactory factory = JavaPsiFacade.getInstance(myManager.getProject()).getElementFactory();
489 try {
490 if (myChangeInfo.isNameChanged) {
491 myChangeInfo.newNameIdentifier = factory.createIdentifier(myChangeInfo.newName);
494 if (myChangeInfo.isReturnTypeChanged) {
495 myChangeInfo.newTypeElement = myChangeInfo.newReturnType.getType(myChangeInfo.getMethod(), myManager);
498 if (myGenerateDelegate) {
499 generateDelegate();
502 for (UsageInfo usage : usages) {
503 if (usage instanceof CallerUsageInfo) {
504 final CallerUsageInfo callerUsageInfo = (CallerUsageInfo)usage;
505 processCallerMethod(callerUsageInfo.getMethod(), null, callerUsageInfo.isToInsertParameter(),
506 callerUsageInfo.isToInsertException());
508 else if (usage instanceof OverriderUsageInfo) {
509 OverriderUsageInfo info = (OverriderUsageInfo)usage;
510 final PsiMethod method = info.getElement();
511 final PsiMethod baseMethod = info.getBaseMethod();
512 if (info.isOriginalOverrider()) {
513 processPrimaryMethod(method, baseMethod, false);
515 else {
516 processCallerMethod(method, baseMethod, info.isToInsertArgs(), info.isToCatchExceptions());
521 LOG.assertTrue(myChangeInfo.getMethod().isValid());
522 processPrimaryMethod(myChangeInfo.getMethod(), null, true);
523 List<UsageInfo> postponedUsages = new ArrayList<UsageInfo>();
525 for (UsageInfo usage : usages) {
526 PsiElement element = usage.getElement();
527 if (element == null) continue;
529 if (usage instanceof DefaultConstructorImplicitUsageInfo) {
530 final DefaultConstructorImplicitUsageInfo defConstructorUsage = (DefaultConstructorImplicitUsageInfo)usage;
531 PsiMethod constructor = defConstructorUsage.getConstructor();
532 if (!constructor.isPhysical()) {
533 final boolean toPropagate = myPropagateParametersMethods.remove(constructor);
534 final PsiClass containingClass = defConstructorUsage.getContainingClass();
535 constructor = (PsiMethod)containingClass.add(constructor);
536 PsiUtil.setModifierProperty(constructor, VisibilityUtil.getVisibilityModifier(containingClass.getModifierList()), true);
537 if (toPropagate) {
538 myPropagateParametersMethods.add(constructor);
541 addSuperCall(constructor, defConstructorUsage.getBaseConstructor(),usages);
543 else if (usage instanceof NoConstructorClassUsageInfo) {
544 addDefaultConstructor(((NoConstructorClassUsageInfo)usage).getPsiClass(),usages);
546 else if (element instanceof PsiJavaCodeReferenceElement) {
547 if (usage instanceof MethodCallUsageInfo) {
548 final MethodCallUsageInfo methodCallInfo = (MethodCallUsageInfo)usage;
549 processMethodUsage(methodCallInfo.getElement(), myChangeInfo, methodCallInfo.isToChangeArguments(),
550 methodCallInfo.isToCatchExceptions(), methodCallInfo.getReferencedMethod(), usages);
552 else if (usage instanceof MyParameterUsageInfo) {
553 String newName = ((MyParameterUsageInfo)usage).newParameterName;
554 String oldName = ((MyParameterUsageInfo)usage).oldParameterName;
555 processParameterUsage((PsiReferenceExpression)element, oldName, newName);
556 } else {
557 postponedUsages.add(usage);
560 else if (usage instanceof CallReferenceUsageInfo) {
561 ((CallReferenceUsageInfo) usage).getReference().handleChangeSignature(myChangeInfo);
563 else if (element instanceof PsiEnumConstant) {
564 fixActualArgumentsList(((PsiEnumConstant)element).getArgumentList(), myChangeInfo, true);
566 else if (!(usage instanceof OverriderUsageInfo)) {
567 postponedUsages.add(usage);
571 for (UsageInfo usageInfo : postponedUsages) {
572 PsiElement element = usageInfo.getElement();
573 if (element == null) continue;
574 PsiReference reference = usageInfo instanceof MoveRenameUsageInfo ?
575 usageInfo.getReference() :
576 element.getReference();
577 if (reference != null) {
578 PsiElement target = null;
579 if (usageInfo instanceof MyParameterUsageInfo) {
580 String newParameterName = ((MyParameterUsageInfo)usageInfo).newParameterName;
581 PsiParameter[] newParams = myChangeInfo.getMethod().getParameterList().getParameters();
582 for (PsiParameter newParam : newParams) {
583 if (newParam.getName().equals(newParameterName)) {
584 target = newParam;
585 break;
589 else {
590 target = myChangeInfo.getMethod();
592 if (target != null) {
593 reference.bindToElement(target);
598 LOG.assertTrue(myChangeInfo.getMethod().isValid());
599 } catch (IncorrectOperationException e) {
600 LOG.error(e);
604 private void generateDelegate() throws IncorrectOperationException {
605 final PsiMethod delegate = (PsiMethod)myChangeInfo.getMethod().copy();
606 final PsiClass targetClass = myChangeInfo.getMethod().getContainingClass();
607 LOG.assertTrue(!targetClass.isInterface());
608 makeEmptyBody(myFactory, delegate);
609 final PsiCallExpression callExpression = addDelegatingCallTemplate(delegate, myChangeInfo.newName);
610 addDelegateArguments(callExpression);
611 targetClass.addBefore(delegate, myChangeInfo.getMethod());
614 private void addDelegateArguments(final PsiCallExpression callExpression) throws IncorrectOperationException {
615 final ParameterInfoImpl[] newParms = myChangeInfo.newParms;
616 for (int i = 0; i < newParms.length; i++) {
617 ParameterInfoImpl newParm = newParms[i];
618 final PsiExpression actualArg;
619 if (newParm.oldParameterIndex >= 0) {
620 actualArg = myFactory.createExpressionFromText(myChangeInfo.oldParameterNames[newParm.oldParameterIndex], callExpression);
622 else {
623 actualArg = myChangeInfo.getValue(i, callExpression);
625 callExpression.getArgumentList().add(actualArg);
629 public static void makeEmptyBody(final PsiElementFactory factory, final PsiMethod delegate) throws IncorrectOperationException {
630 PsiCodeBlock body = delegate.getBody();
631 if (body != null) {
632 body.replace(factory.createCodeBlock());
634 else {
635 delegate.add(factory.createCodeBlock());
637 PsiUtil.setModifierProperty(delegate, PsiModifier.ABSTRACT, false);
640 public static PsiCallExpression addDelegatingCallTemplate(final PsiMethod delegate, final String newName) throws IncorrectOperationException {
641 Project project = delegate.getProject();
642 PsiElementFactory factory = JavaPsiFacade.getInstance(project).getElementFactory();
643 PsiCodeBlock body = delegate.getBody();
644 assert body != null;
645 final PsiCallExpression callExpression;
646 if (delegate.isConstructor()) {
647 PsiElement callStatement = factory.createStatementFromText("this();", null);
648 callStatement = CodeStyleManager.getInstance(project).reformat(callStatement);
649 callStatement = body.add(callStatement);
650 callExpression = (PsiCallExpression)((PsiExpressionStatement) callStatement).getExpression();
651 } else {
652 if (PsiType.VOID.equals(delegate.getReturnType())) {
653 PsiElement callStatement = factory.createStatementFromText(newName + "();", null);
654 callStatement = CodeStyleManager.getInstance(project).reformat(callStatement);
655 callStatement = body.add(callStatement);
656 callExpression = (PsiCallExpression)((PsiExpressionStatement) callStatement).getExpression();
658 else {
659 PsiElement callStatement = factory.createStatementFromText("return " + newName + "();", null);
660 callStatement = CodeStyleManager.getInstance(project).reformat(callStatement);
661 callStatement = body.add(callStatement);
662 callExpression = (PsiCallExpression)((PsiReturnStatement) callStatement).getReturnValue();
665 return callExpression;
668 private void addDefaultConstructor(PsiClass aClass, final UsageInfo[] usages) throws IncorrectOperationException {
669 if (!(aClass instanceof PsiAnonymousClass)) {
670 PsiMethod defaultConstructor = myFactory.createMethodFromText(aClass.getName() + "(){}", aClass);
671 defaultConstructor = (PsiMethod) CodeStyleManager.getInstance(myProject).reformat(defaultConstructor);
672 defaultConstructor = (PsiMethod) aClass.add(defaultConstructor);
673 PsiUtil.setModifierProperty(defaultConstructor, VisibilityUtil.getVisibilityModifier(aClass.getModifierList()), true);
674 addSuperCall(defaultConstructor, null, usages);
675 } else {
676 final PsiElement parent = aClass.getParent();
677 if (parent instanceof PsiNewExpression) {
678 final PsiExpressionList argumentList = ((PsiNewExpression) parent).getArgumentList();
679 fixActualArgumentsList(argumentList, myChangeInfo, true);
684 private void addSuperCall(PsiMethod constructor, PsiMethod callee, final UsageInfo[] usages) throws IncorrectOperationException {
685 PsiExpressionStatement superCall = (PsiExpressionStatement) myFactory.createStatementFromText("super();", constructor);
686 PsiCodeBlock body = constructor.getBody();
687 assert body != null;
688 PsiStatement[] statements = body.getStatements();
689 if (statements.length > 0) {
690 superCall = (PsiExpressionStatement) body.addBefore(superCall, statements[0]);
691 } else {
692 superCall = (PsiExpressionStatement) body.add(superCall);
694 PsiMethodCallExpression callExpression = (PsiMethodCallExpression) superCall.getExpression();
695 processMethodUsage(callExpression.getMethodExpression(), myChangeInfo, true, false, callee, usages);
698 private PsiParameter createNewParameter(ParameterInfoImpl newParm,
699 PsiSubstitutor substitutor) throws IncorrectOperationException {
700 final PsiElementFactory factory = JavaPsiFacade.getInstance(myProject).getElementFactory();
701 final PsiType type = substitutor.substitute(newParm.createType(myChangeInfo.getMethod().getParameterList(), myManager));
702 return factory.createParameter(newParm.getName(), type);
705 protected String getCommandName() {
706 return RefactoringBundle.message("changing.signature.of.0", UsageViewUtil.getDescriptiveName(myChangeInfo.getMethod()));
709 private void processMethodUsage(PsiElement ref,
710 ChangeInfoImpl changeInfo,
711 boolean toChangeArguments,
712 boolean toCatchExceptions,
713 PsiMethod callee, final UsageInfo[] usages) throws IncorrectOperationException {
714 if (changeInfo.isNameChanged) {
715 if (ref instanceof PsiJavaCodeReferenceElement) {
716 PsiElement last = ((PsiJavaCodeReferenceElement)ref).getReferenceNameElement();
717 if (last instanceof PsiIdentifier && last.getText().equals(changeInfo.oldName)) {
718 last.replace(changeInfo.newNameIdentifier);
723 final PsiMethod caller = RefactoringUtil.getEnclosingMethod(ref);
724 if (toChangeArguments) {
725 final PsiExpressionList list = RefactoringUtil.getArgumentListByMethodReference(ref);
726 boolean toInsertDefaultValue = !myPropagateParametersMethods.contains(caller);
727 if (toInsertDefaultValue && ref instanceof PsiReferenceExpression) {
728 final PsiExpression qualifierExpression = ((PsiReferenceExpression) ref).getQualifierExpression();
729 if (qualifierExpression instanceof PsiSuperExpression && callerSignatureIsAboutToChangeToo(caller, usages)) {
730 toInsertDefaultValue = false;
734 fixActualArgumentsList(list, changeInfo, toInsertDefaultValue);
737 if (toCatchExceptions) {
738 if (!(ref instanceof PsiReferenceExpression && ((PsiReferenceExpression)ref).getQualifierExpression() instanceof PsiSuperExpression)) {
739 if (needToCatchExceptions(caller)) {
740 PsiClassType[] newExceptions = callee != null ? getCalleeChangedExceptionInfo(callee) : getPrimaryChangedExceptionInfo(changeInfo);
741 fixExceptions(ref, newExceptions);
747 private static boolean callerSignatureIsAboutToChangeToo(final PsiMethod caller, final UsageInfo[] usages) {
748 for (UsageInfo usage : usages) {
749 if (usage instanceof MethodCallUsageInfo && MethodSignatureUtil.isSuperMethod(((MethodCallUsageInfo)usage).getReferencedMethod(), caller)) return true;
751 return false;
754 private static PsiClassType[] getCalleeChangedExceptionInfo(final PsiMethod callee) {
755 return callee.getThrowsList().getReferencedTypes(); //Callee method's throws list is already modified!
758 private PsiClassType[] getPrimaryChangedExceptionInfo(ChangeInfoImpl changeInfo) throws IncorrectOperationException {
759 PsiClassType[] newExceptions = new PsiClassType[changeInfo.newExceptions.length];
760 for (int i = 0; i < newExceptions.length; i++) {
761 newExceptions[i] = (PsiClassType)changeInfo.newExceptions[i].myType.getType(myChangeInfo.getMethod(), myManager); //context really does not matter here
763 return newExceptions;
766 private void fixExceptions(PsiElement ref, PsiClassType[] newExceptions) throws IncorrectOperationException {
767 //methods' throws lists are already modified, may use ExceptionUtil.collectUnhandledExceptions
768 newExceptions = filterCheckedExceptions(newExceptions);
770 PsiElement context = PsiTreeUtil.getParentOfType(ref, PsiTryStatement.class, PsiMethod.class);
771 if (context instanceof PsiTryStatement) {
772 PsiTryStatement tryStatement = (PsiTryStatement)context;
773 PsiCodeBlock tryBlock = tryStatement.getTryBlock();
775 //Remove unused catches
776 Collection<PsiClassType> classes = ExceptionUtil.collectUnhandledExceptions(tryBlock, tryBlock);
777 PsiParameter[] catchParameters = tryStatement.getCatchBlockParameters();
778 for (PsiParameter parameter : catchParameters) {
779 final PsiType caughtType = parameter.getType();
781 if (!(caughtType instanceof PsiClassType)) continue;
782 if (ExceptionUtil.isUncheckedExceptionOrSuperclass((PsiClassType)caughtType)) continue;
784 if (!isCatchParameterRedundant((PsiClassType)caughtType, classes)) continue;
785 parameter.getParent().delete(); //delete catch section
788 PsiClassType[] exceptionsToAdd = filterUnhandledExceptions(newExceptions, tryBlock);
789 addExceptions(exceptionsToAdd, tryStatement);
791 adjustPossibleEmptyTryStatement(tryStatement);
793 else {
794 newExceptions = filterUnhandledExceptions(newExceptions, ref);
795 if (newExceptions.length > 0) {
796 //Add new try statement
797 PsiElementFactory elementFactory = JavaPsiFacade.getInstance(myManager.getProject()).getElementFactory();
798 PsiTryStatement tryStatement = (PsiTryStatement)elementFactory.createStatementFromText("try {} catch (Exception e) {}", null);
799 PsiStatement anchor = PsiTreeUtil.getParentOfType(ref, PsiStatement.class);
800 LOG.assertTrue(anchor != null);
801 tryStatement.getTryBlock().add(anchor);
802 tryStatement = (PsiTryStatement)anchor.getParent().addAfter(tryStatement, anchor);
804 addExceptions(newExceptions, tryStatement);
805 anchor.delete();
806 tryStatement.getCatchSections()[0].delete(); //Delete dummy catch section
811 private static PsiClassType[] filterCheckedExceptions(PsiClassType[] exceptions) {
812 List<PsiClassType> result = new ArrayList<PsiClassType>();
813 for (PsiClassType exceptionType : exceptions) {
814 if (!ExceptionUtil.isUncheckedException(exceptionType)) result.add(exceptionType);
816 return result.toArray(new PsiClassType[result.size()]);
819 private static void adjustPossibleEmptyTryStatement(PsiTryStatement tryStatement) throws IncorrectOperationException {
820 PsiCodeBlock tryBlock = tryStatement.getTryBlock();
821 if (tryBlock != null) {
822 if (tryStatement.getCatchSections().length == 0 &&
823 tryStatement.getFinallyBlock() == null) {
824 PsiElement firstBodyElement = tryBlock.getFirstBodyElement();
825 if (firstBodyElement != null) {
826 tryStatement.getParent().addRangeAfter(firstBodyElement, tryBlock.getLastBodyElement(), tryStatement);
828 tryStatement.delete();
833 private static void addExceptions(PsiClassType[] exceptionsToAdd, PsiTryStatement tryStatement) throws IncorrectOperationException {
834 for (PsiClassType type : exceptionsToAdd) {
835 final JavaCodeStyleManager styleManager = JavaCodeStyleManager.getInstance(tryStatement.getProject());
836 String name = styleManager.suggestVariableName(VariableKind.PARAMETER, null, null, type).names[0];
837 name = styleManager.suggestUniqueVariableName(name, tryStatement, false);
839 PsiCatchSection catchSection =
840 JavaPsiFacade.getInstance(tryStatement.getProject()).getElementFactory().createCatchSection(type, name, tryStatement);
841 tryStatement.add(catchSection);
845 private void fixPrimaryThrowsLists(PsiMethod method, PsiClassType[] newExceptions) throws IncorrectOperationException {
846 PsiElementFactory elementFactory = JavaPsiFacade.getInstance(myManager.getProject()).getElementFactory();
847 PsiJavaCodeReferenceElement[] refs = new PsiJavaCodeReferenceElement[newExceptions.length];
848 for (int i = 0; i < refs.length; i++) {
849 refs[i] = elementFactory.createReferenceElementByType(newExceptions[i]);
851 PsiReferenceList throwsList = elementFactory.createReferenceList(refs);
853 replaceThrowsList(method, throwsList);
856 private void replaceThrowsList(PsiMethod method, PsiReferenceList throwsList) throws IncorrectOperationException {
857 PsiReferenceList methodThrowsList = (PsiReferenceList)method.getThrowsList().replace(throwsList);
858 methodThrowsList = (PsiReferenceList)JavaCodeStyleManager.getInstance(myProject).shortenClassReferences(methodThrowsList);
859 myManager.getCodeStyleManager().reformatRange(method, method.getParameterList().getTextRange().getEndOffset(),
860 methodThrowsList.getTextRange().getEndOffset());
863 private static PsiClassType[] filterUnhandledExceptions(PsiClassType[] exceptions, PsiElement place) {
864 List<PsiClassType> result = new ArrayList<PsiClassType>();
865 for (PsiClassType exception : exceptions) {
866 if (!ExceptionUtil.isHandled(exception, place)) result.add(exception);
868 return result.toArray(new PsiClassType[result.size()]);
871 private static boolean isCatchParameterRedundant (PsiClassType catchParamType, Collection<PsiClassType> thrownTypes) {
872 for (PsiType exceptionType : thrownTypes) {
873 if (exceptionType.isConvertibleFrom(catchParamType)) return false;
875 return true;
878 private static int getNonVarargCount(ChangeInfoImpl changeInfo, PsiExpression[] args) {
879 if (!changeInfo.wasVararg) return args.length;
880 return changeInfo.oldParameterTypes.length - 1;
883 //This methods works equally well for primary usages as well as for propagated callers' usages
884 private void fixActualArgumentsList(PsiExpressionList list,
885 ChangeInfoImpl changeInfo,
886 boolean toInsertDefaultValue) throws IncorrectOperationException {
887 final PsiElementFactory factory = JavaPsiFacade.getInstance(list.getProject()).getElementFactory();
888 if (changeInfo.isParameterSetOrOrderChanged) {
889 if (changeInfo.isPropagationEnabled) {
890 final ParameterInfoImpl[] createdParmsInfo = changeInfo.getCreatedParmsInfoWithoutVarargs();
891 for (ParameterInfoImpl info : createdParmsInfo) {
892 PsiExpression newArg;
893 if (toInsertDefaultValue) {
894 newArg = createDefaultValue(factory, info, list);
896 else {
897 newArg = factory.createExpressionFromText(info.getName(), list);
899 list.add(newArg);
902 else {
903 final PsiExpression[] args = list.getExpressions();
904 final int nonVarargCount = getNonVarargCount(changeInfo, args);
905 final int varargCount = args.length - nonVarargCount;
906 PsiExpression[] newVarargInitializers = null;
908 final int newArgsLength;
909 final int newNonVarargCount;
910 if (changeInfo.arrayToVarargs) {
911 newNonVarargCount = changeInfo.newParms.length - 1;
912 final ParameterInfoImpl lastNewParm = changeInfo.newParms[changeInfo.newParms.length - 1];
913 final PsiExpression arrayToConvert = args[lastNewParm.oldParameterIndex];
914 if (arrayToConvert instanceof PsiNewExpression) {
915 final PsiNewExpression expression = (PsiNewExpression)arrayToConvert;
916 final PsiArrayInitializerExpression arrayInitializer = expression.getArrayInitializer();
917 if (arrayInitializer != null) {
918 newVarargInitializers = arrayInitializer.getInitializers();
921 newArgsLength = newVarargInitializers == null ? changeInfo.newParms.length : newNonVarargCount + newVarargInitializers.length;
923 else if (changeInfo.retainsVarargs) {
924 newNonVarargCount = changeInfo.newParms.length - 1;
925 newArgsLength = newNonVarargCount + varargCount;
927 else if (changeInfo.obtainsVarags) {
928 newNonVarargCount = changeInfo.newParms.length - 1;
929 newArgsLength = newNonVarargCount;
931 else {
932 newNonVarargCount = changeInfo.newParms.length;
933 newArgsLength = changeInfo.newParms.length;
935 final PsiExpression[] newArgs = new PsiExpression[newArgsLength];
936 for (int i = 0; i < newNonVarargCount; i++) {
937 newArgs [i] = createActualArgument(list, changeInfo.newParms [i], toInsertDefaultValue, args);
939 if (changeInfo.arrayToVarargs) {
940 if (newVarargInitializers == null) {
941 newArgs [newNonVarargCount] = createActualArgument(list, changeInfo.newParms [newNonVarargCount], toInsertDefaultValue, args);
943 else {
944 for (int i = 0; i < newVarargInitializers.length; i++) {
945 newArgs [i + newNonVarargCount] = newVarargInitializers [i];
949 else {
950 final int newVarargCount = newArgsLength - newNonVarargCount;
951 LOG.assertTrue(newVarargCount == 0 || newVarargCount == varargCount);
952 for (int i = 0; i < newVarargCount; i++) {
953 newArgs[newNonVarargCount + i] = args[nonVarargCount + i];
956 ChangeSignatureUtil.synchronizeList(list, Arrays.asList(newArgs), ExpressionList.INSTANCE, changeInfo.toRemoveParm);
961 private PsiExpression createActualArgument(final PsiExpressionList list, final ParameterInfoImpl info, final boolean toInsertDefaultValue,
962 final PsiExpression[] args) throws IncorrectOperationException {
963 final PsiElementFactory factory = JavaPsiFacade.getInstance(list.getProject()).getElementFactory();
964 final int index = info.oldParameterIndex;
965 if (index >= 0) {
966 return args[index];
967 } else {
968 if (toInsertDefaultValue) {
969 return createDefaultValue(factory, info, list);
970 } else {
971 return factory.createExpressionFromText(info.getName(), list);
976 private PsiExpression createDefaultValue(final PsiElementFactory factory, final ParameterInfoImpl info, final PsiExpressionList list)
977 throws IncorrectOperationException {
978 if (info.useAnySingleVariable) {
979 final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(list.getProject()).getResolveHelper();
980 final PsiType type = info.getTypeWrapper().getType(myChangeInfo.getMethod(), myManager);
981 final VariablesProcessor processor = new VariablesProcessor(false) {
982 protected boolean check(PsiVariable var, ResolveState state) {
983 if (var instanceof PsiField && !resolveHelper.isAccessible((PsiField)var, list, null)) return false;
984 final PsiType varType = state.get(PsiSubstitutor.KEY).substitute(var.getType());
985 return type.isAssignableFrom(varType);
988 public boolean execute(PsiElement pe, ResolveState state) {
989 super.execute(pe, state);
990 return size() < 2;
993 PsiScopesUtil.treeWalkUp(processor, list, null);
994 if (processor.size() == 1) {
995 final PsiVariable result = processor.getResult(0);
996 return factory.createExpressionFromText(result.getName(), list);
999 final PsiCallExpression callExpression = PsiTreeUtil.getParentOfType(list, PsiCallExpression.class);
1000 return callExpression != null ? info.getValue(callExpression) : factory.createExpressionFromText(info.defaultValue, list);
1003 private static void addParameterUsages(PsiParameter parameter,
1004 ArrayList<UsageInfo> results,
1005 ParameterInfoImpl info) {
1006 PsiManager manager = parameter.getManager();
1007 GlobalSearchScope projectScope = GlobalSearchScope.projectScope(manager.getProject());
1008 for (PsiReference psiReference : ReferencesSearch.search(parameter, projectScope, false)) {
1009 PsiElement parmRef = psiReference.getElement();
1010 UsageInfo usageInfo = new MyParameterUsageInfo(parmRef, parameter.getName(), info.getName());
1011 results.add(usageInfo);
1015 private void processCallerMethod(PsiMethod caller,
1016 PsiMethod baseMethod,
1017 boolean toInsertParams,
1018 boolean toInsertThrows) throws IncorrectOperationException {
1019 LOG.assertTrue(toInsertParams || toInsertThrows);
1020 if (toInsertParams) {
1021 List<PsiParameter> newParameters = new ArrayList<PsiParameter>();
1022 newParameters.addAll(Arrays.asList(caller.getParameterList().getParameters()));
1023 final ParameterInfoImpl[] primaryNewParms = myChangeInfo.newParms;
1024 PsiSubstitutor substitutor = baseMethod == null ? PsiSubstitutor.EMPTY : calculateSubstitutor(caller, baseMethod);
1025 for (ParameterInfoImpl info : primaryNewParms) {
1026 if (info.oldParameterIndex < 0) newParameters.add(createNewParameter(info, substitutor));
1028 PsiParameter[] arrayed = newParameters.toArray(new PsiParameter[newParameters.size()]);
1029 boolean[] toRemoveParm = new boolean[arrayed.length];
1030 Arrays.fill(toRemoveParm, false);
1031 resolveParameterVsFieldsConflicts(arrayed, caller, caller.getParameterList(), toRemoveParm);
1034 if (toInsertThrows) {
1035 List<PsiJavaCodeReferenceElement> newThrowns = new ArrayList<PsiJavaCodeReferenceElement>();
1036 final PsiReferenceList throwsList = caller.getThrowsList();
1037 newThrowns.addAll(Arrays.asList(throwsList.getReferenceElements()));
1038 final ThrownExceptionInfo[] primaryNewExns = myChangeInfo.newExceptions;
1039 for (ThrownExceptionInfo thrownExceptionInfo : primaryNewExns) {
1040 if (thrownExceptionInfo.oldIndex < 0) {
1041 final PsiClassType type = (PsiClassType)thrownExceptionInfo.createType(caller, myManager);
1042 final PsiJavaCodeReferenceElement ref =
1043 JavaPsiFacade.getInstance(caller.getProject()).getElementFactory().createReferenceElementByType(type);
1044 newThrowns.add(ref);
1047 PsiJavaCodeReferenceElement[] arrayed = newThrowns.toArray(new PsiJavaCodeReferenceElement[newThrowns.size()]);
1048 boolean[] toRemoveParm = new boolean[arrayed.length];
1049 Arrays.fill(toRemoveParm, false);
1050 ChangeSignatureUtil.synchronizeList(throwsList, Arrays.asList(arrayed), ThrowsList.INSTANCE, toRemoveParm);
1054 private void processPrimaryMethod(PsiMethod method,
1055 PsiMethod baseMethod,
1056 boolean isOriginal) throws IncorrectOperationException {
1057 PsiElementFactory factory = JavaPsiFacade.getInstance(method.getProject()).getElementFactory();
1059 if (myChangeInfo.isVisibilityChanged) {
1060 PsiModifierList modifierList = method.getModifierList();
1061 final String highestVisibility = isOriginal ?
1062 myNewVisibility :
1063 VisibilityUtil.getHighestVisibility(myNewVisibility, VisibilityUtil.getVisibilityModifier(modifierList));
1064 VisibilityUtil.setVisibility(modifierList, highestVisibility);
1067 if (myChangeInfo.isNameChanged) {
1068 String newName = baseMethod == null ? myChangeInfo.newName :
1069 RefactoringUtil.suggestNewOverriderName(method.getName(), baseMethod.getName(), myChangeInfo.newName);
1071 if (newName != null && !newName.equals(method.getName())) {
1072 final PsiIdentifier nameId = method.getNameIdentifier();
1073 assert nameId != null;
1074 nameId.replace(JavaPsiFacade.getInstance(myManager.getProject()).getElementFactory().createIdentifier(newName));
1078 final PsiSubstitutor substitutor = baseMethod == null ? PsiSubstitutor.EMPTY : calculateSubstitutor(method, baseMethod);
1080 if (myChangeInfo.isReturnTypeChanged) {
1081 final PsiType returnType = substitutor.substitute(myChangeInfo.newTypeElement);
1082 // don't modify return type for non-Java overriders (EJB)
1083 if (method.getName().equals(myChangeInfo.newName)) {
1084 final PsiTypeElement typeElement = method.getReturnTypeElement();
1085 if (typeElement != null) {
1086 typeElement.replace(factory.createTypeElement(returnType));
1091 PsiParameterList list = method.getParameterList();
1092 PsiParameter[] parameters = list.getParameters();
1094 PsiParameter[] newParms = new PsiParameter[myChangeInfo.newParms.length];
1095 for (int i = 0; i < newParms.length; i++) {
1096 ParameterInfoImpl info = myChangeInfo.newParms[i];
1097 int index = info.oldParameterIndex;
1098 if (index >= 0) {
1099 PsiParameter parameter = parameters[index];
1100 newParms[i] = parameter;
1102 String oldName = myChangeInfo.oldParameterNames[index];
1103 if (!oldName.equals(info.getName()) && oldName.equals(parameter.getName())) {
1104 PsiIdentifier newIdentifier = factory.createIdentifier(info.getName());
1105 parameter.getNameIdentifier().replace(newIdentifier);
1108 String oldType = myChangeInfo.oldParameterTypes[index];
1109 if (!oldType.equals(info.getTypeText())) {
1110 parameter.normalizeDeclaration();
1111 PsiType newType = substitutor.substitute(info.createType(myChangeInfo.getMethod().getParameterList(), myManager));
1113 parameter.getTypeElement().replace(factory.createTypeElement(newType));
1115 } else {
1116 newParms[i] = createNewParameter(info, substitutor);
1120 resolveParameterVsFieldsConflicts(newParms, method, list, myChangeInfo.toRemoveParm);
1121 fixJavadocsForChangedMethod(method);
1122 if (myChangeInfo.isExceptionSetOrOrderChanged) {
1123 final PsiClassType[] newExceptions = getPrimaryChangedExceptionInfo(myChangeInfo);
1124 fixPrimaryThrowsLists(method, newExceptions);
1128 private static void resolveParameterVsFieldsConflicts(final PsiParameter[] newParms,
1129 final PsiMethod method,
1130 final PsiParameterList list,
1131 boolean[] toRemoveParm) throws IncorrectOperationException {
1132 List<FieldConflictsResolver> conflictResolvers = new ArrayList<FieldConflictsResolver>();
1133 for (PsiParameter parameter : newParms) {
1134 conflictResolvers.add(new FieldConflictsResolver(parameter.getName(), method.getBody()));
1136 ChangeSignatureUtil.synchronizeList(list, Arrays.asList(newParms), ParameterList.INSTANCE, toRemoveParm);
1137 JavaCodeStyleManager.getInstance(list.getProject()).shortenClassReferences(list);
1138 for (FieldConflictsResolver fieldConflictsResolver : conflictResolvers) {
1139 fieldConflictsResolver.fix();
1143 private static PsiSubstitutor calculateSubstitutor(PsiMethod derivedMethod, PsiMethod baseMethod) {
1144 PsiSubstitutor substitutor;
1145 if (derivedMethod.getManager().areElementsEquivalent(derivedMethod, baseMethod)) {
1146 substitutor = PsiSubstitutor.EMPTY;
1147 } else {
1148 final PsiClass baseClass = baseMethod.getContainingClass();
1149 final PsiClass derivedClass = derivedMethod.getContainingClass();
1150 if(baseClass != null && derivedClass != null && InheritanceUtil.isInheritorOrSelf(derivedClass, baseClass, true)) {
1151 final PsiSubstitutor superClassSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(baseClass, derivedClass, PsiSubstitutor.EMPTY);
1152 final MethodSignature superMethodSignature = baseMethod.getSignature(superClassSubstitutor);
1153 final MethodSignature methodSignature = derivedMethod.getSignature(PsiSubstitutor.EMPTY);
1154 final PsiSubstitutor superMethodSubstitutor = MethodSignatureUtil.getSuperMethodSignatureSubstitutor(methodSignature, superMethodSignature);
1155 substitutor = superMethodSubstitutor != null ? superMethodSubstitutor : superClassSubstitutor;
1156 } else {
1157 substitutor = PsiSubstitutor.EMPTY;
1160 return substitutor;
1163 private static void processParameterUsage(PsiReferenceExpression ref, String oldName, String newName)
1164 throws IncorrectOperationException {
1166 PsiElement last = ref.getReferenceNameElement();
1167 if (last instanceof PsiIdentifier && last.getText().equals(oldName)) {
1168 PsiElementFactory factory = JavaPsiFacade.getInstance(ref.getProject()).getElementFactory();
1169 PsiIdentifier newNameIdentifier = factory.createIdentifier(newName);
1170 last.replace(newNameIdentifier);
1174 private static class MyParameterUsageInfo extends UsageInfo {
1175 final String oldParameterName;
1176 final String newParameterName;
1178 public MyParameterUsageInfo(PsiElement element, String oldParameterName, String newParameterName) {
1179 super(element);
1180 this.oldParameterName = oldParameterName;
1181 this.newParameterName = newParameterName;
1185 private static class RenamedParameterCollidesWithLocalUsageInfo extends UnresolvableCollisionUsageInfo {
1186 private final PsiElement myCollidingElement;
1187 private final PsiMethod myMethod;
1189 public RenamedParameterCollidesWithLocalUsageInfo(PsiParameter parameter, PsiElement collidingElement, PsiMethod method) {
1190 super(parameter, collidingElement);
1191 myCollidingElement = collidingElement;
1192 myMethod = method;
1195 public String getDescription() {
1196 return RefactoringBundle.message("there.is.already.a.0.in.the.1.it.will.conflict.with.the.renamed.parameter",
1197 RefactoringUIUtil.getDescription(myCollidingElement, true),
1198 RefactoringUIUtil.getDescription(myMethod, true));
1202 private void fixJavadocsForChangedMethod(PsiMethod method) throws IncorrectOperationException {
1203 final PsiParameter[] parameters = method.getParameterList().getParameters();
1204 final ParameterInfoImpl[] newParms = myChangeInfo.newParms;
1205 LOG.assertTrue(parameters.length == newParms.length);
1206 final Set<PsiParameter> newParameters = new HashSet<PsiParameter>();
1207 for (int i = 0; i < newParms.length; i++) {
1208 ParameterInfoImpl newParm = newParms[i];
1209 if (newParm.oldParameterIndex < 0 ||
1210 !newParm.getName().equals(myChangeInfo.oldParameterNames[newParm.oldParameterIndex])) {
1211 newParameters.add(parameters[i]);
1214 RefactoringUtil.fixJavadocsForParams(method, newParameters);
1217 private static class ExpressionList implements ChangeSignatureUtil.ChildrenGenerator<PsiExpressionList, PsiExpression> {
1218 public static final ExpressionList INSTANCE = new ExpressionList();
1219 public List<PsiExpression> getChildren(PsiExpressionList psiExpressionList) {
1220 return Arrays.asList(psiExpressionList.getExpressions());
1224 private static class ParameterList implements ChangeSignatureUtil.ChildrenGenerator<PsiParameterList, PsiParameter> {
1225 public static final ParameterList INSTANCE = new ParameterList();
1226 public List<PsiParameter> getChildren(PsiParameterList psiParameterList) {
1227 return Arrays.asList(psiParameterList.getParameters());
1231 private static class ThrowsList implements ChangeSignatureUtil.ChildrenGenerator<PsiReferenceList, PsiJavaCodeReferenceElement> {
1232 public static final ThrowsList INSTANCE = new ThrowsList();
1233 public List<PsiJavaCodeReferenceElement> getChildren(PsiReferenceList throwsList) {
1234 return Arrays.asList(throwsList.getReferenceElements());