f98d4739be75e07ff988ae77117a646ec659c83a
[idea/community.git] / java / java-impl / src / com / intellij / refactoring / changeSignature / JavaChangeSignatureUsageProcessor.java
1 /*
2  * Copyright 2000-2014 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 package com.intellij.refactoring.changeSignature;
17
18 import com.intellij.codeInsight.AnnotationUtil;
19 import com.intellij.codeInsight.ExceptionUtil;
20 import com.intellij.codeInsight.daemon.impl.analysis.JavaHighlightUtil;
21 import com.intellij.codeInsight.daemon.impl.quickfix.RemoveUnusedVariableUtil;
22 import com.intellij.codeInspection.dataFlow.ControlFlowAnalyzer;
23 import com.intellij.lang.StdLanguages;
24 import com.intellij.lang.java.JavaLanguage;
25 import com.intellij.openapi.application.ApplicationManager;
26 import com.intellij.openapi.diagnostic.Logger;
27 import com.intellij.openapi.project.Project;
28 import com.intellij.openapi.util.Ref;
29 import com.intellij.openapi.util.text.StringUtil;
30 import com.intellij.psi.*;
31 import com.intellij.psi.codeStyle.CodeStyleManager;
32 import com.intellij.psi.codeStyle.JavaCodeStyleManager;
33 import com.intellij.psi.codeStyle.VariableKind;
34 import com.intellij.psi.scope.processor.VariablesProcessor;
35 import com.intellij.psi.scope.util.PsiScopesUtil;
36 import com.intellij.psi.search.LocalSearchScope;
37 import com.intellij.psi.search.searches.ReferencesSearch;
38 import com.intellij.psi.util.*;
39 import com.intellij.refactoring.RefactoringBundle;
40 import com.intellij.refactoring.rename.RenameUtil;
41 import com.intellij.refactoring.rename.ResolveSnapshotProvider;
42 import com.intellij.refactoring.util.*;
43 import com.intellij.refactoring.util.usageInfo.DefaultConstructorImplicitUsageInfo;
44 import com.intellij.refactoring.util.usageInfo.NoConstructorClassUsageInfo;
45 import com.intellij.usageView.UsageInfo;
46 import com.intellij.util.ArrayUtil;
47 import com.intellij.util.IncorrectOperationException;
48 import com.intellij.util.VisibilityUtil;
49 import com.intellij.util.containers.ContainerUtil;
50 import com.intellij.util.containers.HashSet;
51 import com.intellij.util.containers.MultiMap;
52 import org.jetbrains.annotations.NotNull;
53 import org.jetbrains.annotations.Nullable;
54
55 import java.util.*;
56
57 /**
58  * @author Maxim.Medvedev
59  */
60 public class JavaChangeSignatureUsageProcessor implements ChangeSignatureUsageProcessor {
61   private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.changeSignature.JavaChangeSignatureUsageProcessor");
62
63   private static boolean isJavaUsage(UsageInfo info) {
64     final PsiElement element = info.getElement();
65     if (element == null) return false;
66     return element.getLanguage() == StdLanguages.JAVA;
67   }
68
69   @Override
70   public UsageInfo[] findUsages(ChangeInfo info) {
71     if (info instanceof JavaChangeInfo) {
72       return new JavaChangeSignatureUsageSearcher((JavaChangeInfo)info).findUsages();
73     }
74     else {
75       return UsageInfo.EMPTY_ARRAY;
76     }
77   }
78
79   @Override
80   public MultiMap<PsiElement, String> findConflicts(ChangeInfo info, Ref<UsageInfo[]> refUsages) {
81     if (info instanceof JavaChangeInfo) {
82       return new ConflictSearcher((JavaChangeInfo)info).findConflicts(refUsages);
83     }
84     else {
85       return new MultiMap<>();
86     }
87   }
88
89   @Override
90   public boolean processUsage(ChangeInfo changeInfo, UsageInfo usage, boolean beforeMethodChange, UsageInfo[] usages) {
91     if (!isJavaUsage(usage)) return false;
92     if (!(changeInfo instanceof JavaChangeInfo)) return false;
93
94
95     if (beforeMethodChange) {
96       if (usage instanceof CallerUsageInfo) {
97         final CallerUsageInfo callerUsageInfo = (CallerUsageInfo)usage;
98         processCallerMethod((JavaChangeInfo)changeInfo, callerUsageInfo.getMethod(), null, callerUsageInfo.isToInsertParameter(),
99                             callerUsageInfo.isToInsertException());
100         return true;
101       }
102       else if (usage instanceof OverriderUsageInfo) {
103         OverriderUsageInfo info = (OverriderUsageInfo)usage;
104         final PsiMethod method = info.getOverridingMethod();
105         final PsiMethod baseMethod = info.getBaseMethod();
106         if (info.isOriginalOverrider()) {
107           processPrimaryMethod((JavaChangeInfo)changeInfo, method, baseMethod, false);
108         }
109         else {
110           processCallerMethod((JavaChangeInfo)changeInfo, method, baseMethod, info.isToInsertArgs(), info.isToCatchExceptions());
111         }
112         return true;
113       }
114       else if (usage instanceof MethodReferenceUsageInfo && MethodReferenceUsageInfo.needToExpand((JavaChangeInfo)changeInfo)) {
115         final PsiElement element = usage.getElement();
116         if (element instanceof PsiMethodReferenceExpression ) {
117           final PsiExpression expression = LambdaRefactoringUtil.convertToMethodCallInLambdaBody((PsiMethodReferenceExpression)element);
118           if (expression instanceof PsiCallExpression) {
119             ((MethodReferenceUsageInfo)usage).setCallExpression((PsiCallExpression)expression);
120             return true;
121           }
122         }
123       }
124       else if (usage instanceof FunctionalInterfaceChangedUsageInfo) {
125         final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(usage.getProject());
126         final PsiElement element = usage.getElement();
127         final PsiMethod interfaceMethod = ((FunctionalInterfaceChangedUsageInfo)usage).getMethod();
128         if (element instanceof PsiLambdaExpression) {
129           processMethodParams((JavaChangeInfo)changeInfo, interfaceMethod,
130                               elementFactory, PsiSubstitutor.EMPTY, ((PsiLambdaExpression)element).getParameterList(), ((PsiLambdaExpression)element).getBody());
131         }
132         else if (element instanceof PsiMethodReferenceExpression) {
133           final PsiLambdaExpression lambdaExpression =
134             LambdaRefactoringUtil.convertMethodReferenceToLambda((PsiMethodReferenceExpression)element, false, true);
135           if (lambdaExpression != null) {
136             processMethodParams(((JavaChangeInfo)changeInfo), interfaceMethod, elementFactory, PsiSubstitutor.EMPTY, 
137                                 lambdaExpression.getParameterList(), lambdaExpression.getBody());
138           }
139         }
140         return true;
141       }
142
143     }
144     else {
145       PsiElement element = usage.getElement();
146       LOG.assertTrue(element != null);
147
148       if (usage instanceof DefaultConstructorImplicitUsageInfo) {
149         final DefaultConstructorImplicitUsageInfo defConstructorUsage = (DefaultConstructorImplicitUsageInfo)usage;
150         PsiMethod constructor = defConstructorUsage.getConstructor();
151         if (!constructor.isPhysical()) {
152           final boolean toPropagate =
153             changeInfo instanceof JavaChangeInfoImpl && ((JavaChangeInfoImpl)changeInfo).propagateParametersMethods.remove(constructor);
154           final PsiClass containingClass = defConstructorUsage.getContainingClass();
155           constructor = (PsiMethod)containingClass.add(constructor);
156           PsiUtil.setModifierProperty(constructor, VisibilityUtil.getVisibilityModifier(containingClass.getModifierList()), true);
157           if (toPropagate) {
158             ((JavaChangeInfoImpl)changeInfo).propagateParametersMethods.add(constructor);
159           }
160         }
161         addSuperCall((JavaChangeInfo)changeInfo, constructor, defConstructorUsage.getBaseConstructor(), usages);
162         return true;
163       }
164       else if (usage instanceof NoConstructorClassUsageInfo) {
165         addDefaultConstructor(((JavaChangeInfo)changeInfo), ((NoConstructorClassUsageInfo)usage).getPsiClass(), usages);
166         return true;
167       }
168       else if (usage instanceof MethodReferenceUsageInfo && MethodReferenceUsageInfo.needToExpand((JavaChangeInfo)changeInfo)) {
169         final MethodCallUsageInfo methodCallInfo = ((MethodReferenceUsageInfo)usage).createMethodCallInfo();
170         if (methodCallInfo != null) {
171           processMethodUsage(methodCallInfo.getElement(), (JavaChangeInfo)changeInfo, methodCallInfo.isToChangeArguments(),
172                              methodCallInfo.isToCatchExceptions(), methodCallInfo.getReferencedMethod(), methodCallInfo.getSubstitutor(), usages);
173           return true;
174         }
175       }
176       else if (usage instanceof MethodCallUsageInfo) {
177         final MethodCallUsageInfo methodCallInfo = (MethodCallUsageInfo)usage;
178         processMethodUsage(methodCallInfo.getElement(), (JavaChangeInfo)changeInfo, methodCallInfo.isToChangeArguments(),
179                            methodCallInfo.isToCatchExceptions(), methodCallInfo.getReferencedMethod(), methodCallInfo.getSubstitutor(), usages);
180         return true;
181       }
182       else if (usage instanceof ChangeSignatureParameterUsageInfo) {
183         String newName = ((ChangeSignatureParameterUsageInfo)usage).newParameterName;
184         String oldName = ((ChangeSignatureParameterUsageInfo)usage).oldParameterName;
185         processParameterUsage((PsiReferenceExpression)element, oldName, newName);
186         return true;
187       }
188       else if (usage instanceof CallReferenceUsageInfo) {
189         ((CallReferenceUsageInfo)usage).getReference().handleChangeSignature(changeInfo);
190         return true;
191       }
192       else if (element instanceof PsiEnumConstant) {
193         fixActualArgumentsList(((PsiEnumConstant)element).getArgumentList(), (JavaChangeInfo)changeInfo, true, PsiSubstitutor.EMPTY);
194         return true;
195       }
196       else if (!(usage instanceof OverriderUsageInfo)) {
197         PsiReference reference = usage instanceof MoveRenameUsageInfo ? usage.getReference() : element.getReference();
198         if (reference != null) {
199           PsiElement target = changeInfo.getMethod();
200           if (target != null) {
201             reference.bindToElement(target);
202           }
203         }
204       }
205     }
206     return false;
207   }
208
209   private static void processParameterUsage(PsiReferenceExpression ref, String oldName, String newName)
210     throws IncorrectOperationException {
211
212     PsiElement last = ref.getReferenceNameElement();
213     if (last instanceof PsiIdentifier && last.getText().equals(oldName)) {
214       PsiElementFactory factory = JavaPsiFacade.getInstance(ref.getProject()).getElementFactory();
215       PsiIdentifier newNameIdentifier = factory.createIdentifier(newName);
216       last.replace(newNameIdentifier);
217     }
218   }
219
220
221   private static void addDefaultConstructor(JavaChangeInfo changeInfo, PsiClass aClass, final UsageInfo[] usages)
222     throws IncorrectOperationException {
223     if (!(aClass instanceof PsiAnonymousClass)) {
224       PsiElementFactory factory = JavaPsiFacade.getElementFactory(aClass.getProject());
225       PsiMethod defaultConstructor = factory.createMethodFromText(aClass.getName() + "(){}", aClass);
226       defaultConstructor = (PsiMethod)CodeStyleManager.getInstance(aClass.getProject()).reformat(defaultConstructor);
227       defaultConstructor = (PsiMethod)aClass.add(defaultConstructor);
228       PsiUtil.setModifierProperty(defaultConstructor, VisibilityUtil.getVisibilityModifier(aClass.getModifierList()), true);
229       addSuperCall(changeInfo, defaultConstructor, null, usages);
230     }
231     else {
232       final PsiElement parent = aClass.getParent();
233       if (parent instanceof PsiNewExpression) {
234         final PsiExpressionList argumentList = ((PsiNewExpression)parent).getArgumentList();
235         final PsiClass baseClass = changeInfo.getMethod().getContainingClass();
236         final PsiSubstitutor substitutor = TypeConversionUtil.getSuperClassSubstitutor(baseClass, aClass, PsiSubstitutor.EMPTY);
237         fixActualArgumentsList(argumentList, changeInfo, true, substitutor);
238       }
239     }
240   }
241
242   private static void addSuperCall(JavaChangeInfo changeInfo, PsiMethod constructor, PsiMethod callee, final UsageInfo[] usages)
243     throws IncorrectOperationException {
244     final PsiElementFactory factory = JavaPsiFacade.getElementFactory(constructor.getProject());
245     PsiExpressionStatement superCall = (PsiExpressionStatement)factory.createStatementFromText("super();", constructor);
246     PsiCodeBlock body = constructor.getBody();
247     assert body != null;
248     PsiStatement[] statements = body.getStatements();
249     if (statements.length > 0) {
250       superCall = (PsiExpressionStatement)body.addBefore(superCall, statements[0]);
251     }
252     else {
253       superCall = (PsiExpressionStatement)body.add(superCall);
254     }
255     PsiMethodCallExpression callExpression = (PsiMethodCallExpression)superCall.getExpression();
256     final PsiClass aClass = constructor.getContainingClass();
257     final PsiClass baseClass = changeInfo.getMethod().getContainingClass();
258     final PsiSubstitutor substitutor = TypeConversionUtil.getSuperClassSubstitutor(baseClass, aClass, PsiSubstitutor.EMPTY);
259     processMethodUsage(callExpression.getMethodExpression(), changeInfo, true, false, callee, substitutor, usages);
260   }
261
262   private static void processMethodUsage(PsiElement ref,
263                                   JavaChangeInfo changeInfo,
264                                   boolean toChangeArguments,
265                                   boolean toCatchExceptions,
266                                   PsiMethod callee, PsiSubstitutor subsitutor, final UsageInfo[] usages) throws IncorrectOperationException {
267     if (changeInfo.isNameChanged()) {
268       if (ref instanceof PsiJavaCodeReferenceElement) {
269         PsiElement last = ((PsiJavaCodeReferenceElement)ref).getReferenceNameElement();
270         if (last instanceof PsiIdentifier && last.getText().equals(changeInfo.getOldName())) {
271           last.replace(changeInfo.getNewNameIdentifier());
272         }
273       }
274     }
275
276     final PsiMethod caller = RefactoringUtil.getEnclosingMethod(ref);
277     if (toChangeArguments) {
278       final PsiExpressionList list = RefactoringUtil.getArgumentListByMethodReference(ref);
279       LOG.assertTrue(list != null);
280       boolean toInsertDefaultValue = needDefaultValue(changeInfo, caller);
281       if (toInsertDefaultValue && ref instanceof PsiReferenceExpression) {
282         final PsiExpression qualifierExpression = ((PsiReferenceExpression)ref).getQualifierExpression();
283         if (qualifierExpression instanceof PsiSuperExpression && callerSignatureIsAboutToChangeToo(caller, usages)) {
284           toInsertDefaultValue = false;
285         }
286       }
287
288       fixActualArgumentsList(list, changeInfo, toInsertDefaultValue, subsitutor);
289     }
290
291     if (toCatchExceptions) {
292       if (!(ref instanceof PsiReferenceExpression &&
293             JavaHighlightUtil.isSuperOrThisCall(PsiTreeUtil.getParentOfType(ref, PsiStatement.class), true, false))) {
294         if (needToCatchExceptions(changeInfo, caller)) {
295           PsiClassType[] newExceptions =
296             callee != null ? getCalleeChangedExceptionInfo(callee) : getPrimaryChangedExceptionInfo(changeInfo);
297           fixExceptions(ref, newExceptions);
298         }
299       }
300     }
301   }
302
303   private static boolean callerSignatureIsAboutToChangeToo(final PsiMethod caller, final UsageInfo[] usages) {
304     for (UsageInfo usage : usages) {
305       if (usage instanceof MethodCallUsageInfo &&
306           MethodSignatureUtil.isSuperMethod(((MethodCallUsageInfo)usage).getReferencedMethod(), caller)) {
307         return true;
308       }
309     }
310     return false;
311   }
312
313   private static PsiClassType[] getCalleeChangedExceptionInfo(final PsiMethod callee) {
314     return callee.getThrowsList().getReferencedTypes(); //Callee method's throws list is already modified!
315   }
316
317   private static void fixExceptions(PsiElement ref, PsiClassType[] newExceptions) throws IncorrectOperationException {
318     //methods' throws lists are already modified, may use ExceptionUtil.collectUnhandledExceptions
319     newExceptions = filterCheckedExceptions(newExceptions);
320
321     PsiElement context = PsiTreeUtil.getParentOfType(ref, PsiTryStatement.class, PsiMethod.class, PsiLambdaExpression.class);
322     if (context instanceof PsiTryStatement) {
323       PsiTryStatement tryStatement = (PsiTryStatement)context;
324       PsiCodeBlock tryBlock = tryStatement.getTryBlock();
325
326       //Remove unused catches
327       Collection<PsiClassType> classes = ExceptionUtil.collectUnhandledExceptions(tryBlock, tryBlock);
328       PsiParameter[] catchParameters = tryStatement.getCatchBlockParameters();
329       for (PsiParameter parameter : catchParameters) {
330         final PsiType caughtType = parameter.getType();
331
332         if (!(caughtType instanceof PsiClassType)) continue;
333         if (ExceptionUtil.isUncheckedExceptionOrSuperclass((PsiClassType)caughtType)) continue;
334
335         if (!isCatchParameterRedundant((PsiClassType)caughtType, classes)) continue;
336         parameter.getParent().delete(); //delete catch section
337       }
338
339       PsiClassType[] exceptionsToAdd = filterUnhandledExceptions(newExceptions, tryBlock);
340       addExceptions(exceptionsToAdd, tryStatement);
341
342       adjustPossibleEmptyTryStatement(tryStatement);
343     }
344     else {
345       newExceptions = filterUnhandledExceptions(newExceptions, ref);
346       if (newExceptions.length > 0) {
347         //Add new try statement
348         PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(ref.getProject());
349         PsiTryStatement tryStatement = (PsiTryStatement)elementFactory.createStatementFromText("try {} catch (Exception e) {}", null);
350         PsiStatement anchor;
351         PsiElement lambdaBody = context instanceof PsiLambdaExpression ? ((PsiLambdaExpression)context).getBody() : null;
352         if (lambdaBody instanceof PsiExpression) {
353           PsiCodeBlock codeBlock = (PsiCodeBlock)((PsiLambdaExpression)RefactoringUtil.expandExpressionLambdaToCodeBlock(lambdaBody)).getBody();
354           LOG.assertTrue(codeBlock != null);
355           anchor = codeBlock.getStatements()[0];
356         }
357         else {
358           anchor = PsiTreeUtil.getParentOfType(ref, PsiStatement.class);
359         }
360         LOG.assertTrue(anchor != null);
361         tryStatement.getTryBlock().add(anchor);
362         tryStatement = (PsiTryStatement)anchor.getParent().addAfter(tryStatement, anchor);
363
364         addExceptions(newExceptions, tryStatement);
365         anchor.delete();
366         tryStatement.getCatchSections()[0].delete(); //Delete dummy catch section
367       }
368     }
369   }
370
371   public static boolean hasNewCheckedExceptions(JavaChangeInfo changeInfo) {
372     return filterCheckedExceptions(getPrimaryChangedExceptionInfo(changeInfo)).length > 0;
373   }
374
375   private static PsiClassType[] filterCheckedExceptions(PsiClassType[] exceptions) {
376     List<PsiClassType> result = new ArrayList<>();
377     for (PsiClassType exceptionType : exceptions) {
378       if (!ExceptionUtil.isUncheckedException(exceptionType)) result.add(exceptionType);
379     }
380     return result.toArray(new PsiClassType[result.size()]);
381   }
382
383   private static void adjustPossibleEmptyTryStatement(PsiTryStatement tryStatement) throws IncorrectOperationException {
384     PsiCodeBlock tryBlock = tryStatement.getTryBlock();
385     if (tryBlock != null) {
386       if (tryStatement.getCatchSections().length == 0 &&
387           tryStatement.getFinallyBlock() == null) {
388         PsiElement firstBodyElement = tryBlock.getFirstBodyElement();
389         if (firstBodyElement != null) {
390           tryStatement.getParent().addRangeAfter(firstBodyElement, tryBlock.getLastBodyElement(), tryStatement);
391         }
392         tryStatement.delete();
393       }
394     }
395   }
396
397   private static void addExceptions(PsiClassType[] exceptionsToAdd, PsiTryStatement tryStatement) throws IncorrectOperationException {
398     for (PsiClassType type : exceptionsToAdd) {
399       final JavaCodeStyleManager styleManager = JavaCodeStyleManager.getInstance(tryStatement.getProject());
400       String name = styleManager.suggestVariableName(VariableKind.PARAMETER, null, null, type).names[0];
401       name = styleManager.suggestUniqueVariableName(name, tryStatement, false);
402
403       PsiCatchSection catchSection =
404         JavaPsiFacade.getInstance(tryStatement.getProject()).getElementFactory().createCatchSection(type, name, tryStatement);
405       tryStatement.add(catchSection);
406     }
407   }
408
409   private static PsiClassType[] filterUnhandledExceptions(PsiClassType[] exceptions, PsiElement place) {
410     List<PsiClassType> result = new ArrayList<>();
411     for (PsiClassType exception : exceptions) {
412       if (!ExceptionUtil.isHandled(exception, place)) result.add(exception);
413     }
414     return result.toArray(new PsiClassType[result.size()]);
415   }
416
417   private static boolean isCatchParameterRedundant(PsiClassType catchParamType, Collection<PsiClassType> thrownTypes) {
418     for (PsiType exceptionType : thrownTypes) {
419       if (exceptionType.isConvertibleFrom(catchParamType)) return false;
420     }
421     return true;
422   }
423
424   //This methods works equally well for primary usages as well as for propagated callers' usages
425   private static void fixActualArgumentsList(PsiExpressionList list,
426                                              JavaChangeInfo changeInfo,
427                                              boolean toInsertDefaultValue,
428                                              PsiSubstitutor substitutor) throws IncorrectOperationException {
429     final PsiElementFactory factory = JavaPsiFacade.getInstance(list.getProject()).getElementFactory();
430     if (changeInfo.isParameterSetOrOrderChanged()) {
431       if (changeInfo instanceof JavaChangeInfoImpl && ((JavaChangeInfoImpl)changeInfo).isPropagationEnabled) {
432         final ParameterInfoImpl[] createdParmsInfo = ((JavaChangeInfoImpl)changeInfo).getCreatedParmsInfoWithoutVarargs();
433         for (ParameterInfoImpl info : createdParmsInfo) {
434           PsiExpression newArg;
435           if (toInsertDefaultValue) {
436             newArg = createDefaultValue(changeInfo, factory, info, list, substitutor);
437           }
438           else {
439             newArg = factory.createExpressionFromText(info.getName(), list);
440           }
441           if (newArg != null) JavaCodeStyleManager.getInstance(list.getProject()).shortenClassReferences(list.add(newArg));
442         }
443       }
444       else {
445         final PsiExpression[] args = list.getExpressions();
446         final int nonVarargCount = getNonVarargCount(changeInfo, args);
447         final int varargCount = args.length - nonVarargCount;
448         if (varargCount<0) return;
449         PsiExpression[] newVarargInitializers = null;
450
451         final int newArgsLength;
452         final int newNonVarargCount;
453         final JavaParameterInfo[] newParms = changeInfo.getNewParameters();
454         if (changeInfo.isArrayToVarargs()) {
455           newNonVarargCount = newParms.length - 1;
456           final JavaParameterInfo lastNewParm = newParms[newParms.length - 1];
457           final PsiExpression arrayToConvert = args[lastNewParm.getOldIndex()];
458           if (arrayToConvert instanceof PsiNewExpression) {
459             final PsiNewExpression expression = (PsiNewExpression)arrayToConvert;
460             final PsiArrayInitializerExpression arrayInitializer = expression.getArrayInitializer();
461             if (arrayInitializer != null) {
462               newVarargInitializers = arrayInitializer.getInitializers();
463             }
464           }
465           newArgsLength = newVarargInitializers == null ? newParms.length : newNonVarargCount + newVarargInitializers.length;
466         }
467         else if (changeInfo.isRetainsVarargs()) {
468           newNonVarargCount = newParms.length - 1;
469           newArgsLength = newNonVarargCount + varargCount;
470         }
471         else if (changeInfo.isObtainsVarags()) {
472           newNonVarargCount = newParms.length - 1;
473           newArgsLength = newNonVarargCount;
474         }
475         else {
476           newNonVarargCount = newParms.length;
477           newArgsLength = newParms.length;
478         }
479
480         String[] oldVarargs = null;
481         if (changeInfo.wasVararg() && !changeInfo.isRetainsVarargs()) {
482           oldVarargs = new String[varargCount];
483           for (int i = nonVarargCount; i < args.length; i++) {
484             oldVarargs[i - nonVarargCount] = args[i].getText();
485           }
486         }
487
488         final PsiExpression[] newArgs = new PsiExpression[newArgsLength];
489         for (int i = 0; i < newNonVarargCount; i++) {
490           if (newParms[i].getOldIndex() == nonVarargCount && oldVarargs != null) {
491             PsiType type = newParms[i].createType(changeInfo.getMethod(), list.getManager());
492             if (type instanceof PsiArrayType) {
493               type = substitutor.substitute(type);
494               type = TypeConversionUtil.erasure(type);
495               String typeText = type.getCanonicalText();
496               if (type instanceof PsiEllipsisType) {
497                 typeText = typeText.replace("...", "[]");
498               }
499               String text = "new " + typeText + "{" + StringUtil.join(oldVarargs, ",") + "}";
500               newArgs[i] = factory.createExpressionFromText(text, changeInfo.getMethod());
501               continue;
502             }
503           }
504           newArgs[i] = createActualArgument(changeInfo, list, newParms[i], toInsertDefaultValue, args, substitutor);
505         }
506         if (changeInfo.isArrayToVarargs()) {
507           if (newVarargInitializers == null) {
508             newArgs[newNonVarargCount] =
509               createActualArgument(changeInfo, list, newParms[newNonVarargCount], toInsertDefaultValue, args, substitutor);
510           }
511           else {
512             System.arraycopy(newVarargInitializers, 0, newArgs, newNonVarargCount, newVarargInitializers.length);
513           }
514         }
515         else {
516           final int newVarargCount = newArgsLength - newNonVarargCount;
517           LOG.assertTrue(newVarargCount == 0 || newVarargCount == varargCount);
518           for (int i = newNonVarargCount; i < newArgsLength; i++){
519             final int oldIndex = newParms[newNonVarargCount].getOldIndex();
520             if (oldIndex >= 0 && oldIndex != nonVarargCount) {
521               newArgs[i] = createActualArgument(changeInfo, list, newParms[newNonVarargCount], toInsertDefaultValue, args, substitutor);
522             } else {
523               System.arraycopy(args, nonVarargCount, newArgs, newNonVarargCount, newVarargCount);
524               break;
525             }
526           }
527         }
528         ChangeSignatureUtil.synchronizeList(list, Arrays.asList(newArgs), ExpressionList.INSTANCE, changeInfo.toRemoveParm());
529       }
530     }
531   }
532
533   private static int getNonVarargCount(JavaChangeInfo changeInfo, PsiExpression[] args) {
534     if (!changeInfo.wasVararg()) return args.length;
535     return changeInfo.getOldParameterTypes().length - 1;
536   }
537
538
539   @Nullable
540   private static PsiExpression createActualArgument(JavaChangeInfo changeInfo,
541                                                     final PsiExpressionList list,
542                                                     final JavaParameterInfo info,
543                                                     final boolean toInsertDefaultValue,
544                                                     final PsiExpression[] args,
545                                                     PsiSubstitutor substitutor) throws IncorrectOperationException {
546     final PsiElementFactory factory = JavaPsiFacade.getInstance(list.getProject()).getElementFactory();
547     final int index = info.getOldIndex();
548     if (index >= 0 && index < args.length) {
549       return args[index];
550     }
551     else {
552       if (toInsertDefaultValue) {
553         return createDefaultValue(changeInfo, factory, info, list, substitutor);
554       }
555       else {
556         return factory.createExpressionFromText(info.getName(), list);
557       }
558     }
559   }
560
561   @Nullable
562   private static PsiExpression createDefaultValue(JavaChangeInfo changeInfo,
563                                                   final PsiElementFactory factory,
564                                                   final JavaParameterInfo info,
565                                                   final PsiExpressionList list, PsiSubstitutor substitutor)
566     throws IncorrectOperationException {
567     if (info.isUseAnySingleVariable()) {
568       final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(list.getProject()).getResolveHelper();
569       final PsiType type = info.getTypeWrapper().getType(changeInfo.getMethod(), list.getManager());
570       final VariablesProcessor processor = new VariablesProcessor(false) {
571         @Override
572         protected boolean check(PsiVariable var, ResolveState state) {
573           if (var instanceof PsiField && !resolveHelper.isAccessible((PsiField)var, list, null)) return false;
574           if (var instanceof PsiLocalVariable && list.getTextRange().getStartOffset() <= var.getTextRange().getStartOffset()) return false;
575           if (PsiTreeUtil.isAncestor(var, list, false)) return false;
576           final PsiType varType = state.get(PsiSubstitutor.KEY).substitute(var.getType());
577           return type.isAssignableFrom(varType);
578         }
579
580         @Override
581         public boolean execute(@NotNull PsiElement pe, @NotNull ResolveState state) {
582           super.execute(pe, state);
583           return size() < 2;
584         }
585       };
586       PsiScopesUtil.treeWalkUp(processor, list, null);
587       if (processor.size() == 1) {
588         final PsiVariable result = processor.getResult(0);
589         return factory.createExpressionFromText(result.getName(), list);
590       }
591       if (processor.size() == 0) {
592         final PsiClass parentClass = PsiTreeUtil.getParentOfType(list, PsiClass.class);
593         if (parentClass != null) {
594           PsiClass containingClass = parentClass;
595           final Set<PsiClass> containingClasses = new HashSet<>();
596           while (containingClass != null) {
597             if (type.isAssignableFrom(factory.createType(containingClass, PsiSubstitutor.EMPTY))) {
598               containingClasses.add(containingClass);
599             }
600             containingClass = PsiTreeUtil.getParentOfType(containingClass, PsiClass.class);
601           }
602           if (containingClasses.size() == 1) {
603             return RefactoringChangeUtil.createThisExpression(parentClass.getManager(), containingClasses.contains(parentClass) ? null
604                                                                                                                                 : containingClasses
605                                                                                           .iterator().next());
606           }
607         }
608       }
609     }
610     final PsiCallExpression callExpression = PsiTreeUtil.getParentOfType(list, PsiCallExpression.class);
611     final String defaultValue = info.getDefaultValue();
612     return callExpression != null ? (PsiExpression)info.getActualValue(callExpression, substitutor)
613                                   : !StringUtil.isEmpty(defaultValue) ? factory.createExpressionFromText(defaultValue, list) : null;
614   }
615
616
617   @Override
618   public boolean processPrimaryMethod(ChangeInfo changeInfo) {
619     if (!StdLanguages.JAVA.equals(changeInfo.getLanguage()) || !(changeInfo instanceof JavaChangeInfo)) return false;
620     final PsiElement element = changeInfo.getMethod();
621     LOG.assertTrue(element instanceof PsiMethod);
622     if (!JavaLanguage.INSTANCE.equals(element.getLanguage())) return false;
623     if (changeInfo.isGenerateDelegate()) {
624       generateDelegate((JavaChangeInfo)changeInfo);
625     }
626     processPrimaryMethod((JavaChangeInfo)changeInfo, (PsiMethod)element, null, true);
627     return true;
628   }
629
630   @Override
631   public boolean shouldPreviewUsages(ChangeInfo changeInfo, UsageInfo[] usages) {
632     return false;
633   }
634
635   @Override
636   public boolean setupDefaultValues(ChangeInfo changeInfo, Ref<UsageInfo[]> refUsages, Project project) {
637     if (!(changeInfo instanceof JavaChangeInfo)) return true;
638     for (UsageInfo usageInfo : refUsages.get()) {
639       if (usageInfo instanceof  MethodCallUsageInfo) {
640         MethodCallUsageInfo methodCallUsageInfo = (MethodCallUsageInfo)usageInfo;
641         if (methodCallUsageInfo.isToChangeArguments()){
642           final PsiElement element = methodCallUsageInfo.getElement();
643           if (element == null) continue;
644           final PsiMethod caller = RefactoringUtil.getEnclosingMethod(element);
645           final boolean needDefaultValue = needDefaultValue(changeInfo, caller);
646           if (needDefaultValue && (caller == null || !MethodSignatureUtil.isSuperMethod(methodCallUsageInfo.getReferencedMethod(), caller))) {
647             final ParameterInfo[] parameters = changeInfo.getNewParameters();
648             for (ParameterInfo parameter : parameters) {
649               final String defaultValue = parameter.getDefaultValue();
650               if (defaultValue == null && parameter.getOldIndex() == -1) {
651                 ((ParameterInfoImpl)parameter).setDefaultValue("");
652                 if (!ApplicationManager.getApplication().isUnitTestMode()) {
653                   final PsiType type = ((ParameterInfoImpl)parameter).getTypeWrapper().getType(element);
654                   final DefaultValueChooser chooser =
655                     new DefaultValueChooser(project, parameter.getName(), PsiTypesUtil.getDefaultValueOfType(type));
656                   if (chooser.showAndGet()) {
657                     if (chooser.feelLucky()) {
658                       parameter.setUseAnySingleVariable(true);
659                     }
660                     else {
661                       ((ParameterInfoImpl)parameter).setDefaultValue(chooser.getDefaultValue());
662                     }
663                   }
664                   else {
665                     return false;
666                   }
667                 }
668               }
669             }
670           }
671         }
672       }
673     }
674     return true;
675   }
676
677   @Override
678   public void registerConflictResolvers(List<ResolveSnapshotProvider.ResolveSnapshot> snapshots,
679                                         @NotNull ResolveSnapshotProvider resolveSnapshotProvider,
680                                         UsageInfo[] usages, ChangeInfo changeInfo) {
681     snapshots.add(resolveSnapshotProvider.createSnapshot(changeInfo.getMethod()));
682     for (UsageInfo usage : usages) {
683       if (usage instanceof OverriderUsageInfo) {
684         snapshots.add(resolveSnapshotProvider.createSnapshot(((OverriderUsageInfo)usage).getOverridingMethod()));
685       }
686     }
687   }
688
689   private static boolean needDefaultValue(ChangeInfo changeInfo, @Nullable PsiMethod method) {
690     if (!(changeInfo instanceof JavaChangeInfoImpl)) {
691       return true;
692     }
693     if (method != null) {
694       final Set<PsiMethod> parametersMethods = ((JavaChangeInfoImpl)changeInfo).propagateParametersMethods;
695       if (parametersMethods.contains(method)) {
696         return false;
697       }
698       for (PsiMethod superMethod : method.findDeepestSuperMethods()) {
699         if (parametersMethods.contains(superMethod)) {
700           return false;
701         }
702       }
703     }
704     return true;
705   }
706
707   public static void generateDelegate(JavaChangeInfo changeInfo) throws IncorrectOperationException {
708     final PsiMethod delegate = (PsiMethod)changeInfo.getMethod().copy();
709     final PsiClass targetClass = changeInfo.getMethod().getContainingClass();
710     LOG.assertTrue(targetClass != null);
711     if (targetClass.isInterface() && delegate.getBody() == null) {
712       delegate.getModifierList().setModifierProperty(PsiModifier.DEFAULT, true);
713     }
714     PsiElementFactory factory = JavaPsiFacade.getElementFactory(targetClass.getProject());
715     ChangeSignatureProcessor.makeEmptyBody(factory, delegate);
716     final PsiCallExpression callExpression = ChangeSignatureProcessor.addDelegatingCallTemplate(delegate, changeInfo.getNewName());
717     addDelegateArguments(changeInfo, factory, callExpression);
718     targetClass.addBefore(delegate, changeInfo.getMethod());
719   }
720
721
722   private static void addDelegateArguments(JavaChangeInfo changeInfo, PsiElementFactory factory, final PsiCallExpression callExpression) throws IncorrectOperationException {
723     final JavaParameterInfo[] newParms = changeInfo.getNewParameters();
724     final String[] oldParameterNames = changeInfo.getOldParameterNames();
725     for (JavaParameterInfo newParm : newParms) {
726       final PsiExpression actualArg;
727       if (newParm.getOldIndex() >= 0) {
728         actualArg = factory.createExpressionFromText(oldParameterNames[newParm.getOldIndex()], callExpression);
729       }
730       else {
731         actualArg = (PsiExpression)newParm.getActualValue(callExpression, PsiSubstitutor.EMPTY);
732       }
733       final PsiExpressionList argumentList = callExpression.getArgumentList();
734       if (actualArg != null && argumentList != null) {
735         JavaCodeStyleManager.getInstance(callExpression.getProject()).shortenClassReferences(argumentList.add(actualArg));
736       }
737     }
738   }
739
740   private static void processPrimaryMethod(JavaChangeInfo changeInfo, PsiMethod method,
741                                            PsiMethod baseMethod,
742                                            boolean isOriginal) throws IncorrectOperationException {
743     PsiElementFactory factory = JavaPsiFacade.getInstance(method.getProject()).getElementFactory();
744
745     if (changeInfo.isVisibilityChanged()) {
746       PsiModifierList modifierList = method.getModifierList();
747       final String highestVisibility = isOriginal
748                                        ? changeInfo.getNewVisibility()
749                                        : VisibilityUtil.getHighestVisibility(changeInfo.getNewVisibility(),
750                                                                              VisibilityUtil.getVisibilityModifier(modifierList));
751       VisibilityUtil.setVisibility(modifierList, highestVisibility);
752     }
753
754     if (changeInfo.isNameChanged()) {
755       String newName = baseMethod == null ? changeInfo.getNewName() :
756                        RefactoringUtil.suggestNewOverriderName(method.getName(), baseMethod.getName(), changeInfo.getNewName());
757
758       if (newName != null && !newName.equals(method.getName())) {
759         final PsiIdentifier nameId = method.getNameIdentifier();
760         assert nameId != null;
761         nameId.replace(JavaPsiFacade.getInstance(method.getProject()).getElementFactory().createIdentifier(newName));
762       }
763     }
764
765     final PsiSubstitutor substitutor =
766       baseMethod == null ? PsiSubstitutor.EMPTY : ChangeSignatureProcessor.calculateSubstitutor(method, baseMethod);
767
768     final JavaCodeStyleManager javaCodeStyleManager = JavaCodeStyleManager.getInstance(method.getProject());
769     if (changeInfo.isReturnTypeChanged()) {
770       PsiType newTypeElement = changeInfo.getNewReturnType().getType(changeInfo.getMethod().getParameterList(), method.getManager());
771       final PsiType returnType = substitutor.substitute(newTypeElement);
772       // don't modify return type for non-Java overriders (EJB)
773       if (method.getName().equals(changeInfo.getNewName())) {
774         final PsiTypeElement typeElement = method.getReturnTypeElement();
775         if (typeElement != null) {
776           javaCodeStyleManager.shortenClassReferences(typeElement.replace(factory.createTypeElement(returnType)));
777         }
778       }
779     }
780
781     PsiParameterList list = method.getParameterList();
782     int newParamsLength = processMethodParams(changeInfo, baseMethod, factory, substitutor, list, method.getBody());
783     fixJavadocsForChangedMethod(method, changeInfo, newParamsLength);
784     if (changeInfo.isExceptionSetOrOrderChanged()) {
785       final PsiClassType[] newExceptions = getPrimaryChangedExceptionInfo(changeInfo);
786       fixPrimaryThrowsLists(method, newExceptions);
787     }
788
789     if (baseMethod == null && method.findSuperMethods().length == 0) {
790       final PsiAnnotation annotation = AnnotationUtil.findAnnotation(method, true, Override.class.getName());
791       if (annotation != null) {
792         annotation.delete();
793       }
794     }
795   }
796
797   private static int processMethodParams(JavaChangeInfo changeInfo,
798                                          PsiMethod baseMethod,
799                                          PsiElementFactory factory,
800                                          PsiSubstitutor substitutor,
801                                          PsiParameterList list,
802                                          PsiElement methodBody) {
803     PsiParameter[] parameters = list.getParameters();
804
805     final JavaParameterInfo[] parameterInfos = changeInfo.getNewParameters();
806     final int delta = baseMethod != null ? baseMethod.getParameterList().getParametersCount() - list.getParametersCount() : 0;
807     PsiParameter[] newParms = new PsiParameter[Math.max(parameterInfos.length - delta, 0)];
808     final String[] oldParameterNames = changeInfo.getOldParameterNames();
809     final String[] oldParameterTypes = changeInfo.getOldParameterTypes();
810     for (int i = 0; i < newParms.length; i++) {
811       JavaParameterInfo info = parameterInfos[i];
812       int index = info.getOldIndex();
813       if (index >= 0) {
814         PsiParameter parameter = parameters[index];
815         newParms[i] = parameter;
816
817         String oldName = oldParameterNames[index];
818         if (!oldName.equals(info.getName()) && oldName.equals(parameter.getName())) {
819           PsiIdentifier newIdentifier = factory.createIdentifier(info.getName());
820           parameter.getNameIdentifier().replace(newIdentifier);
821         }
822
823         final PsiTypeElement typeElement = parameter.getTypeElement();
824         if (typeElement != null) {
825           String oldType = oldParameterTypes[index];
826           if (!oldType.equals(info.getTypeText())) {
827             parameter.normalizeDeclaration();
828             PsiType newType =
829               substitutor.substitute(info.createType(changeInfo.getMethod().getParameterList(), changeInfo.getMethod().getManager()));
830             typeElement.replace(factory.createTypeElement(newType));
831           }
832         }
833       }
834       else {
835         newParms[i] = createNewParameter(changeInfo, info, substitutor);
836       }
837     }
838
839
840     resolveParameterVsFieldsConflicts(newParms, list, changeInfo.toRemoveParm(), methodBody);
841     return newParms.length;
842   }
843
844   private static PsiClassType[] getPrimaryChangedExceptionInfo(JavaChangeInfo changeInfo) throws IncorrectOperationException {
845     final ThrownExceptionInfo[] newExceptionInfos = changeInfo.getNewExceptions();
846     PsiClassType[] newExceptions = new PsiClassType[newExceptionInfos.length];
847     final PsiMethod method = changeInfo.getMethod();
848     for (int i = 0; i < newExceptions.length; i++) {
849       newExceptions[i] =
850         (PsiClassType)newExceptionInfos[i].createType(method, method.getManager()); //context really does not matter here
851     }
852     return newExceptions;
853   }
854
855
856   private static void processCallerMethod(JavaChangeInfo changeInfo, PsiMethod caller,
857                                           PsiMethod baseMethod,
858                                           boolean toInsertParams,
859                                           boolean toInsertThrows) throws IncorrectOperationException {
860     LOG.assertTrue(toInsertParams || toInsertThrows);
861     if (toInsertParams) {
862       List<PsiParameter> newParameters = new ArrayList<>();
863       ContainerUtil.addAll(newParameters, caller.getParameterList().getParameters());
864       final JavaParameterInfo[] primaryNewParms = changeInfo.getNewParameters();
865       PsiSubstitutor substitutor =
866         baseMethod == null ? PsiSubstitutor.EMPTY : ChangeSignatureProcessor.calculateSubstitutor(caller, baseMethod);
867       final PsiClass aClass = changeInfo.getMethod().getContainingClass();
868       final PsiClass callerContainingClass = caller.getContainingClass();
869       final PsiSubstitutor psiSubstitutor = aClass != null && callerContainingClass != null && callerContainingClass.isInheritor(aClass, true)
870                                             ? TypeConversionUtil.getSuperClassSubstitutor(aClass, callerContainingClass, substitutor)
871                                             : PsiSubstitutor.EMPTY;
872       for (JavaParameterInfo info : primaryNewParms) {
873         if (info.getOldIndex() < 0) newParameters.add(createNewParameter(changeInfo, info, psiSubstitutor, substitutor));
874       }
875       PsiParameter[] arrayed = newParameters.toArray(new PsiParameter[newParameters.size()]);
876       boolean[] toRemoveParm = new boolean[arrayed.length];
877       Arrays.fill(toRemoveParm, false);
878       resolveParameterVsFieldsConflicts(arrayed, caller.getParameterList(), toRemoveParm, caller.getBody());
879     }
880
881     if (toInsertThrows) {
882       List<PsiJavaCodeReferenceElement> newThrowns = new ArrayList<>();
883       final PsiReferenceList throwsList = caller.getThrowsList();
884       ContainerUtil.addAll(newThrowns, throwsList.getReferenceElements());
885       final ThrownExceptionInfo[] primaryNewExns = changeInfo.getNewExceptions();
886       for (ThrownExceptionInfo thrownExceptionInfo : primaryNewExns) {
887         if (thrownExceptionInfo.getOldIndex() < 0) {
888           final PsiClassType type = (PsiClassType)thrownExceptionInfo.createType(caller, caller.getManager());
889           final PsiJavaCodeReferenceElement ref =
890             JavaPsiFacade.getInstance(caller.getProject()).getElementFactory().createReferenceElementByType(type);
891           newThrowns.add(ref);
892         }
893       }
894       PsiJavaCodeReferenceElement[] arrayed = newThrowns.toArray(new PsiJavaCodeReferenceElement[newThrowns.size()]);
895       boolean[] toRemoveParm = new boolean[arrayed.length];
896       Arrays.fill(toRemoveParm, false);
897       ChangeSignatureUtil.synchronizeList(throwsList, Arrays.asList(arrayed), ThrowsList.INSTANCE, toRemoveParm);
898     }
899   }
900
901   private static void fixPrimaryThrowsLists(PsiMethod method, PsiClassType[] newExceptions) throws IncorrectOperationException {
902     PsiElementFactory elementFactory = JavaPsiFacade.getInstance(method.getProject()).getElementFactory();
903     PsiJavaCodeReferenceElement[] refs = new PsiJavaCodeReferenceElement[newExceptions.length];
904     for (int i = 0; i < refs.length; i++) {
905       refs[i] = elementFactory.createReferenceElementByType(newExceptions[i]);
906     }
907     PsiReferenceList throwsList = elementFactory.createReferenceList(refs);
908
909     PsiReferenceList methodThrowsList = (PsiReferenceList)method.getThrowsList().replace(throwsList);
910     methodThrowsList = (PsiReferenceList)JavaCodeStyleManager.getInstance(method.getProject()).shortenClassReferences(methodThrowsList);
911     CodeStyleManager.getInstance(method.getManager().getProject())
912         .reformatRange(method, method.getParameterList().getTextRange().getEndOffset(),
913                        methodThrowsList.getTextRange().getEndOffset());
914   }
915
916   private static void fixJavadocsForChangedMethod(final PsiMethod method, final JavaChangeInfo changeInfo, int newParamsLength) throws IncorrectOperationException {
917     final PsiParameter[] parameters = method.getParameterList().getParameters();
918     final JavaParameterInfo[] newParms = changeInfo.getNewParameters();
919     LOG.assertTrue(parameters.length <= newParamsLength);
920     final Set<PsiParameter> newParameters = new HashSet<>();
921     final String[] oldParameterNames = changeInfo.getOldParameterNames();
922     for (int i = 0; i < newParamsLength; i++) {
923       JavaParameterInfo newParm = newParms[i];
924       if (newParm.getOldIndex() < 0 ||
925           newParm.getOldIndex() == i && !(newParm.getName().equals(oldParameterNames[newParm.getOldIndex()]) && newParm.getTypeText().equals(changeInfo.getOldParameterTypes()[newParm.getOldIndex()]))) {
926         newParameters.add(parameters[i]);
927       }
928     }
929     RefactoringUtil.fixJavadocsForParams(method, newParameters, pair -> {
930       final PsiParameter parameter = pair.first;
931       final String oldParamName = pair.second;
932       final int idx = ArrayUtil.find(oldParameterNames, oldParamName);
933       return idx >= 0 && idx == method.getParameterList().getParameterIndex(parameter) && changeInfo.getNewParameters()[idx].getOldIndex() == idx;
934     }, paramName -> ArrayUtil.find(oldParameterNames, paramName) >= 0);
935   }
936
937   private static PsiParameter createNewParameter(JavaChangeInfo changeInfo, JavaParameterInfo newParm,
938                                                  PsiSubstitutor... substitutor) throws IncorrectOperationException {
939     final PsiParameterList list = changeInfo.getMethod().getParameterList();
940     final PsiElementFactory factory = JavaPsiFacade.getInstance(list.getProject()).getElementFactory();
941     PsiType type = newParm.createType(list);
942     for (PsiSubstitutor psiSubstitutor : substitutor) {
943       type = psiSubstitutor.substitute(type);
944     }
945     return factory.createParameter(newParm.getName(), type);
946   }
947
948   private static void resolveParameterVsFieldsConflicts(final PsiParameter[] newParms,
949                                                         final PsiParameterList list,
950                                                         boolean[] toRemoveParm, 
951                                                         final PsiElement methodBody) throws IncorrectOperationException {
952     List<FieldConflictsResolver> conflictResolvers = new ArrayList<>();
953     for (PsiParameter parameter : newParms) {
954       conflictResolvers.add(new FieldConflictsResolver(parameter.getName(), methodBody));
955     }
956     ChangeSignatureUtil.synchronizeList(list, Arrays.asList(newParms), ParameterList.INSTANCE, toRemoveParm);
957     JavaCodeStyleManager.getInstance(list.getProject()).shortenClassReferences(list);
958     for (FieldConflictsResolver fieldConflictsResolver : conflictResolvers) {
959       fieldConflictsResolver.fix();
960     }
961   }
962
963   private static boolean needToCatchExceptions(JavaChangeInfo changeInfo, PsiMethod caller) {
964     return changeInfo.isExceptionSetOrOrderChanged() &&
965            !(changeInfo instanceof JavaChangeInfoImpl && ((JavaChangeInfoImpl)changeInfo).propagateExceptionsMethods.contains(caller));
966   }
967
968   private static class ParameterList implements ChangeSignatureUtil.ChildrenGenerator<PsiParameterList, PsiParameter> {
969     public static final ParameterList INSTANCE = new ParameterList();
970
971     @Override
972     public List<PsiParameter> getChildren(PsiParameterList psiParameterList) {
973       return Arrays.asList(psiParameterList.getParameters());
974     }
975   }
976
977   private static class ThrowsList implements ChangeSignatureUtil.ChildrenGenerator<PsiReferenceList, PsiJavaCodeReferenceElement> {
978     public static final ThrowsList INSTANCE = new ThrowsList();
979
980     @Override
981     public List<PsiJavaCodeReferenceElement> getChildren(PsiReferenceList throwsList) {
982       return Arrays.asList(throwsList.getReferenceElements());
983     }
984   }
985
986   private static class ConflictSearcher {
987     private final JavaChangeInfo myChangeInfo;
988
989     private ConflictSearcher(@NotNull JavaChangeInfo changeInfo) {
990       this.myChangeInfo = changeInfo;
991     }
992
993     public MultiMap<PsiElement, String> findConflicts(Ref<UsageInfo[]> refUsages) {
994       MultiMap<PsiElement, String> conflictDescriptions = new MultiMap<>();
995       final PsiMethod prototype = addMethodConflicts(conflictDescriptions);
996       Set<UsageInfo> usagesSet = new HashSet<>(Arrays.asList(refUsages.get()));
997       RenameUtil.removeConflictUsages(usagesSet);
998       if (myChangeInfo.isVisibilityChanged()) {
999         try {
1000           addInaccessibilityDescriptions(usagesSet, conflictDescriptions);
1001         }
1002         catch (IncorrectOperationException e) {
1003           LOG.error(e);
1004         }
1005       }
1006
1007       final boolean[] toRemove = myChangeInfo.toRemoveParm();
1008       //introduce parameter object deletes parameters but replaces their usages with generated code
1009       final boolean checkUnusedParameter = myChangeInfo.checkUnusedParameter();
1010       if (checkUnusedParameter) {
1011         checkParametersToDelete(myChangeInfo.getMethod(), toRemove, conflictDescriptions);
1012       }
1013       checkContract(conflictDescriptions, myChangeInfo.getMethod());
1014
1015       for (UsageInfo usageInfo : usagesSet) {
1016         final PsiElement element = usageInfo.getElement();
1017         if (usageInfo instanceof OverriderUsageInfo) {
1018           final PsiMethod method = ((OverriderUsageInfo)usageInfo).getOverridingMethod();
1019           final PsiMethod baseMethod = ((OverriderUsageInfo)usageInfo).getBaseMethod();
1020           final int delta = baseMethod.getParameterList().getParametersCount() - method.getParameterList().getParametersCount();
1021           if (delta > 0) {
1022             if (toRemove[toRemove.length - 1]) { //todo check if implicit parameter is not the last one
1023               conflictDescriptions.putValue(baseMethod, "Implicit last parameter should not be deleted");
1024             }
1025           }
1026           else if (prototype != null && baseMethod == myChangeInfo.getMethod()) {
1027             ConflictsUtil.checkMethodConflicts(method.getContainingClass(), method, prototype, conflictDescriptions);
1028             if (checkUnusedParameter) {
1029               checkParametersToDelete(method, toRemove, conflictDescriptions);
1030             }
1031           }
1032
1033           checkContract(conflictDescriptions, method);
1034         }
1035         else if (element instanceof PsiMethodReferenceExpression && MethodReferenceUsageInfo.needToExpand(myChangeInfo)) {
1036           conflictDescriptions.putValue(element, RefactoringBundle.message("expand.method.reference.warning"));
1037         }
1038         else if (element instanceof PsiJavaCodeReferenceElement) {
1039           final PsiElement parent = element.getParent();
1040           if (parent instanceof PsiCallExpression) {
1041             final PsiExpressionList argumentList = ((PsiCallExpression)parent).getArgumentList();
1042             if (argumentList != null) {
1043               final PsiExpression[] args = argumentList.getExpressions();
1044               for (int i = 0; i < toRemove.length; i++) {
1045                 if (toRemove[i] && i < args.length) {
1046                   if (RemoveUnusedVariableUtil.checkSideEffects(args[i], null, new ArrayList<>())) {
1047                     conflictDescriptions.putValue(args[i], "Parameter '" + myChangeInfo.getOldParameterNames()[i] + "' has usage that is not safe to delete");
1048                   }
1049                 }
1050               }
1051             }
1052           }
1053         }
1054       }
1055
1056       return conflictDescriptions;
1057     }
1058
1059     private static void checkParametersToDelete(PsiMethod method, boolean[] toRemove, MultiMap<PsiElement, String> conflictDescriptions) {
1060       final PsiParameter[] parameters = method.getParameterList().getParameters();
1061       final PsiCodeBlock body = method.getBody();
1062       if (body != null) {
1063         final LocalSearchScope searchScope = new LocalSearchScope(body);
1064         for (int i = 0; i < toRemove.length; i++) {
1065           if (toRemove[i] && ReferencesSearch.search(parameters[i], searchScope).findFirst() != null) {
1066             conflictDescriptions.putValue(parameters[i], StringUtil.capitalize(RefactoringUIUtil.getDescription(parameters[i], true)) + " is used in method body");
1067           }
1068         }
1069       }
1070     }
1071
1072     private static void checkContract(MultiMap<PsiElement, String> conflictDescriptions, PsiMethod method) {
1073       PsiAnnotation contract = ControlFlowAnalyzer.findContractAnnotation(method);
1074       if (contract != null && !AnnotationUtil.isInferredAnnotation(contract)) {
1075         conflictDescriptions.putValue(method, "@Contract annotation will have to be changed manually");
1076       }
1077     }
1078
1079     private boolean needToChangeCalls() {
1080       return myChangeInfo.isNameChanged() || myChangeInfo.isParameterSetOrOrderChanged() || myChangeInfo.isExceptionSetOrOrderChanged();
1081     }
1082
1083
1084     private void addInaccessibilityDescriptions(Set<UsageInfo> usages, MultiMap<PsiElement, String> conflictDescriptions)
1085       throws IncorrectOperationException {
1086       PsiMethod method = myChangeInfo.getMethod();
1087       PsiModifierList modifierList = (PsiModifierList)method.getModifierList().copy();
1088       VisibilityUtil.setVisibility(modifierList, myChangeInfo.getNewVisibility());
1089
1090       for (Iterator<UsageInfo> iterator = usages.iterator(); iterator.hasNext();) {
1091         UsageInfo usageInfo = iterator.next();
1092         PsiElement element = usageInfo.getElement();
1093         if (element != null) {
1094           if (element instanceof PsiQualifiedReference) {
1095             PsiClass accessObjectClass = null;
1096             PsiElement qualifier = ((PsiQualifiedReference)element).getQualifier();
1097             if (qualifier instanceof PsiExpression) {
1098               accessObjectClass = (PsiClass)PsiUtil.getAccessObjectClass((PsiExpression)qualifier).getElement();
1099             }
1100
1101             if (!JavaPsiFacade.getInstance(element.getProject()).getResolveHelper()
1102               .isAccessible(method, modifierList, element, accessObjectClass, null)) {
1103               String message =
1104                 RefactoringBundle.message("0.with.1.visibility.is.not.accessible.from.2",
1105                                           RefactoringUIUtil.getDescription(method, true),
1106                                           VisibilityUtil.toPresentableText(myChangeInfo.getNewVisibility()),
1107                                           RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(element), true));
1108               conflictDescriptions.putValue(method, message);
1109               if (!needToChangeCalls()) {
1110                 iterator.remove();
1111               }
1112             }
1113           }
1114         }
1115       }
1116     }
1117
1118
1119     private PsiMethod addMethodConflicts(MultiMap<PsiElement, String> conflicts) {
1120       String newMethodName = myChangeInfo.getNewName();
1121       try {
1122         final PsiMethod method = myChangeInfo.getMethod();
1123         if (!StdLanguages.JAVA.equals(method.getLanguage())) return null;
1124         PsiManager manager = method.getManager();
1125         PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory();
1126         final CanonicalTypes.Type returnType = myChangeInfo.getNewReturnType();
1127         PsiMethod prototype;
1128         if (returnType != null) {
1129           prototype = factory.createMethod(newMethodName, returnType.getType(method, manager));
1130         }
1131         else {
1132           prototype = factory.createConstructor();
1133           prototype.setName(newMethodName);
1134         }
1135         JavaParameterInfo[] parameters = myChangeInfo.getNewParameters();
1136
1137
1138         for (JavaParameterInfo info : parameters) {
1139           PsiType parameterType = info.createType(method, manager);
1140           if (parameterType == null) {
1141             parameterType =
1142               JavaPsiFacade.getElementFactory(method.getProject()).createTypeFromText(CommonClassNames.JAVA_LANG_OBJECT, method);
1143           }
1144           PsiParameter param = factory.createParameter(info.getName(), parameterType);
1145           prototype.getParameterList().add(param);
1146         }
1147
1148         ConflictsUtil.checkMethodConflicts(method.getContainingClass(), myChangeInfo.isGenerateDelegate() ? null : method, prototype, conflicts);
1149         return prototype;
1150       }
1151       catch (IncorrectOperationException e) {
1152         LOG.error(e);
1153       }
1154       return null;
1155     }
1156   }
1157
1158   private static class ExpressionList implements ChangeSignatureUtil.ChildrenGenerator<PsiExpressionList, PsiExpression> {
1159     public static final ExpressionList INSTANCE = new ExpressionList();
1160
1161     @Override
1162     public List<PsiExpression> getChildren(PsiExpressionList psiExpressionList) {
1163       return Arrays.asList(psiExpressionList.getExpressions());
1164     }
1165   }
1166
1167 }