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