Cleanup: NotNull/Nullable
[idea/community.git] / java / java-impl / src / com / intellij / refactoring / move / moveInstanceMethod / MoveInstanceMethodProcessor.java
1 /*
2  * Copyright 2000-2016 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.move.moveInstanceMethod;
17
18 import com.intellij.codeInsight.ChangeContextUtil;
19 import com.intellij.codeInsight.generation.OverrideImplementUtil;
20 import com.intellij.ide.util.EditorHelper;
21 import com.intellij.openapi.diagnostic.Logger;
22 import com.intellij.openapi.project.Project;
23 import com.intellij.openapi.util.Comparing;
24 import com.intellij.openapi.util.Ref;
25 import com.intellij.psi.*;
26 import com.intellij.psi.codeStyle.JavaCodeStyleManager;
27 import com.intellij.psi.javadoc.PsiDocTagValue;
28 import com.intellij.psi.search.GlobalSearchScope;
29 import com.intellij.psi.search.searches.ClassInheritorsSearch;
30 import com.intellij.psi.search.searches.ReferencesSearch;
31 import com.intellij.psi.util.MethodSignature;
32 import com.intellij.psi.util.PsiTreeUtil;
33 import com.intellij.psi.util.PsiUtil;
34 import com.intellij.refactoring.BaseRefactoringProcessor;
35 import com.intellij.refactoring.RefactoringBundle;
36 import com.intellij.refactoring.move.MoveInstanceMembersUtil;
37 import com.intellij.refactoring.util.*;
38 import com.intellij.usageView.UsageInfo;
39 import com.intellij.usageView.UsageViewDescriptor;
40 import com.intellij.usageView.UsageViewUtil;
41 import com.intellij.util.IncorrectOperationException;
42 import com.intellij.util.VisibilityUtil;
43 import com.intellij.util.containers.MultiMap;
44 import com.siyeh.ig.psiutils.ExpressionUtils;
45 import org.jetbrains.annotations.NonNls;
46 import org.jetbrains.annotations.NotNull;
47
48 import java.util.*;
49
50 /**
51  * @author ven
52  */
53 public class MoveInstanceMethodProcessor extends BaseRefactoringProcessor{
54   private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.move.moveInstanceMethod.MoveInstanceMethodProcessor");
55
56   public PsiMethod getMethod() {
57     return myMethod;
58   }
59
60   public PsiVariable getTargetVariable() {
61     return myTargetVariable;
62   }
63
64   private PsiMethod myMethod;
65   private PsiVariable myTargetVariable;
66   private PsiClass myTargetClass;
67   private final String myNewVisibility;
68   private final boolean myOpenInEditor;
69   private final Map<PsiClass, String> myOldClassParameterNames;
70
71   public MoveInstanceMethodProcessor(final Project project,
72                                    final PsiMethod method,
73                                    final PsiVariable targetVariable,
74                                    final String newVisibility,
75                                    final Map<PsiClass, String> oldClassParameterNames) {
76     this(project, method, targetVariable, newVisibility, false, oldClassParameterNames);
77   }
78
79   public MoveInstanceMethodProcessor(final Project project,
80                                      final PsiMethod method,
81                                      final PsiVariable targetVariable,
82                                      final String newVisibility,
83                                      boolean openInEditor,
84                                      final Map<PsiClass, String> oldClassParameterNames) {
85     super(project);
86     myMethod = method;
87     myTargetVariable = targetVariable;
88     myOpenInEditor = openInEditor;
89     myOldClassParameterNames = oldClassParameterNames;
90     LOG.assertTrue(myTargetVariable instanceof PsiParameter || myTargetVariable instanceof PsiField);
91     LOG.assertTrue(myTargetVariable.getType() instanceof PsiClassType);
92     final PsiType type = myTargetVariable.getType();
93     LOG.assertTrue(type instanceof PsiClassType);
94     myTargetClass = ((PsiClassType) type).resolve();
95     myNewVisibility = newVisibility;
96   }
97
98   @Override
99   @NotNull
100   protected UsageViewDescriptor createUsageViewDescriptor(@NotNull UsageInfo[] usages) {
101     return new MoveInstanceMethodViewDescriptor(myMethod, myTargetVariable, myTargetClass);
102   }
103
104   @Override
105   protected boolean preprocessUsages(@NotNull Ref<UsageInfo[]> refUsages) {
106     final UsageInfo[] usages = refUsages.get();
107     MultiMap<PsiElement, String> conflicts = new MultiMap<>();
108     final Set<PsiMember> members = new HashSet<>();
109     members.add(myMethod);
110     if (myTargetVariable instanceof PsiField) members.add((PsiMember)myTargetVariable);
111     if (!myTargetClass.isInterface()) {
112       RefactoringConflictsUtil.analyzeAccessibilityConflicts(members, myTargetClass, conflicts, myNewVisibility);
113     }
114     else {
115       for (final UsageInfo usage : usages) {
116         if (usage instanceof InheritorUsageInfo) {
117           RefactoringConflictsUtil.analyzeAccessibilityConflicts(
118             members, ((InheritorUsageInfo)usage).getInheritor(), conflicts, myNewVisibility);
119         }
120       }
121     }
122
123     if (myTargetVariable instanceof PsiParameter) {
124       PsiParameter parameter = (PsiParameter)myTargetVariable;
125       final int index = myMethod.getParameterList().getParameterIndex(parameter);
126       for (final UsageInfo usageInfo : usages) {
127         if (usageInfo instanceof MethodCallUsageInfo) {
128           final PsiElement methodCall = ((MethodCallUsageInfo)usageInfo).getMethodCallExpression();
129           if (methodCall instanceof PsiMethodCallExpression) {
130             final PsiExpression[] expressions = ((PsiMethodCallExpression)methodCall).getArgumentList().getExpressions();
131             if (index < expressions.length) {
132               PsiExpression instanceValue = expressions[index];
133               instanceValue = RefactoringUtil.unparenthesizeExpression(instanceValue);
134               if (instanceValue instanceof PsiLiteralExpression && ((PsiLiteralExpression)instanceValue).getValue() == null) {
135                 String message = RefactoringBundle.message("0.contains.call.with.null.argument.for.parameter.1",
136                                                            RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(methodCall), true),
137                                                            CommonRefactoringUtil.htmlEmphasize(parameter.getName()));
138                 conflicts.putValue(instanceValue, message);
139               }
140             }
141           } else if (methodCall instanceof PsiMethodReferenceExpression && shouldBeExpandedToLambda((PsiMethodReferenceExpression)methodCall, index)) {
142             conflicts.putValue(methodCall, RefactoringBundle.message("expand.method.reference.warning"));
143           }
144         }
145       }
146     }
147
148     try {
149       ConflictsUtil.checkMethodConflicts(myTargetClass, myMethod, getPatternMethod(), conflicts);
150     }
151     catch (IncorrectOperationException ignored) {}
152
153     return showConflicts(conflicts, usages);
154   }
155
156   /**
157    * If collapse by second search is possible, then it's possible not to expand
158    */
159   private boolean shouldBeExpandedToLambda(PsiMethodReferenceExpression referenceExpression, int index) {
160     PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(referenceExpression.getFunctionalInterfaceType());
161     PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(resolveResult);
162     if (interfaceMethod != null) {
163       MethodSignature methodSignature = interfaceMethod.getSignature(LambdaUtil.getSubstitutor(interfaceMethod, resolveResult));
164       if (index == 0 && methodSignature.getParameterTypes().length > 0 &&
165           methodSignature.getParameterTypes()[0].isAssignableFrom(myMethod.getParameterList().getParameters()[0].getType())) {
166         return false;
167       }
168     }
169     return true;
170   }
171
172   @Override
173   @NotNull
174   protected UsageInfo[] findUsages() {
175     final PsiManager manager = myMethod.getManager();
176     final GlobalSearchScope searchScope = GlobalSearchScope.allScope(manager.getProject());
177     final List<UsageInfo> usages = new ArrayList<>();
178     for (PsiReference ref : ReferencesSearch.search(myMethod, searchScope, false)) {
179       final PsiElement element = ref.getElement();
180       if (element instanceof PsiReferenceExpression) {
181         boolean isInternal = PsiTreeUtil.isAncestor(myMethod, element, true);
182         usages.add(new MethodCallUsageInfo((PsiReferenceExpression)element, isInternal));
183       }
184       else if (element instanceof PsiDocTagValue) {
185         usages.add(new JavadocUsageInfo((PsiDocTagValue)element));
186       }
187       else {
188         throw new UnknownReferenceTypeException(element.getLanguage());
189       }
190     }
191
192     if (myTargetClass.isInterface() && !PsiUtil.isLanguageLevel8OrHigher(myTargetClass)) {
193       addInheritorUsages(myTargetClass, searchScope, usages);
194     }
195
196     final PsiCodeBlock body = myMethod.getBody();
197     if (body != null) {
198       body.accept(new JavaRecursiveElementWalkingVisitor() {
199         @Override public void visitNewExpression(PsiNewExpression expression) {
200           if (MoveInstanceMembersUtil.getClassReferencedByThis(expression) != null) {
201             usages.add(new InternalUsageInfo(expression));
202           }
203           super.visitNewExpression(expression);
204         }
205
206         @Override public void visitReferenceExpression(PsiReferenceExpression expression) {
207           if (MoveInstanceMembersUtil.getClassReferencedByThis(expression) != null) {
208             usages.add(new InternalUsageInfo(expression));
209           } else if (!expression.isQualified()) {
210             final PsiElement resolved = expression.resolve();
211             if (myTargetVariable.equals(resolved)) {
212               usages.add(new InternalUsageInfo(expression));
213             }
214           }
215
216           super.visitReferenceExpression(expression);
217         }
218       });
219     }
220
221     return usages.toArray(UsageInfo.EMPTY_ARRAY);
222   }
223
224   private static void addInheritorUsages(PsiClass aClass, final GlobalSearchScope searchScope, final List<UsageInfo> usages) {
225     for (PsiClass inheritor : ClassInheritorsSearch.search(aClass, searchScope, false).findAll()) {
226       if (!inheritor.isInterface()) {
227         usages.add(new InheritorUsageInfo(inheritor));
228       }
229       else {
230         addInheritorUsages(inheritor, searchScope, usages);
231       }
232     }
233   }
234
235   @Override
236   protected void refreshElements(@NotNull PsiElement[] elements) {
237     LOG.assertTrue(elements.length == 3);
238     myMethod = (PsiMethod) elements[0];
239     myTargetVariable = (PsiVariable) elements[1];
240     myTargetClass = (PsiClass) elements[2];
241   }
242
243   @Override
244   @NotNull
245   protected String getCommandName() {
246     return RefactoringBundle.message("move.instance.method.command");
247   }
248
249   public PsiClass getTargetClass() {
250     return myTargetClass;
251   }
252
253   @Override
254   protected void performRefactoring(@NotNull UsageInfo[] usages) {
255     PsiMethod patternMethod = createMethodToAdd();
256     final List<PsiReference> docRefs = new ArrayList<>();
257     for (UsageInfo usage : usages) {
258       if (usage instanceof InheritorUsageInfo) {
259         final PsiClass inheritor = ((InheritorUsageInfo)usage).getInheritor();
260         addMethodToClass(inheritor, patternMethod, true);
261       }
262       else if (usage instanceof MethodCallUsageInfo && !((MethodCallUsageInfo)usage).isInternal()) {
263         final PsiElement expression = ((MethodCallUsageInfo)usage).getMethodCallExpression();
264         if (expression instanceof PsiMethodCallExpression) {
265           correctMethodCall((PsiMethodCallExpression)expression, false);
266         }
267         else if (expression instanceof PsiMethodReferenceExpression) {
268           PsiMethodReferenceExpression methodReferenceExpression = (PsiMethodReferenceExpression)expression;
269           PsiExpression qualifierExpression = methodReferenceExpression.getQualifierExpression();
270
271           if (myTargetVariable instanceof PsiParameter && shouldBeExpandedToLambda(methodReferenceExpression, myMethod.getParameterList().getParameterIndex((PsiParameter)myTargetVariable))) {
272             PsiLambdaExpression lambdaExpression = LambdaRefactoringUtil.convertMethodReferenceToLambda(methodReferenceExpression, false, true);
273             if (lambdaExpression != null) {
274               List<PsiExpression> returnExpressions = LambdaUtil.getReturnExpressions(lambdaExpression);
275               if (!returnExpressions.isEmpty()) {
276                 correctMethodCall((PsiMethodCallExpression)returnExpressions.get(0), false);
277               }
278             }
279           }
280           else {
281             String exprText;
282             if (myTargetVariable instanceof PsiParameter ||
283                 qualifierExpression instanceof PsiReferenceExpression && ((PsiReferenceExpression)qualifierExpression).resolve() == myMethod.getContainingClass()) {
284               exprText = myTargetVariable.getType().getCanonicalText();
285             }
286             else if (qualifierExpression instanceof PsiReferenceExpression) {
287               exprText = qualifierExpression.getText() + "." + myTargetVariable.getName();
288             }
289             else {
290               exprText = myTargetVariable.getName();
291             }
292             PsiExpression newQualifier = JavaPsiFacade.getElementFactory(myProject).createExpressionFromText(exprText, null);
293             ((PsiMethodReferenceExpression)expression).setQualifierExpression(newQualifier);
294             JavaCodeStyleManager.getInstance(myProject).shortenClassReferences(expression);
295           }
296         }
297       }
298       else if (usage instanceof JavadocUsageInfo) {
299         docRefs.add(usage.getElement().getReference());
300       }
301     }
302
303     try {
304       if (myTargetClass.isInterface()) {
305         final PsiModifierList modifierList = patternMethod.getModifierList();
306         if (!PsiUtil.isLanguageLevel8OrHigher(myTargetClass)) {
307           patternMethod.getBody().delete();
308           modifierList.setModifierProperty(PsiModifier.DEFAULT, false);
309         }
310         else {
311           modifierList.setModifierProperty(PsiModifier.DEFAULT, true);
312         }
313         RefactoringUtil.makeMethodAbstract(myTargetClass, patternMethod);
314       }
315
316       final PsiMethod method = addMethodToClass(myTargetClass, patternMethod, false);
317       myMethod.delete();
318       for (PsiReference reference : docRefs) {
319         reference.bindToElement(method);
320       }
321       VisibilityUtil.fixVisibility(UsageViewUtil.toElements(usages), method, myNewVisibility);
322
323       if (myOpenInEditor) {
324         EditorHelper.openInEditor(method);
325       }
326     }
327     catch (IncorrectOperationException e) {
328       LOG.error(e);
329     }
330   }
331
332   private void correctMethodCall(final PsiMethodCallExpression expression, final boolean isInternalCall) {
333     try {
334       final PsiManager manager = myMethod.getManager();
335       PsiReferenceExpression methodExpression = expression.getMethodExpression();
336       if (!methodExpression.isReferenceTo(myMethod)) return;
337       final PsiExpression oldQualifier = methodExpression.getQualifierExpression();
338       PsiExpression newQualifier = null;
339       final PsiClass classReferencedByThis = MoveInstanceMembersUtil.getClassReferencedByThis(methodExpression);
340       if (myTargetVariable instanceof PsiParameter) {
341         final int index = myMethod.getParameterList().getParameterIndex((PsiParameter)myTargetVariable);
342         final PsiExpression[] arguments = expression.getArgumentList().getExpressions();
343         if (index < arguments.length) {
344           newQualifier = (PsiExpression)arguments[index].copy();
345           arguments[index].delete();
346         }
347       }
348       else {
349         VisibilityUtil.escalateVisibility((PsiField)myTargetVariable, expression);
350         String newQualifierName = myTargetVariable.getName();
351         if (myTargetVariable instanceof PsiField && oldQualifier != null) {
352           final PsiClass aClass = PsiUtil.resolveClassInClassTypeOnly(oldQualifier.getType());
353           if (aClass == ((PsiField)myTargetVariable).getContainingClass()) {
354             newQualifierName = oldQualifier.getText() + "." + newQualifierName;
355           }
356         }
357         newQualifier = JavaPsiFacade.getElementFactory(manager.getProject()).createExpressionFromText(newQualifierName, null);
358       }
359
360       PsiExpression newArgument = null;
361
362       if (classReferencedByThis != null) {
363         @NonNls String thisArgumentText = null;
364         if (manager.areElementsEquivalent(myMethod.getContainingClass(), classReferencedByThis)) {
365           if (myOldClassParameterNames.containsKey(myMethod.getContainingClass())) {
366             thisArgumentText = "this";
367           }
368         }
369         else {
370           final String name = classReferencedByThis.getName();
371           if (name != null) {
372             thisArgumentText = name + ".this";
373           }
374           else {
375             thisArgumentText = "this";
376           }
377         }
378
379         if (thisArgumentText != null) {
380           newArgument = JavaPsiFacade.getElementFactory(manager.getProject()).createExpressionFromText(thisArgumentText, null);
381         }
382       } else {
383         if (!isInternalCall && oldQualifier != null) {
384           final PsiType type = oldQualifier.getType();
385           if (type instanceof PsiClassType) {
386             final PsiClass resolved = ((PsiClassType)type).resolve();
387             if (resolved != null && getParameterNameToCreate(resolved) != null) {
388               newArgument = replaceRefsToTargetVariable(oldQualifier);  //replace is needed in case old qualifier is e.g. the same as field as target variable
389             }
390           }
391         }
392       }
393
394
395       if (newArgument != null) {
396         expression.getArgumentList().add(newArgument);
397       }
398
399       if (newQualifier != null) {
400         if (newQualifier instanceof PsiThisExpression && ((PsiThisExpression)newQualifier).getQualifier() == null) {
401           //Remove now redundant 'this' qualifier
402           if (oldQualifier != null) oldQualifier.delete();
403         }
404         else {
405           final PsiReferenceExpression refExpr = (PsiReferenceExpression)JavaPsiFacade.getElementFactory(manager.getProject())
406               .createExpressionFromText("q." + myMethod.getName(), null);
407           refExpr.getQualifierExpression().replace(newQualifier);
408           methodExpression.replace(refExpr);
409         }
410       }
411     }
412     catch (IncorrectOperationException e) {
413       LOG.error(e);
414     }
415   }
416
417   private PsiExpression replaceRefsToTargetVariable(final PsiExpression expression) {
418     final PsiManager manager = expression.getManager();
419     if (ExpressionUtils.isReferenceTo(expression, myTargetVariable)) {
420       return createThisExpr(manager);
421     }
422
423     expression.accept(new JavaRecursiveElementVisitor() {
424       @Override public void visitReferenceExpression(PsiReferenceExpression expression) {
425         super.visitReferenceExpression(expression);
426         if (expression.isReferenceTo(myTargetVariable)) {
427           try {
428             expression.replace(createThisExpr(manager));
429           }
430           catch (IncorrectOperationException e) {
431             LOG.error(e);
432           }
433         }
434       }
435     });
436
437     return expression;
438   }
439
440   private static PsiExpression createThisExpr(final PsiManager manager)  {
441     try {
442       return JavaPsiFacade.getElementFactory(manager.getProject()).createExpressionFromText("this", null);
443     }
444     catch (IncorrectOperationException e) {
445       LOG.error(e);
446       return null;
447     }
448   }
449
450   private static PsiMethod addMethodToClass(final PsiClass aClass, final PsiMethod patternMethod, boolean canAddOverride) {
451     try {
452       final PsiMethod method = (PsiMethod)aClass.add(patternMethod);
453       ChangeContextUtil.decodeContextInfo(method, null, null);
454       if (canAddOverride && OverrideImplementUtil.isInsertOverride(method, aClass)) {
455         method.getModifierList().addAnnotation(CommonClassNames.JAVA_LANG_OVERRIDE);
456       }
457       return method;
458     }
459     catch (IncorrectOperationException e) {
460       LOG.error(e);
461       return null;
462     }
463   }
464
465   private PsiMethod createMethodToAdd () {
466     ChangeContextUtil.encodeContextInfo(myMethod, true);
467     try {
468       final PsiManager manager = myMethod.getManager();
469       JavaPsiFacade facade = JavaPsiFacade.getInstance(manager.getProject());
470       final PsiElementFactory factory = facade.getElementFactory();
471
472       //correct internal references
473       final PsiCodeBlock body = myMethod.getBody();
474       if (body != null) {
475         final Map<PsiElement, PsiElement> replaceMap = new HashMap<>();
476         body.accept(new JavaRecursiveElementVisitor() {
477           @Override public void visitThisExpression(PsiThisExpression expression) {
478             final PsiClass classReferencedByThis = MoveInstanceMembersUtil.getClassReferencedByThis(expression);
479             if (classReferencedByThis != null && !PsiTreeUtil.isAncestor(myMethod, classReferencedByThis, false)) {
480               final PsiElementFactory factory = JavaPsiFacade.getElementFactory(myProject);
481               String paramName = getParameterNameToCreate(classReferencedByThis);
482               try {
483                 final PsiExpression refExpression = factory.createExpressionFromText(paramName, null);
484                 replaceMap.put(expression, refExpression);
485               }
486               catch (IncorrectOperationException e) {
487                 LOG.error(e);
488               }
489             }
490           }
491
492           @Override public void visitReferenceExpression(PsiReferenceExpression expression) {
493             try {
494               final PsiExpression qualifier = expression.getQualifierExpression();
495               final PsiElement resolved = expression.resolve();
496               if (ExpressionUtils.isReferenceTo(qualifier, myTargetVariable)) {
497                 if (resolved instanceof PsiField) {
498                   String fieldName = ((PsiField)resolved).getName();
499                   LOG.assertTrue(fieldName != null);
500                   for (PsiParameter parameter : myMethod.getParameterList().getParameters()) {
501                     if (Comparing.strEqual(parameter.getName(), fieldName) ||
502                         facade.getResolveHelper().resolveReferencedVariable(fieldName, expression) != null) {
503                       qualifier.replace(factory.createExpressionFromText("this", null));
504                       return;
505                     }
506                   }
507                 }
508                 if (expression instanceof PsiMethodReferenceExpression) {
509                   qualifier.replace(factory.createExpressionFromText("this", null));
510                 }
511                 else {
512                   //Target is a field, replace target.m -> m
513                   qualifier.delete();
514                 }
515                 return;
516               }
517               if (myTargetVariable.equals(resolved)) {
518                 PsiThisExpression thisExpression = RefactoringChangeUtil.createThisExpression(manager, PsiTreeUtil.isAncestor(myMethod, PsiTreeUtil.getParentOfType(expression, PsiClass.class), true) ? myTargetClass : null);
519                 replaceMap.put(expression, thisExpression);
520                 return;
521               }
522               else if (myMethod.equals(resolved)) {
523               }
524               else {
525                 PsiClass classReferencedByThis = MoveInstanceMembersUtil.getClassReferencedByThis(expression);
526                 if (classReferencedByThis != null) {
527                   final String paramName = getParameterNameToCreate(classReferencedByThis);
528                   if (paramName != null) {
529                     PsiReferenceExpression newQualifier = (PsiReferenceExpression)factory.createExpressionFromText(paramName, null);
530                     expression.setQualifierExpression(newQualifier);
531                     return;
532                   }
533                 }
534               }
535               super.visitReferenceExpression(expression);
536             }
537             catch (IncorrectOperationException e) {
538               LOG.error(e);
539             }
540           }
541
542           @Override public void visitNewExpression(PsiNewExpression expression) {
543             try {
544               final PsiExpression qualifier = expression.getQualifier();
545               if (ExpressionUtils.isReferenceTo(qualifier, myTargetVariable)) {
546                 //Target is a field, replace target.new A() -> new A()
547                 qualifier.delete();
548               } else {
549                 final PsiClass classReferencedByThis = MoveInstanceMembersUtil.getClassReferencedByThis(expression);
550                 if (classReferencedByThis != null) {
551                   if (qualifier != null) qualifier.delete();
552                   final String paramName = getParameterNameToCreate(classReferencedByThis);
553                   final PsiExpression newExpression = factory.createExpressionFromText(paramName + "." + expression.getText(), null);
554                   replaceMap.put(expression, newExpression);
555                 }
556               }
557               super.visitNewExpression(expression);
558             }
559             catch (IncorrectOperationException e) {
560               LOG.error(e);
561             }
562           }
563
564           @Override public void visitMethodCallExpression(PsiMethodCallExpression expression) {
565             correctMethodCall(expression, true);
566             super.visitMethodCallExpression(expression);
567           }
568         });
569         for (PsiElement element : replaceMap.keySet()) {
570           final PsiElement replacement = replaceMap.get(element);
571           element.replace(replacement);
572         }
573       }
574
575       final PsiMethod methodCopy = getPatternMethod();
576
577       final List<PsiParameter> newParameters = Arrays.asList(methodCopy.getParameterList().getParameters());
578       RefactoringUtil.fixJavadocsForParams(methodCopy, new HashSet<>(newParameters));
579       return methodCopy;
580     }
581     catch (IncorrectOperationException e) {
582       LOG.error(e);
583       return myMethod;
584     }
585   }
586
587   private PsiMethod getPatternMethod() throws IncorrectOperationException {
588     final PsiMethod methodCopy = (PsiMethod)myMethod.copy();
589     String name = myTargetClass.isInterface()
590                   ? PsiModifier.PUBLIC :
591                   !Comparing.strEqual(myNewVisibility, VisibilityUtil.ESCALATE_VISIBILITY) ? myNewVisibility : null;
592     if (name != null) {
593       PsiUtil.setModifierProperty(methodCopy, name, true);
594     }
595     if (myTargetVariable instanceof PsiParameter) {
596       final int index = myMethod.getParameterList().getParameterIndex((PsiParameter)myTargetVariable);
597       methodCopy.getParameterList().getParameters()[index].delete();
598     }
599
600     addParameters(JavaPsiFacade.getElementFactory(myProject), methodCopy, myTargetClass.isInterface());
601     return methodCopy;
602   }
603
604   private void addParameters(final PsiElementFactory factory, final PsiMethod methodCopy, final boolean isInterface) throws IncorrectOperationException {
605     final Set<Map.Entry<PsiClass, String>> entries = myOldClassParameterNames.entrySet();
606     for (final Map.Entry<PsiClass, String> entry : entries) {
607       final PsiClassType type = factory.createType(entry.getKey());
608       final PsiParameter parameter = factory.createParameter(entry.getValue(), type);
609       if (isInterface) {
610         PsiUtil.setModifierProperty(parameter, PsiModifier.FINAL, false);
611       }
612       methodCopy.getParameterList().add(parameter);
613     }
614   }
615
616   private String getParameterNameToCreate(@NotNull PsiClass aClass) {
617     return myOldClassParameterNames.get(aClass);
618   }
619 }