Merge branch 'master' into changeSignature
[idea/community.git] / java / java-impl / src / com / intellij / refactoring / changeSignature / ChangeSignatureProcessor.java
1 /*
2  * Copyright 2000-2009 JetBrains s.r.o.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 /**
18  * created at Sep 17, 2001
19  * @author Jeka
20  */
21 package com.intellij.refactoring.changeSignature;
22
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;
61 import org.jetbrains.annotations.Nullable;
62
63 import java.util.*;
64
65 public class ChangeSignatureProcessor extends BaseRefactoringProcessor {
66   private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.changeSignature.ChangeSignatureProcessor");
67
68   @Modifier private final String myNewVisibility;
69   private final ChangeInfoImpl myChangeInfo;
70   private final PsiManager myManager;
71   private final PsiElementFactory myFactory;
72   private final boolean myGenerateDelegate;
73   private final Set<PsiMethod> myPropagateParametersMethods;
74   private final Set<PsiMethod> myPropagateExceptionsMethods;
75
76   public ChangeSignatureProcessor(Project project,
77                                   PsiMethod method,
78                                   final boolean generateDelegate,
79                                   @Modifier String newVisibility,
80                                   String newName,
81                                   PsiType newType,
82                                   @NotNull ParameterInfoImpl[] parameterInfo) {
83     this(project, method, generateDelegate, newVisibility, newName,
84          newType != null ? CanonicalTypes.createTypeWrapper(newType) : null,
85          parameterInfo, null, null, null);
86   }
87
88   public ChangeSignatureProcessor(Project project,
89                                   PsiMethod method,
90                                   final boolean generateDelegate,
91                                   String newVisibility,
92                                   String newName,
93                                   PsiType newType,
94                                   ParameterInfoImpl[] parameterInfo,
95                                   ThrownExceptionInfo[] exceptionInfos) {
96     this(project, method, generateDelegate, newVisibility, newName,
97          newType != null ? CanonicalTypes.createTypeWrapper(newType) : null,
98          parameterInfo, exceptionInfos, null, null);
99   }
100
101   public ChangeSignatureProcessor(Project project,
102                                   PsiMethod method,
103                                   boolean generateDelegate,
104                                   String newVisibility,
105                                   String newName,
106                                   CanonicalTypes.Type newType,
107                                   @NotNull ParameterInfoImpl[] parameterInfo,
108                                   ThrownExceptionInfo[] thrownExceptions,
109                                   Set<PsiMethod> propagateParametersMethods,
110                                   Set<PsiMethod> propagateExceptionsMethods) {
111     super(project);
112     myManager = PsiManager.getInstance(project);
113     myFactory = JavaPsiFacade.getInstance(myManager.getProject()).getElementFactory();
114     myGenerateDelegate = generateDelegate;
115
116     myPropagateParametersMethods = propagateParametersMethods != null ? propagateParametersMethods : new HashSet<PsiMethod>();
117     myPropagateExceptionsMethods = propagateExceptionsMethods != null ? propagateExceptionsMethods : new HashSet<PsiMethod>();
118
119     LOG.assertTrue(method.isValid());
120     if (newVisibility == null) {
121       myNewVisibility = VisibilityUtil.getVisibilityModifier(method.getModifierList());
122     } else {
123       myNewVisibility = newVisibility;
124     }
125
126     myChangeInfo = new ChangeInfoImpl(myNewVisibility, method, newName, newType, parameterInfo, thrownExceptions);
127     LOG.assertTrue(myChangeInfo.getMethod().isValid());
128   }
129
130   protected UsageViewDescriptor createUsageViewDescriptor(UsageInfo[] usages) {
131     return new ChangeSignatureViewDescriptor(myChangeInfo.getMethod());
132   }
133
134   @NotNull
135   protected UsageInfo[] findUsages() {
136     ArrayList<UsageInfo> result = new ArrayList<UsageInfo>();
137     final PsiMethod method = myChangeInfo.getMethod();
138
139     findSimpleUsages(method, result);
140
141     final UsageInfo[] usageInfos = result.toArray(new UsageInfo[result.size()]);
142     return UsageViewUtil.removeDuplicatedUsages(usageInfos);
143   }
144
145   private void findSimpleUsages(final PsiMethod method, final ArrayList<UsageInfo> result) {
146     PsiMethod[] overridingMethods = findSimpleUsagesWithoutParameters(method, result, true, true, true);
147     findUsagesInCallers (result);
148
149     //Parameter name changes are not propagated
150     findParametersUsage(method, result, overridingMethods);
151   }
152
153   private PsiMethod[] findSimpleUsagesWithoutParameters(final PsiMethod method,
154                                                         final ArrayList<UsageInfo> result,
155                                                         boolean isToModifyArgs,
156                                                         boolean isToThrowExceptions,
157                                                         boolean isOriginal) {
158
159     GlobalSearchScope projectScope = GlobalSearchScope.projectScope(myProject);
160     PsiMethod[] overridingMethods = OverridingMethodsSearch.search(method, method.getUseScope(), true).toArray(PsiMethod.EMPTY_ARRAY);
161
162     for (PsiMethod overridingMethod : overridingMethods) {
163       result.add(new OverriderUsageInfo(overridingMethod, method, isOriginal, isToModifyArgs, isToThrowExceptions));
164     }
165
166     boolean needToChangeCalls = !myGenerateDelegate && (myChangeInfo.isNameChanged || myChangeInfo.isParameterSetOrOrderChanged || myChangeInfo.isExceptionSetOrOrderChanged || myChangeInfo.isVisibilityChanged/*for checking inaccessible*/);
167     if (needToChangeCalls) {
168       int parameterCount = method.getParameterList().getParametersCount();
169
170       PsiReference[] refs = MethodReferencesSearch.search(method, projectScope, true).toArray(PsiReference.EMPTY_ARRAY);
171       for (PsiReference ref : refs) {
172         PsiElement element = ref.getElement();
173         boolean isToCatchExceptions = isToThrowExceptions && needToCatchExceptions(RefactoringUtil.getEnclosingMethod(element));
174         if (!isToCatchExceptions) {
175           if (RefactoringUtil.isMethodUsage(element)) {
176             PsiExpressionList list = RefactoringUtil.getArgumentListByMethodReference(element);
177             if (!method.isVarArgs() && list.getExpressions().length != parameterCount) continue;
178           }
179         }
180         if (RefactoringUtil.isMethodUsage(element)) {
181           result.add(new MethodCallUsageInfo(element, isToModifyArgs, isToCatchExceptions));
182         }
183         else if (element instanceof PsiDocTagValue) {
184           result.add(new UsageInfo(ref.getElement()));
185         }
186         else if (element instanceof PsiMethod && ((PsiMethod)element).isConstructor()) {
187           DefaultConstructorImplicitUsageInfo implicitUsageInfo = new DefaultConstructorImplicitUsageInfo((PsiMethod)element,
188                                                                                                           ((PsiMethod)element).getContainingClass(), method);
189           result.add(implicitUsageInfo);
190         }
191         else if(element instanceof PsiClass) {
192           LOG.assertTrue(method.isConstructor());
193           final PsiClass psiClass = (PsiClass)element;
194           if (shouldPropagateToNonPhysicalMethod(method, result, psiClass, myPropagateParametersMethods)) continue;
195           if (shouldPropagateToNonPhysicalMethod(method, result, psiClass, myPropagateExceptionsMethods)) continue;
196           result.add(new NoConstructorClassUsageInfo(psiClass));
197         }
198         else if (ref instanceof PsiCallReference) {
199           result.add(new CallReferenceUsageInfo((PsiCallReference) ref));
200         }
201         else {
202           result.add(new MoveRenameUsageInfo(element, ref, method));
203         }
204       }
205
206       //if (method.isConstructor() && parameterCount == 0) {
207       //    RefactoringUtil.visitImplicitConstructorUsages(method.getContainingClass(),
208       //                                                   new DefaultConstructorUsageCollector(result));
209       //}
210     }
211     else if (myChangeInfo.isParameterTypesChanged) {
212       PsiReference[] refs = MethodReferencesSearch.search(method, projectScope, true).toArray(PsiReference.EMPTY_ARRAY);
213       for (PsiReference reference : refs) {
214         final PsiElement element = reference.getElement();
215         if (element instanceof PsiDocTagValue) {
216           result.add(new UsageInfo(reference));
217         }
218         else if (element instanceof XmlElement) {
219           result.add(new MoveRenameUsageInfo(reference, method));
220         }
221       }
222     }
223
224     // Conflicts
225     detectLocalsCollisionsInMethod(method, result, isOriginal);
226     for (final PsiMethod overridingMethod : overridingMethods) {
227       detectLocalsCollisionsInMethod(overridingMethod, result, isOriginal);
228     }
229
230     return overridingMethods;
231   }
232
233   private static boolean shouldPropagateToNonPhysicalMethod(PsiMethod method, ArrayList<UsageInfo> result, PsiClass containingClass, final Set<PsiMethod> propagateMethods) {
234     for (PsiMethod psiMethod : propagateMethods) {
235       if (!psiMethod.isPhysical() && Comparing.strEqual(psiMethod.getName(), containingClass.getName())) {
236         result.add(new DefaultConstructorImplicitUsageInfo(psiMethod, containingClass, method));
237         return true;
238       }
239     }
240     return false;
241   }
242
243   private void findUsagesInCallers(final ArrayList<UsageInfo> usages) {
244     for (PsiMethod caller : myPropagateParametersMethods) {
245       usages.add(new CallerUsageInfo(caller, true, myPropagateExceptionsMethods.contains(caller)));
246     }
247     for (PsiMethod caller : myPropagateExceptionsMethods) {
248       usages.add(new CallerUsageInfo(caller, myPropagateParametersMethods.contains(caller), true));
249     }
250     Set<PsiMethod> merged = new HashSet<PsiMethod>();
251     merged.addAll(myPropagateParametersMethods);
252     merged.addAll(myPropagateExceptionsMethods);
253     for (final PsiMethod method : merged) {
254       findSimpleUsagesWithoutParameters(method, usages, myPropagateParametersMethods.contains(method),
255                                         myPropagateExceptionsMethods.contains(method), false);
256     }
257   }
258
259   private boolean needToChangeCalls() {
260     return myChangeInfo.isNameChanged || myChangeInfo.isParameterSetOrOrderChanged || myChangeInfo.isExceptionSetOrOrderChanged;
261   }
262
263   private boolean needToCatchExceptions(PsiMethod caller) {
264     return myChangeInfo.isExceptionSetOrOrderChanged && !myPropagateExceptionsMethods.contains(caller);
265   }
266
267   private void detectLocalsCollisionsInMethod(final PsiMethod method,
268                                               final ArrayList<UsageInfo> result,
269                                               boolean isOriginal) {
270     final PsiParameter[] parameters = method.getParameterList().getParameters();
271     final Set<PsiParameter> deletedOrRenamedParameters = new HashSet<PsiParameter>();
272     if (isOriginal) {
273       deletedOrRenamedParameters.addAll(Arrays.asList(parameters));
274       for (ParameterInfoImpl parameterInfo : myChangeInfo.newParms) {
275         if (parameterInfo.oldParameterIndex >= 0) {
276           final PsiParameter parameter = parameters[parameterInfo.oldParameterIndex];
277           if (parameterInfo.getName().equals(parameter.getName())) {
278             deletedOrRenamedParameters.remove(parameter);
279           }
280         }
281       }
282     }
283
284     for (ParameterInfoImpl parameterInfo : myChangeInfo.newParms) {
285       final int oldParameterIndex = parameterInfo.oldParameterIndex;
286       final String newName = parameterInfo.getName();
287       if (oldParameterIndex >= 0) {
288         if (isOriginal) {   //Name changes take place only in primary method
289           final PsiParameter parameter = parameters[oldParameterIndex];
290           if (!newName.equals(parameter.getName())) {
291             JavaUnresolvableLocalCollisionDetector.visitLocalsCollisions(parameter, newName, method.getBody(), null, new JavaUnresolvableLocalCollisionDetector.CollidingVariableVisitor() {
292               public void visitCollidingElement(final PsiVariable collidingVariable) {
293                 if (!deletedOrRenamedParameters.contains(collidingVariable)) {
294                   result.add(new RenamedParameterCollidesWithLocalUsageInfo(parameter, collidingVariable, method));
295                 }
296               }
297             });
298           }
299         }
300       }
301       else {
302         JavaUnresolvableLocalCollisionDetector.visitLocalsCollisions(method, newName, method.getBody(), null, new JavaUnresolvableLocalCollisionDetector.CollidingVariableVisitor() {
303           public void visitCollidingElement(PsiVariable collidingVariable) {
304             if (!deletedOrRenamedParameters.contains(collidingVariable)) {
305               result.add(new NewParameterCollidesWithLocalUsageInfo(collidingVariable, collidingVariable, method));
306             }
307           }
308         });
309       }
310     }
311   }
312
313   private void findParametersUsage(final PsiMethod method, ArrayList<UsageInfo> result, PsiMethod[] overriders) {
314     PsiParameter[] parameters = method.getParameterList().getParameters();
315     for (ParameterInfoImpl info : myChangeInfo.newParms) {
316       if (info.oldParameterIndex >= 0) {
317         PsiParameter parameter = parameters[info.oldParameterIndex];
318         if (!info.getName().equals(parameter.getName())) {
319           addParameterUsages(parameter, result, info);
320
321           for (PsiMethod overrider : overriders) {
322             PsiParameter parameter1 = overrider.getParameterList().getParameters()[info.oldParameterIndex];
323             if (parameter.getName().equals(parameter1.getName())) {
324               addParameterUsages(parameter1, result, info);
325             }
326           }
327         }
328       }
329     }
330   }
331
332   protected void refreshElements(PsiElement[] elements) {
333     boolean condition = elements.length == 1 && elements[0] instanceof PsiMethod;
334     LOG.assertTrue(condition);
335     myChangeInfo.updateMethod((PsiMethod) elements[0]);
336   }
337
338   private void addMethodConflicts(MultiMap<PsiElement, String> conflicts) {
339     String newMethodName = myChangeInfo.newName;
340
341     try {
342       PsiMethod prototype;
343       PsiManager manager = PsiManager.getInstance(myProject);
344       PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory();
345       final PsiMethod method = myChangeInfo.getMethod();
346       final CanonicalTypes.Type returnType = myChangeInfo.newReturnType;
347       if (returnType != null) {
348         prototype = factory.createMethod(newMethodName, returnType.getType(method, manager));
349       }
350       else {
351         prototype = factory.createConstructor();
352         prototype.setName(newMethodName);
353       }
354       ParameterInfoImpl[] parameters = myChangeInfo.newParms;
355
356
357       for (ParameterInfoImpl info : parameters) {
358         final PsiType parameterType = info.createType(method, manager);
359         PsiParameter param = factory.createParameter(info.getName(), parameterType);
360         prototype.getParameterList().add(param);
361       }
362
363       ConflictsUtil.checkMethodConflicts(
364         method.getContainingClass(),
365         method,
366         prototype, conflicts);
367     }
368     catch (IncorrectOperationException e) {
369       LOG.error(e);
370     }
371   }
372
373
374   protected boolean preprocessUsages(Ref<UsageInfo[]> refUsages) {
375     MultiMap<PsiElement, String> conflictDescriptions = new MultiMap<PsiElement, String>();
376     UsageInfo[] usagesIn = refUsages.get();
377     addMethodConflicts(conflictDescriptions);
378     RenameUtil.addConflictDescriptions(usagesIn, conflictDescriptions);
379     Set<UsageInfo> usagesSet = new HashSet<UsageInfo>(Arrays.asList(usagesIn));
380     RenameUtil.removeConflictUsages(usagesSet);
381     if (myChangeInfo.isVisibilityChanged) {
382       try {
383         addInaccessibilityDescriptions(usagesSet, conflictDescriptions);
384       }
385       catch (IncorrectOperationException e) {
386         LOG.error(e);
387       }
388     }
389
390     if (myPrepareSuccessfulSwingThreadCallback != null && !conflictDescriptions.isEmpty()) {
391       ConflictsDialog dialog = new ConflictsDialog(myProject, conflictDescriptions);
392       dialog.show();
393       if (!dialog.isOK()){
394         if (dialog.isShowConflicts()) prepareSuccessful();
395         return false;
396       }
397     }
398
399     if (myChangeInfo.isReturnTypeChanged) {
400       askToRemoveCovariantOverriders (usagesSet);
401     }
402
403     refUsages.set(usagesSet.toArray(new UsageInfo[usagesSet.size()]));
404     prepareSuccessful();
405     return true;
406   }
407
408   private void addInaccessibilityDescriptions(Set<UsageInfo> usages, MultiMap<PsiElement, String> conflictDescriptions) throws IncorrectOperationException {
409     PsiMethod method = myChangeInfo.getMethod();
410     PsiModifierList modifierList = (PsiModifierList)method.getModifierList().copy();
411     VisibilityUtil.setVisibility(modifierList, myNewVisibility);
412
413     for (Iterator<UsageInfo> iterator = usages.iterator(); iterator.hasNext();) {
414       UsageInfo usageInfo = iterator.next();
415       PsiElement element = usageInfo.getElement();
416       if (element != null) {
417         if (element instanceof PsiReferenceExpression) {
418           PsiClass accessObjectClass = null;
419           PsiExpression qualifier = ((PsiReferenceExpression)element).getQualifierExpression();
420           if (qualifier != null) {
421             accessObjectClass = (PsiClass)PsiUtil.getAccessObjectClass(qualifier).getElement();
422           }
423
424           if (!JavaPsiFacade.getInstance(element.getProject()).getResolveHelper()
425             .isAccessible(method, modifierList, element, accessObjectClass, null)) {
426             String message =
427               RefactoringBundle.message("0.with.1.visibility.is.not.accesible.from.2",
428                                         RefactoringUIUtil.getDescription(method, true),
429                                         myNewVisibility,
430                                         RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(element), true));
431             conflictDescriptions.putValue(method, message);
432             if (!needToChangeCalls()) {
433               iterator.remove();
434             }
435           }
436         }
437       }
438     }
439   }
440
441   private void askToRemoveCovariantOverriders(Set<UsageInfo> usages) {
442     if (PsiUtil.isLanguageLevel5OrHigher(myChangeInfo.getMethod())) {
443       List<UsageInfo> covariantOverriderInfos = new ArrayList<UsageInfo>();
444       for (UsageInfo usageInfo : usages) {
445         if (usageInfo instanceof OverriderUsageInfo) {
446           final OverriderUsageInfo info = (OverriderUsageInfo)usageInfo;
447           PsiMethod overrider = info.getElement();
448           PsiMethod baseMethod = info.getBaseMethod();
449           PsiSubstitutor substitutor = calculateSubstitutor(overrider, baseMethod);
450           PsiType type;
451           try {
452             type = substitutor.substitute(myChangeInfo.newReturnType.getType(myChangeInfo.getMethod(), myManager));
453           }
454           catch (IncorrectOperationException e) {
455             LOG.error(e);
456             return;
457           }
458           final PsiType overriderType = overrider.getReturnType();
459           if (overriderType != null && type.isAssignableFrom(overriderType)) {
460             covariantOverriderInfos.add(usageInfo);
461           }
462         }
463       }
464
465       // to be able to do filtering
466       preprocessCovariantOverriders(covariantOverriderInfos);
467
468       if (!covariantOverriderInfos.isEmpty()) {
469         if (ApplicationManager.getApplication().isUnitTestMode() || !isProcessCovariantOverriders()) {
470           for (UsageInfo usageInfo : covariantOverriderInfos) {
471             usages.remove(usageInfo);
472           }
473         }
474       }
475     }
476   }
477
478   protected void preprocessCovariantOverriders(final List<UsageInfo> covariantOverriderInfos) {
479   }
480
481   protected boolean isProcessCovariantOverriders() {
482     return Messages.showYesNoDialog(myProject, RefactoringBundle.message("do.you.want.to.process.overriding.methods.with.covariant.return.type"),
483                              JavaChangeSignatureHandler.REFACTORING_NAME, Messages.getQuestionIcon())
484     == DialogWrapper.OK_EXIT_CODE;
485   }
486
487   protected void performRefactoring(UsageInfo[] usages) {
488     PsiElementFactory factory = JavaPsiFacade.getInstance(myManager.getProject()).getElementFactory();
489
490     try {
491       if (myChangeInfo.isNameChanged) {
492         myChangeInfo.newNameIdentifier = factory.createIdentifier(myChangeInfo.newName);
493       }
494
495       if (myChangeInfo.isReturnTypeChanged) {
496         myChangeInfo.newTypeElement = myChangeInfo.newReturnType.getType(myChangeInfo.getMethod(), myManager);
497       }
498
499       if (myGenerateDelegate) {
500         generateDelegate();
501       }
502
503       for (UsageInfo usage : usages) {
504         if (usage instanceof CallerUsageInfo) {
505           final CallerUsageInfo callerUsageInfo = (CallerUsageInfo)usage;
506           processCallerMethod(callerUsageInfo.getMethod(), null, callerUsageInfo.isToInsertParameter(),
507                               callerUsageInfo.isToInsertException());
508         }
509         else if (usage instanceof OverriderUsageInfo) {
510           OverriderUsageInfo info = (OverriderUsageInfo)usage;
511           final PsiMethod method = info.getElement();
512           final PsiMethod baseMethod = info.getBaseMethod();
513           if (info.isOriginalOverrider()) {
514             processPrimaryMethod(method, baseMethod, false);
515           }
516           else {
517             processCallerMethod(method, baseMethod, info.isToInsertArgs(), info.isToCatchExceptions());
518           }
519         }
520       }
521
522       LOG.assertTrue(myChangeInfo.getMethod().isValid());
523       processPrimaryMethod(myChangeInfo.getMethod(), null, true);
524       List<UsageInfo> postponedUsages = new ArrayList<UsageInfo>();
525
526       for (UsageInfo usage : usages) {
527         PsiElement element = usage.getElement();
528         if (element == null) continue;
529
530         if (usage instanceof DefaultConstructorImplicitUsageInfo) {
531           final DefaultConstructorImplicitUsageInfo defConstructorUsage = (DefaultConstructorImplicitUsageInfo)usage;
532           PsiMethod constructor = defConstructorUsage.getConstructor();
533           if (!constructor.isPhysical()) {
534             final boolean toPropagate = myPropagateParametersMethods.remove(constructor);
535             final PsiClass containingClass = defConstructorUsage.getContainingClass();
536             constructor = (PsiMethod)containingClass.add(constructor);
537             PsiUtil.setModifierProperty(constructor, VisibilityUtil.getVisibilityModifier(containingClass.getModifierList()), true);
538             if (toPropagate) {
539               myPropagateParametersMethods.add(constructor);
540             }
541           }
542           addSuperCall(constructor, defConstructorUsage.getBaseConstructor(),usages);
543         }
544         else if (usage instanceof NoConstructorClassUsageInfo) {
545           addDefaultConstructor(((NoConstructorClassUsageInfo)usage).getPsiClass(),usages);
546         }
547         else if (element instanceof PsiJavaCodeReferenceElement) {
548           if (usage instanceof MethodCallUsageInfo) {
549             final MethodCallUsageInfo methodCallInfo = (MethodCallUsageInfo)usage;
550             processMethodUsage(methodCallInfo.getElement(), myChangeInfo, methodCallInfo.isToChangeArguments(),
551                                methodCallInfo.isToCatchExceptions(), methodCallInfo.getReferencedMethod(), usages);
552           }
553           else if (usage instanceof MyParameterUsageInfo) {
554             String newName = ((MyParameterUsageInfo)usage).newParameterName;
555             String oldName = ((MyParameterUsageInfo)usage).oldParameterName;
556             processParameterUsage((PsiReferenceExpression)element, oldName, newName);
557           } else {
558             postponedUsages.add(usage);
559           }
560         }
561         else if (usage instanceof CallReferenceUsageInfo) {
562           ((CallReferenceUsageInfo) usage).getReference().handleChangeSignature(myChangeInfo);
563         }
564         else if (element instanceof PsiEnumConstant) {
565           fixActualArgumentsList(((PsiEnumConstant)element).getArgumentList(), myChangeInfo, true);
566         }
567         else if (!(usage instanceof OverriderUsageInfo)) {
568           postponedUsages.add(usage);
569         }
570       }
571
572       for (UsageInfo usageInfo : postponedUsages) {
573         PsiElement element = usageInfo.getElement();
574         if (element == null) continue;
575         PsiReference reference = usageInfo instanceof MoveRenameUsageInfo ?
576                                  usageInfo.getReference() :
577                                  element.getReference();
578         if (reference != null) {
579           PsiElement target = null;
580           if (usageInfo instanceof MyParameterUsageInfo) {
581             String newParameterName = ((MyParameterUsageInfo)usageInfo).newParameterName;
582             PsiParameter[] newParams = myChangeInfo.getMethod().getParameterList().getParameters();
583             for (PsiParameter newParam : newParams) {
584               if (newParam.getName().equals(newParameterName)) {
585                 target = newParam;
586                 break;
587               }
588             }
589           }
590           else {
591             target = myChangeInfo.getMethod();
592           }
593           if (target != null) {
594             reference.bindToElement(target);
595           }
596         }
597       }
598
599       LOG.assertTrue(myChangeInfo.getMethod().isValid());
600     } catch (IncorrectOperationException e) {
601       LOG.error(e);
602     }
603   }
604
605   private void generateDelegate() throws IncorrectOperationException {
606     final PsiMethod delegate = (PsiMethod)myChangeInfo.getMethod().copy();
607     final PsiClass targetClass = myChangeInfo.getMethod().getContainingClass();
608     LOG.assertTrue(!targetClass.isInterface());
609     makeEmptyBody(myFactory, delegate);
610     final PsiCallExpression callExpression = addDelegatingCallTemplate(delegate, myChangeInfo.newName);
611     addDelegateArguments(callExpression);
612     targetClass.addBefore(delegate, myChangeInfo.getMethod());
613   }
614
615   private void addDelegateArguments(final PsiCallExpression callExpression) throws IncorrectOperationException {
616     final ParameterInfoImpl[] newParms = myChangeInfo.newParms;
617     for (int i = 0; i < newParms.length; i++) {
618       ParameterInfoImpl newParm = newParms[i];
619       final PsiExpression actualArg;
620       if (newParm.oldParameterIndex >= 0) {
621         actualArg = myFactory.createExpressionFromText(myChangeInfo.oldParameterNames[newParm.oldParameterIndex], callExpression);
622       }
623       else {
624         actualArg = myChangeInfo.getValue(i, callExpression);
625       }
626       callExpression.getArgumentList().add(actualArg);
627     }
628   }
629
630   public static void makeEmptyBody(final PsiElementFactory factory, final PsiMethod delegate) throws IncorrectOperationException {
631     PsiCodeBlock body = delegate.getBody();
632     if (body != null) {
633       body.replace(factory.createCodeBlock());
634     }
635     else {
636       delegate.add(factory.createCodeBlock());
637     }
638     PsiUtil.setModifierProperty(delegate, PsiModifier.ABSTRACT, false);
639   }
640
641   public static PsiCallExpression addDelegatingCallTemplate(final PsiMethod delegate, final String newName) throws IncorrectOperationException {
642     Project project = delegate.getProject();
643     PsiElementFactory factory = JavaPsiFacade.getInstance(project).getElementFactory();
644     PsiCodeBlock body = delegate.getBody();
645     assert body != null;
646     final PsiCallExpression callExpression;
647     if (delegate.isConstructor()) {
648       PsiElement callStatement = factory.createStatementFromText("this();", null);
649       callStatement = CodeStyleManager.getInstance(project).reformat(callStatement);
650       callStatement = body.add(callStatement);
651       callExpression = (PsiCallExpression)((PsiExpressionStatement) callStatement).getExpression();
652     } else {
653       if (PsiType.VOID.equals(delegate.getReturnType())) {
654         PsiElement callStatement = factory.createStatementFromText(newName + "();", null);
655         callStatement = CodeStyleManager.getInstance(project).reformat(callStatement);
656         callStatement = body.add(callStatement);
657         callExpression = (PsiCallExpression)((PsiExpressionStatement) callStatement).getExpression();
658       }
659       else {
660         PsiElement callStatement = factory.createStatementFromText("return " + newName + "();", null);
661         callStatement = CodeStyleManager.getInstance(project).reformat(callStatement);
662         callStatement = body.add(callStatement);
663         callExpression = (PsiCallExpression)((PsiReturnStatement) callStatement).getReturnValue();
664       }
665     }
666     return callExpression;
667   }
668
669   private void addDefaultConstructor(PsiClass aClass, final UsageInfo[] usages) throws IncorrectOperationException {
670     if (!(aClass instanceof PsiAnonymousClass)) {
671       PsiMethod defaultConstructor = myFactory.createMethodFromText(aClass.getName() + "(){}", aClass);
672       defaultConstructor = (PsiMethod) CodeStyleManager.getInstance(myProject).reformat(defaultConstructor);
673       defaultConstructor = (PsiMethod) aClass.add(defaultConstructor);
674       PsiUtil.setModifierProperty(defaultConstructor, VisibilityUtil.getVisibilityModifier(aClass.getModifierList()), true);
675       addSuperCall(defaultConstructor, null, usages);
676     } else {
677       final PsiElement parent = aClass.getParent();
678       if (parent instanceof PsiNewExpression) {
679         final PsiExpressionList argumentList = ((PsiNewExpression) parent).getArgumentList();
680         fixActualArgumentsList(argumentList, myChangeInfo, true);
681       }
682     }
683   }
684
685   private void addSuperCall(PsiMethod constructor, PsiMethod callee, final UsageInfo[] usages) throws IncorrectOperationException {
686     PsiExpressionStatement superCall = (PsiExpressionStatement) myFactory.createStatementFromText("super();", constructor);
687     PsiCodeBlock body = constructor.getBody();
688     assert body != null;
689     PsiStatement[] statements = body.getStatements();
690     if (statements.length > 0) {
691       superCall = (PsiExpressionStatement) body.addBefore(superCall, statements[0]);
692     } else {
693       superCall = (PsiExpressionStatement) body.add(superCall);
694     }
695     PsiMethodCallExpression callExpression = (PsiMethodCallExpression) superCall.getExpression();
696     processMethodUsage(callExpression.getMethodExpression(), myChangeInfo, true, false, callee, usages);
697   }
698
699   private PsiParameter createNewParameter(ParameterInfoImpl newParm,
700                                           PsiSubstitutor substitutor) throws IncorrectOperationException {
701     final PsiElementFactory factory = JavaPsiFacade.getInstance(myProject).getElementFactory();
702     final PsiType type = substitutor.substitute(newParm.createType(myChangeInfo.getMethod().getParameterList(), myManager));
703     return factory.createParameter(newParm.getName(), type);
704   }
705
706   protected String getCommandName() {
707     return RefactoringBundle.message("changing.signature.of.0", UsageViewUtil.getDescriptiveName(myChangeInfo.getMethod()));
708   }
709
710   private void processMethodUsage(PsiElement ref,
711                                   ChangeInfoImpl changeInfo,
712                                   boolean toChangeArguments,
713                                   boolean toCatchExceptions,
714                                   PsiMethod callee, final UsageInfo[] usages) throws IncorrectOperationException {
715     if (changeInfo.isNameChanged) {
716       if (ref instanceof PsiJavaCodeReferenceElement) {
717         PsiElement last = ((PsiJavaCodeReferenceElement)ref).getReferenceNameElement();
718         if (last instanceof PsiIdentifier && last.getText().equals(changeInfo.oldName)) {
719           last.replace(changeInfo.newNameIdentifier);
720         }
721       }
722     }
723
724     final PsiMethod caller = RefactoringUtil.getEnclosingMethod(ref);
725     if (toChangeArguments) {
726       final PsiExpressionList list = RefactoringUtil.getArgumentListByMethodReference(ref);
727       boolean toInsertDefaultValue = !myPropagateParametersMethods.contains(caller);
728       if (toInsertDefaultValue && ref instanceof PsiReferenceExpression) {
729         final PsiExpression qualifierExpression = ((PsiReferenceExpression) ref).getQualifierExpression();
730         if (qualifierExpression instanceof PsiSuperExpression && callerSignatureIsAboutToChangeToo(caller, usages)) {
731           toInsertDefaultValue = false;
732         }
733       }
734
735       fixActualArgumentsList(list, changeInfo, toInsertDefaultValue);
736     }
737
738     if (toCatchExceptions) {
739       if (!(ref instanceof PsiReferenceExpression && ((PsiReferenceExpression)ref).getQualifierExpression() instanceof PsiSuperExpression)) {
740         if (needToCatchExceptions(caller)) {
741           PsiClassType[] newExceptions = callee != null ? getCalleeChangedExceptionInfo(callee) : getPrimaryChangedExceptionInfo(changeInfo);
742           fixExceptions(ref, newExceptions);
743         }
744       }
745     }
746   }
747
748   private static boolean callerSignatureIsAboutToChangeToo(final PsiMethod caller, final UsageInfo[] usages) {
749     for (UsageInfo usage : usages) {
750       if (usage instanceof MethodCallUsageInfo && MethodSignatureUtil.isSuperMethod(((MethodCallUsageInfo)usage).getReferencedMethod(), caller)) return true;
751     }
752     return false;
753   }
754
755   private static PsiClassType[] getCalleeChangedExceptionInfo(final PsiMethod callee) {
756     return callee.getThrowsList().getReferencedTypes(); //Callee method's throws list is already modified!
757   }
758
759   private PsiClassType[] getPrimaryChangedExceptionInfo(ChangeInfoImpl changeInfo) throws IncorrectOperationException {
760     PsiClassType[] newExceptions = new PsiClassType[changeInfo.newExceptions.length];
761     for (int i = 0; i < newExceptions.length; i++) {
762       newExceptions[i] = (PsiClassType)changeInfo.newExceptions[i].myType.getType(myChangeInfo.getMethod(), myManager); //context really does not matter here
763     }
764     return newExceptions;
765   }
766
767   private void fixExceptions(PsiElement ref, PsiClassType[] newExceptions) throws IncorrectOperationException {
768     //methods' throws lists are already modified, may use ExceptionUtil.collectUnhandledExceptions
769     newExceptions = filterCheckedExceptions(newExceptions);
770
771     PsiElement context = PsiTreeUtil.getParentOfType(ref, PsiTryStatement.class, PsiMethod.class);
772     if (context instanceof PsiTryStatement) {
773       PsiTryStatement tryStatement = (PsiTryStatement)context;
774       PsiCodeBlock tryBlock = tryStatement.getTryBlock();
775
776       //Remove unused catches
777       Collection<PsiClassType> classes = ExceptionUtil.collectUnhandledExceptions(tryBlock, tryBlock);
778       PsiParameter[] catchParameters = tryStatement.getCatchBlockParameters();
779       for (PsiParameter parameter : catchParameters) {
780         final PsiType caughtType = parameter.getType();
781
782         if (!(caughtType instanceof PsiClassType)) continue;
783         if (ExceptionUtil.isUncheckedExceptionOrSuperclass((PsiClassType)caughtType)) continue;
784
785         if (!isCatchParameterRedundant((PsiClassType)caughtType, classes)) continue;
786         parameter.getParent().delete(); //delete catch section
787       }
788
789       PsiClassType[] exceptionsToAdd  = filterUnhandledExceptions(newExceptions, tryBlock);
790       addExceptions(exceptionsToAdd, tryStatement);
791
792       adjustPossibleEmptyTryStatement(tryStatement);
793     }
794     else {
795       newExceptions = filterUnhandledExceptions(newExceptions, ref);
796       if (newExceptions.length > 0) {
797         //Add new try statement
798         PsiElementFactory elementFactory = JavaPsiFacade.getInstance(myManager.getProject()).getElementFactory();
799         PsiTryStatement tryStatement = (PsiTryStatement)elementFactory.createStatementFromText("try {} catch (Exception e) {}", null);
800         PsiStatement anchor = PsiTreeUtil.getParentOfType(ref, PsiStatement.class);
801         LOG.assertTrue(anchor != null);
802         tryStatement.getTryBlock().add(anchor);
803         tryStatement = (PsiTryStatement)anchor.getParent().addAfter(tryStatement, anchor);
804
805         addExceptions(newExceptions, tryStatement);
806         anchor.delete();
807         tryStatement.getCatchSections()[0].delete(); //Delete dummy catch section
808       }
809     }
810   }
811
812   private static PsiClassType[] filterCheckedExceptions(PsiClassType[] exceptions) {
813     List<PsiClassType> result = new ArrayList<PsiClassType>();
814     for (PsiClassType exceptionType : exceptions) {
815       if (!ExceptionUtil.isUncheckedException(exceptionType)) result.add(exceptionType);
816     }
817     return result.toArray(new PsiClassType[result.size()]);
818   }
819
820   private static void adjustPossibleEmptyTryStatement(PsiTryStatement tryStatement) throws IncorrectOperationException {
821     PsiCodeBlock tryBlock = tryStatement.getTryBlock();
822     if (tryBlock != null) {
823       if (tryStatement.getCatchSections().length == 0 &&
824           tryStatement.getFinallyBlock() == null) {
825         PsiElement firstBodyElement = tryBlock.getFirstBodyElement();
826         if (firstBodyElement != null) {
827           tryStatement.getParent().addRangeAfter(firstBodyElement, tryBlock.getLastBodyElement(), tryStatement);
828         }
829         tryStatement.delete();
830       }
831     }
832   }
833
834   private static void addExceptions(PsiClassType[] exceptionsToAdd, PsiTryStatement tryStatement) throws IncorrectOperationException {
835     for (PsiClassType type : exceptionsToAdd) {
836       final JavaCodeStyleManager styleManager = JavaCodeStyleManager.getInstance(tryStatement.getProject());
837       String name = styleManager.suggestVariableName(VariableKind.PARAMETER, null, null, type).names[0];
838       name = styleManager.suggestUniqueVariableName(name, tryStatement, false);
839
840       PsiCatchSection catchSection =
841         JavaPsiFacade.getInstance(tryStatement.getProject()).getElementFactory().createCatchSection(type, name, tryStatement);
842       tryStatement.add(catchSection);
843     }
844   }
845
846   private void fixPrimaryThrowsLists(PsiMethod method, PsiClassType[] newExceptions) throws IncorrectOperationException {
847     PsiElementFactory elementFactory = JavaPsiFacade.getInstance(myManager.getProject()).getElementFactory();
848     PsiJavaCodeReferenceElement[] refs = new PsiJavaCodeReferenceElement[newExceptions.length];
849     for (int i = 0; i < refs.length; i++) {
850       refs[i] = elementFactory.createReferenceElementByType(newExceptions[i]);
851     }
852     PsiReferenceList throwsList = elementFactory.createReferenceList(refs);
853
854     replaceThrowsList(method, throwsList);
855   }
856
857   private void replaceThrowsList(PsiMethod method, PsiReferenceList throwsList) throws IncorrectOperationException {
858     PsiReferenceList methodThrowsList = (PsiReferenceList)method.getThrowsList().replace(throwsList);
859     methodThrowsList = (PsiReferenceList)JavaCodeStyleManager.getInstance(myProject).shortenClassReferences(methodThrowsList);
860     myManager.getCodeStyleManager().reformatRange(method, method.getParameterList().getTextRange().getEndOffset(),
861                                                   methodThrowsList.getTextRange().getEndOffset());
862   }
863
864   private static PsiClassType[] filterUnhandledExceptions(PsiClassType[] exceptions, PsiElement place) {
865     List<PsiClassType> result = new ArrayList<PsiClassType>();
866     for (PsiClassType exception : exceptions) {
867       if (!ExceptionUtil.isHandled(exception, place)) result.add(exception);
868     }
869     return result.toArray(new PsiClassType[result.size()]);
870   }
871
872   private static boolean isCatchParameterRedundant (PsiClassType catchParamType, Collection<PsiClassType> thrownTypes) {
873     for (PsiType exceptionType : thrownTypes) {
874       if (exceptionType.isConvertibleFrom(catchParamType)) return false;
875     }
876     return true;
877   }
878
879   private static int getNonVarargCount(ChangeInfoImpl changeInfo, PsiExpression[] args) {
880     if (!changeInfo.wasVararg) return args.length;
881     return changeInfo.oldParameterTypes.length - 1;
882   }
883
884   //This methods works equally well for primary usages as well as for propagated callers' usages
885   private void fixActualArgumentsList(PsiExpressionList list,
886                                       ChangeInfoImpl changeInfo,
887                                       boolean toInsertDefaultValue) throws IncorrectOperationException {
888     final PsiElementFactory factory = JavaPsiFacade.getInstance(list.getProject()).getElementFactory();
889     if (changeInfo.isParameterSetOrOrderChanged) {
890       if (changeInfo.isPropagationEnabled) {
891         final ParameterInfoImpl[] createdParmsInfo = changeInfo.getCreatedParmsInfoWithoutVarargs();
892         for (ParameterInfoImpl info : createdParmsInfo) {
893           PsiExpression newArg;
894           if (toInsertDefaultValue) {
895             newArg = createDefaultValue(factory, info, list);
896           }
897           else {
898             newArg = factory.createExpressionFromText(info.getName(), list);
899           }
900           list.add(newArg);
901         }
902       }
903       else {
904         final PsiExpression[] args = list.getExpressions();
905         final int nonVarargCount = getNonVarargCount(changeInfo, args);
906         final int varargCount = args.length - nonVarargCount;
907         PsiExpression[] newVarargInitializers = null;
908
909         final int newArgsLength;
910         final int newNonVarargCount;
911         if (changeInfo.arrayToVarargs) {
912           newNonVarargCount = changeInfo.newParms.length - 1;
913           final ParameterInfoImpl lastNewParm = changeInfo.newParms[changeInfo.newParms.length - 1];
914           final PsiExpression arrayToConvert = args[lastNewParm.oldParameterIndex];
915           if (arrayToConvert instanceof PsiNewExpression) {
916             final PsiNewExpression expression = (PsiNewExpression)arrayToConvert;
917             final PsiArrayInitializerExpression arrayInitializer = expression.getArrayInitializer();
918             if (arrayInitializer != null) {
919               newVarargInitializers = arrayInitializer.getInitializers();
920             }
921           }
922           newArgsLength = newVarargInitializers == null ? changeInfo.newParms.length : newNonVarargCount + newVarargInitializers.length;
923         }
924         else if (changeInfo.retainsVarargs) {
925           newNonVarargCount = changeInfo.newParms.length - 1;
926           newArgsLength =  newNonVarargCount + varargCount;
927         }
928         else if (changeInfo.obtainsVarags) {
929           newNonVarargCount = changeInfo.newParms.length - 1;
930           newArgsLength = newNonVarargCount;
931         }
932         else {
933           newNonVarargCount = changeInfo.newParms.length;
934           newArgsLength = changeInfo.newParms.length;
935         }
936         final PsiExpression[] newArgs = new PsiExpression[newArgsLength];
937         for (int i = 0; i < newNonVarargCount; i++) {
938           newArgs [i] = createActualArgument(list, changeInfo.newParms [i], toInsertDefaultValue, args);
939         }
940         if (changeInfo.arrayToVarargs) {
941           if (newVarargInitializers == null) {
942             newArgs [newNonVarargCount] = createActualArgument(list, changeInfo.newParms [newNonVarargCount], toInsertDefaultValue, args);
943           }
944           else {
945             System.arraycopy(newVarargInitializers, 0, newArgs, newNonVarargCount, newVarargInitializers.length);
946           }
947         }
948         else {
949           final int newVarargCount = newArgsLength - newNonVarargCount;
950           LOG.assertTrue(newVarargCount == 0 || newVarargCount == varargCount);
951           System.arraycopy(args, nonVarargCount, newArgs, newNonVarargCount, newVarargCount);
952         }
953         ChangeSignatureUtil.synchronizeList(list, Arrays.asList(newArgs), ExpressionList.INSTANCE, changeInfo.toRemoveParm);
954       }
955     }
956   }
957
958   private PsiExpression createActualArgument(final PsiExpressionList list, final ParameterInfoImpl info, final boolean toInsertDefaultValue,
959                                              final PsiExpression[] args) throws IncorrectOperationException {
960     final PsiElementFactory factory = JavaPsiFacade.getInstance(list.getProject()).getElementFactory();
961     final int index = info.oldParameterIndex;
962     if (index >= 0) {
963       return args[index];
964     } else {
965       if (toInsertDefaultValue) {
966         return createDefaultValue(factory, info, list);
967       } else {
968         return factory.createExpressionFromText(info.getName(), list);
969       }
970     }
971   }
972
973   @Nullable
974   private PsiExpression createDefaultValue(final PsiElementFactory factory, final ParameterInfoImpl info, final PsiExpressionList list)
975     throws IncorrectOperationException {
976     if (info.useAnySingleVariable) {
977       final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(list.getProject()).getResolveHelper();
978       final PsiType type = info.getTypeWrapper().getType(myChangeInfo.getMethod(), myManager);
979       final VariablesProcessor processor = new VariablesProcessor(false) {
980               protected boolean check(PsiVariable var, ResolveState state) {
981                 if (var instanceof PsiField && !resolveHelper.isAccessible((PsiField)var, list, null)) return false;
982                 final PsiType varType = state.get(PsiSubstitutor.KEY).substitute(var.getType());
983                 return type.isAssignableFrom(varType);
984               }
985
986               public boolean execute(PsiElement pe, ResolveState state) {
987                 super.execute(pe, state);
988                 return size() < 2;
989               }
990             };
991       PsiScopesUtil.treeWalkUp(processor, list, null);
992       if (processor.size() == 1) {
993         final PsiVariable result = processor.getResult(0);
994         return factory.createExpressionFromText(result.getName(), list);
995       }
996     }
997     final PsiCallExpression callExpression = PsiTreeUtil.getParentOfType(list, PsiCallExpression.class);
998     return callExpression != null ? info.getValue(callExpression) : factory.createExpressionFromText(info.defaultValue, list);
999   }
1000
1001   private static void addParameterUsages(PsiParameter parameter,
1002                                   ArrayList<UsageInfo> results,
1003                                   ParameterInfoImpl info) {
1004     PsiManager manager = parameter.getManager();
1005     GlobalSearchScope projectScope = GlobalSearchScope.projectScope(manager.getProject());
1006     for (PsiReference psiReference : ReferencesSearch.search(parameter, projectScope, false)) {
1007       PsiElement parmRef = psiReference.getElement();
1008       UsageInfo usageInfo = new MyParameterUsageInfo(parmRef, parameter.getName(), info.getName());
1009       results.add(usageInfo);
1010     }
1011   }
1012
1013   private void processCallerMethod(PsiMethod caller,
1014                                    PsiMethod baseMethod,
1015                                    boolean toInsertParams,
1016                                    boolean toInsertThrows) throws IncorrectOperationException {
1017     LOG.assertTrue(toInsertParams || toInsertThrows);
1018     if (toInsertParams) {
1019       List<PsiParameter> newParameters = new ArrayList<PsiParameter>();
1020       newParameters.addAll(Arrays.asList(caller.getParameterList().getParameters()));
1021       final ParameterInfoImpl[] primaryNewParms = myChangeInfo.newParms;
1022       PsiSubstitutor substitutor = baseMethod == null ? PsiSubstitutor.EMPTY : calculateSubstitutor(caller, baseMethod);
1023       for (ParameterInfoImpl info : primaryNewParms) {
1024         if (info.oldParameterIndex < 0) newParameters.add(createNewParameter(info, substitutor));
1025       }
1026       PsiParameter[] arrayed = newParameters.toArray(new PsiParameter[newParameters.size()]);
1027       boolean[] toRemoveParm = new boolean[arrayed.length];
1028       Arrays.fill(toRemoveParm, false);
1029       resolveParameterVsFieldsConflicts(arrayed, caller, caller.getParameterList(), toRemoveParm);
1030     }
1031
1032     if (toInsertThrows) {
1033       List<PsiJavaCodeReferenceElement> newThrowns = new ArrayList<PsiJavaCodeReferenceElement>();
1034       final PsiReferenceList throwsList = caller.getThrowsList();
1035       newThrowns.addAll(Arrays.asList(throwsList.getReferenceElements()));
1036       final ThrownExceptionInfo[] primaryNewExns = myChangeInfo.newExceptions;
1037       for (ThrownExceptionInfo thrownExceptionInfo : primaryNewExns) {
1038         if (thrownExceptionInfo.oldIndex < 0) {
1039           final PsiClassType type = (PsiClassType)thrownExceptionInfo.createType(caller, myManager);
1040           final PsiJavaCodeReferenceElement ref =
1041             JavaPsiFacade.getInstance(caller.getProject()).getElementFactory().createReferenceElementByType(type);
1042           newThrowns.add(ref);
1043         }
1044       }
1045       PsiJavaCodeReferenceElement[] arrayed = newThrowns.toArray(new PsiJavaCodeReferenceElement[newThrowns.size()]);
1046       boolean[] toRemoveParm = new boolean[arrayed.length];
1047       Arrays.fill(toRemoveParm, false);
1048       ChangeSignatureUtil.synchronizeList(throwsList, Arrays.asList(arrayed), ThrowsList.INSTANCE, toRemoveParm);
1049     }
1050   }
1051
1052   private void processPrimaryMethod(PsiMethod method,
1053                                     PsiMethod baseMethod,
1054                                     boolean isOriginal) throws IncorrectOperationException {
1055     PsiElementFactory factory = JavaPsiFacade.getInstance(method.getProject()).getElementFactory();
1056
1057     if (myChangeInfo.isVisibilityChanged) {
1058       PsiModifierList modifierList = method.getModifierList();
1059       final String highestVisibility = isOriginal ?
1060                                        myNewVisibility :
1061                                        VisibilityUtil.getHighestVisibility(myNewVisibility, VisibilityUtil.getVisibilityModifier(modifierList));
1062       VisibilityUtil.setVisibility(modifierList, highestVisibility);
1063     }
1064
1065     if (myChangeInfo.isNameChanged) {
1066       String newName = baseMethod == null ? myChangeInfo.newName :
1067                        RefactoringUtil.suggestNewOverriderName(method.getName(), baseMethod.getName(), myChangeInfo.newName);
1068
1069       if (newName != null && !newName.equals(method.getName())) {
1070         final PsiIdentifier nameId = method.getNameIdentifier();
1071         assert nameId != null;
1072         nameId.replace(JavaPsiFacade.getInstance(myManager.getProject()).getElementFactory().createIdentifier(newName));
1073       }
1074     }
1075
1076     final PsiSubstitutor substitutor = baseMethod == null ? PsiSubstitutor.EMPTY : calculateSubstitutor(method, baseMethod);
1077
1078     if (myChangeInfo.isReturnTypeChanged) {
1079       final PsiType returnType = substitutor.substitute(myChangeInfo.newTypeElement);
1080       // don't modify return type for non-Java overriders (EJB)
1081       if (method.getName().equals(myChangeInfo.newName)) {
1082         final PsiTypeElement typeElement = method.getReturnTypeElement();
1083         if (typeElement != null) {
1084           typeElement.replace(factory.createTypeElement(returnType));
1085         }
1086       }
1087     }
1088
1089     PsiParameterList list = method.getParameterList();
1090     PsiParameter[] parameters = list.getParameters();
1091
1092     PsiParameter[] newParms = new PsiParameter[myChangeInfo.newParms.length];
1093     for (int i = 0; i < newParms.length; i++) {
1094       ParameterInfoImpl info = myChangeInfo.newParms[i];
1095       int index = info.oldParameterIndex;
1096       if (index >= 0) {
1097         PsiParameter parameter = parameters[index];
1098         newParms[i] = parameter;
1099
1100         String oldName = myChangeInfo.oldParameterNames[index];
1101         if (!oldName.equals(info.getName()) && oldName.equals(parameter.getName())) {
1102           PsiIdentifier newIdentifier = factory.createIdentifier(info.getName());
1103           parameter.getNameIdentifier().replace(newIdentifier);
1104         }
1105
1106         String oldType = myChangeInfo.oldParameterTypes[index];
1107         if (!oldType.equals(info.getTypeText())) {
1108           parameter.normalizeDeclaration();
1109           PsiType newType = substitutor.substitute(info.createType(myChangeInfo.getMethod().getParameterList(), myManager));
1110
1111           parameter.getTypeElement().replace(factory.createTypeElement(newType));
1112         }
1113       } else {
1114         newParms[i] = createNewParameter(info, substitutor);
1115       }
1116     }
1117
1118     resolveParameterVsFieldsConflicts(newParms, method, list, myChangeInfo.toRemoveParm);
1119     fixJavadocsForChangedMethod(method);
1120     if (myChangeInfo.isExceptionSetOrOrderChanged) {
1121       final PsiClassType[] newExceptions = getPrimaryChangedExceptionInfo(myChangeInfo);
1122       fixPrimaryThrowsLists(method, newExceptions);
1123     }
1124   }
1125
1126   private static void resolveParameterVsFieldsConflicts(final PsiParameter[] newParms,
1127                                                  final PsiMethod method,
1128                                                  final PsiParameterList list,
1129                                                  boolean[] toRemoveParm) throws IncorrectOperationException {
1130     List<FieldConflictsResolver> conflictResolvers = new ArrayList<FieldConflictsResolver>();
1131     for (PsiParameter parameter : newParms) {
1132       conflictResolvers.add(new FieldConflictsResolver(parameter.getName(), method.getBody()));
1133     }
1134     ChangeSignatureUtil.synchronizeList(list, Arrays.asList(newParms), ParameterList.INSTANCE, toRemoveParm);
1135     JavaCodeStyleManager.getInstance(list.getProject()).shortenClassReferences(list);
1136     for (FieldConflictsResolver fieldConflictsResolver : conflictResolvers) {
1137       fieldConflictsResolver.fix();
1138     }
1139   }
1140
1141   private static PsiSubstitutor calculateSubstitutor(PsiMethod derivedMethod, PsiMethod baseMethod) {
1142     PsiSubstitutor substitutor;
1143     if (derivedMethod.getManager().areElementsEquivalent(derivedMethod, baseMethod)) {
1144       substitutor = PsiSubstitutor.EMPTY;
1145     } else {
1146       final PsiClass baseClass = baseMethod.getContainingClass();
1147       final PsiClass derivedClass = derivedMethod.getContainingClass();
1148       if(baseClass != null && derivedClass != null && InheritanceUtil.isInheritorOrSelf(derivedClass, baseClass, true)) {
1149         final PsiSubstitutor superClassSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(baseClass, derivedClass, PsiSubstitutor.EMPTY);
1150         final MethodSignature superMethodSignature = baseMethod.getSignature(superClassSubstitutor);
1151         final MethodSignature methodSignature = derivedMethod.getSignature(PsiSubstitutor.EMPTY);
1152         final PsiSubstitutor superMethodSubstitutor = MethodSignatureUtil.getSuperMethodSignatureSubstitutor(methodSignature, superMethodSignature);
1153         substitutor = superMethodSubstitutor != null ? superMethodSubstitutor : superClassSubstitutor;
1154       } else {
1155         substitutor = PsiSubstitutor.EMPTY;
1156       }
1157     }
1158     return substitutor;
1159   }
1160
1161   private static void processParameterUsage(PsiReferenceExpression ref, String oldName, String newName)
1162           throws IncorrectOperationException {
1163
1164     PsiElement last = ref.getReferenceNameElement();
1165     if (last instanceof PsiIdentifier && last.getText().equals(oldName)) {
1166       PsiElementFactory factory = JavaPsiFacade.getInstance(ref.getProject()).getElementFactory();
1167       PsiIdentifier newNameIdentifier = factory.createIdentifier(newName);
1168       last.replace(newNameIdentifier);
1169     }
1170   }
1171
1172   private static class MyParameterUsageInfo extends UsageInfo {
1173     final String oldParameterName;
1174     final String newParameterName;
1175
1176     public MyParameterUsageInfo(PsiElement element, String oldParameterName, String newParameterName) {
1177       super(element);
1178       this.oldParameterName = oldParameterName;
1179       this.newParameterName = newParameterName;
1180     }
1181   }
1182
1183   private static class RenamedParameterCollidesWithLocalUsageInfo extends UnresolvableCollisionUsageInfo {
1184     private final PsiElement myCollidingElement;
1185     private final PsiMethod myMethod;
1186
1187     public RenamedParameterCollidesWithLocalUsageInfo(PsiParameter parameter, PsiElement collidingElement, PsiMethod method) {
1188       super(parameter, collidingElement);
1189       myCollidingElement = collidingElement;
1190       myMethod = method;
1191     }
1192
1193     public String getDescription() {
1194       return RefactoringBundle.message("there.is.already.a.0.in.the.1.it.will.conflict.with.the.renamed.parameter",
1195                                        RefactoringUIUtil.getDescription(myCollidingElement, true),
1196                                        RefactoringUIUtil.getDescription(myMethod, true));
1197     }
1198   }
1199
1200   private void fixJavadocsForChangedMethod(PsiMethod method) throws IncorrectOperationException {
1201     final PsiParameter[] parameters = method.getParameterList().getParameters();
1202     final ParameterInfoImpl[] newParms = myChangeInfo.newParms;
1203     LOG.assertTrue(parameters.length == newParms.length);
1204     final Set<PsiParameter> newParameters = new HashSet<PsiParameter>();
1205     for (int i = 0; i < newParms.length; i++) {
1206       ParameterInfoImpl newParm = newParms[i];
1207       if (newParm.oldParameterIndex < 0 ||
1208           !newParm.getName().equals(myChangeInfo.oldParameterNames[newParm.oldParameterIndex])) {
1209         newParameters.add(parameters[i]);
1210       }
1211     }
1212     RefactoringUtil.fixJavadocsForParams(method, newParameters);
1213   }
1214
1215   private static class ExpressionList implements ChangeSignatureUtil.ChildrenGenerator<PsiExpressionList, PsiExpression> {
1216     public static final ExpressionList INSTANCE = new ExpressionList();
1217     public List<PsiExpression> getChildren(PsiExpressionList psiExpressionList) {
1218       return Arrays.asList(psiExpressionList.getExpressions());
1219     }
1220   }
1221
1222   private static class ParameterList implements ChangeSignatureUtil.ChildrenGenerator<PsiParameterList, PsiParameter> {
1223     public static final ParameterList INSTANCE = new ParameterList();
1224     public List<PsiParameter> getChildren(PsiParameterList psiParameterList) {
1225       return Arrays.asList(psiParameterList.getParameters());
1226     }
1227   }
1228
1229   private static class ThrowsList implements ChangeSignatureUtil.ChildrenGenerator<PsiReferenceList, PsiJavaCodeReferenceElement> {
1230     public static final ThrowsList INSTANCE = new ThrowsList();
1231     public List<PsiJavaCodeReferenceElement> getChildren(PsiReferenceList throwsList) {
1232       return Arrays.asList(throwsList.getReferenceElements());
1233     }
1234   }
1235
1236 }