update copyright
[fedora-idea.git] / java / java-impl / src / com / intellij / refactoring / changeSignature / ChangeSignatureProcessor.java
blob1beae85a192e69be365dc797ee43069db6ac2d1a
1 /*
2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 /**
18 * created at Sep 17, 2001
19 * @author Jeka
21 package com.intellij.refactoring.changeSignature;
23 import com.intellij.codeInsight.ExceptionUtil;
24 import com.intellij.openapi.application.ApplicationManager;
25 import com.intellij.openapi.diagnostic.Logger;
26 import com.intellij.openapi.project.Project;
27 import com.intellij.openapi.ui.DialogWrapper;
28 import com.intellij.openapi.ui.Messages;
29 import com.intellij.openapi.util.Ref;
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.javadoc.PsiDocTagValue;
35 import com.intellij.psi.scope.processor.VariablesProcessor;
36 import com.intellij.psi.scope.util.PsiScopesUtil;
37 import com.intellij.psi.search.GlobalSearchScope;
38 import com.intellij.psi.search.searches.MethodReferencesSearch;
39 import com.intellij.psi.search.searches.OverridingMethodsSearch;
40 import com.intellij.psi.search.searches.ReferencesSearch;
41 import com.intellij.psi.util.*;
42 import com.intellij.psi.xml.XmlElement;
43 import com.intellij.refactoring.BaseRefactoringProcessor;
44 import com.intellij.refactoring.RefactoringBundle;
45 import com.intellij.refactoring.rename.JavaUnresolvableLocalCollisionDetector;
46 import com.intellij.refactoring.rename.RenameUtil;
47 import com.intellij.refactoring.rename.UnresolvableCollisionUsageInfo;
48 import com.intellij.refactoring.ui.ConflictsDialog;
49 import com.intellij.refactoring.util.*;
50 import com.intellij.refactoring.util.usageInfo.DefaultConstructorImplicitUsageInfo;
51 import com.intellij.refactoring.util.usageInfo.NoConstructorClassUsageInfo;
52 import com.intellij.usageView.UsageInfo;
53 import com.intellij.usageView.UsageViewDescriptor;
54 import com.intellij.usageView.UsageViewUtil;
55 import com.intellij.util.IncorrectOperationException;
56 import com.intellij.util.VisibilityUtil;
57 import com.intellij.util.containers.HashSet;
58 import com.intellij.util.containers.MultiMap;
59 import org.jetbrains.annotations.NotNull;
61 import java.util.*;
63 public class ChangeSignatureProcessor extends BaseRefactoringProcessor {
64 private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.changeSignature.ChangeSignatureProcessor");
66 @Modifier private final String myNewVisibility;
67 private final ChangeInfoImpl myChangeInfo;
68 private final PsiManager myManager;
69 private final PsiElementFactory myFactory;
70 private final boolean myGenerateDelegate;
71 private final Set<PsiMethod> myPropagateParametersMethods;
72 private final Set<PsiMethod> myPropagateExceptionsMethods;
74 public ChangeSignatureProcessor(Project project,
75 PsiMethod method,
76 final boolean generateDelegate,
77 @Modifier String newVisibility,
78 String newName,
79 PsiType newType,
80 @NotNull ParameterInfoImpl[] parameterInfo) {
81 this(project, method, generateDelegate, newVisibility, newName,
82 newType != null ? CanonicalTypes.createTypeWrapper(newType) : null,
83 parameterInfo, null, null, null);
86 public ChangeSignatureProcessor(Project project,
87 PsiMethod method,
88 final boolean generateDelegate,
89 String newVisibility,
90 String newName,
91 PsiType newType,
92 ParameterInfoImpl[] parameterInfo,
93 ThrownExceptionInfo[] exceptionInfos) {
94 this(project, method, generateDelegate, newVisibility, newName,
95 newType != null ? CanonicalTypes.createTypeWrapper(newType) : null,
96 parameterInfo, exceptionInfos, null, null);
99 public ChangeSignatureProcessor(Project project,
100 PsiMethod method,
101 boolean generateDelegate,
102 String newVisibility,
103 String newName,
104 CanonicalTypes.Type newType,
105 @NotNull ParameterInfoImpl[] parameterInfo,
106 ThrownExceptionInfo[] thrownExceptions,
107 Set<PsiMethod> propagateParametersMethods,
108 Set<PsiMethod> propagateExceptionsMethods) {
109 super(project);
110 myManager = PsiManager.getInstance(project);
111 myFactory = JavaPsiFacade.getInstance(myManager.getProject()).getElementFactory();
112 myGenerateDelegate = generateDelegate;
114 myPropagateParametersMethods = propagateParametersMethods != null ? propagateParametersMethods : new HashSet<PsiMethod>();
115 myPropagateExceptionsMethods = propagateExceptionsMethods != null ? propagateExceptionsMethods : new HashSet<PsiMethod>();
117 LOG.assertTrue(method.isValid());
118 if (newVisibility == null) {
119 myNewVisibility = VisibilityUtil.getVisibilityModifier(method.getModifierList());
120 } else {
121 myNewVisibility = newVisibility;
124 myChangeInfo = new ChangeInfoImpl(myNewVisibility, method, newName, newType, parameterInfo, thrownExceptions);
125 LOG.assertTrue(myChangeInfo.getMethod().isValid());
128 protected UsageViewDescriptor createUsageViewDescriptor(UsageInfo[] usages) {
129 return new ChangeSignatureViewDescriptor(myChangeInfo.getMethod());
132 @NotNull
133 protected UsageInfo[] findUsages() {
134 ArrayList<UsageInfo> result = new ArrayList<UsageInfo>();
135 final PsiMethod method = myChangeInfo.getMethod();
137 findSimpleUsages(method, result);
139 final UsageInfo[] usageInfos = result.toArray(new UsageInfo[result.size()]);
140 return UsageViewUtil.removeDuplicatedUsages(usageInfos);
143 private void findSimpleUsages(final PsiMethod method, final ArrayList<UsageInfo> result) {
144 PsiMethod[] overridingMethods = findSimpleUsagesWithoutParameters(method, result, true, true, true);
145 findUsagesInCallers (result);
147 //Parameter name changes are not propagated
148 findParametersUsage(method, result, overridingMethods);
151 private PsiMethod[] findSimpleUsagesWithoutParameters(final PsiMethod method,
152 final ArrayList<UsageInfo> result,
153 boolean isToModifyArgs,
154 boolean isToThrowExceptions,
155 boolean isOriginal) {
157 GlobalSearchScope projectScope = GlobalSearchScope.projectScope(myProject);
158 PsiMethod[] overridingMethods = OverridingMethodsSearch.search(method, method.getUseScope(), true).toArray(PsiMethod.EMPTY_ARRAY);
160 for (PsiMethod overridingMethod : overridingMethods) {
161 result.add(new OverriderUsageInfo(overridingMethod, method, isOriginal, isToModifyArgs, isToThrowExceptions));
164 boolean needToChangeCalls = !myGenerateDelegate && (myChangeInfo.isNameChanged || myChangeInfo.isParameterSetOrOrderChanged || myChangeInfo.isExceptionSetOrOrderChanged || myChangeInfo.isVisibilityChanged/*for checking inaccessible*/);
165 if (needToChangeCalls) {
166 int parameterCount = method.getParameterList().getParametersCount();
168 PsiReference[] refs = MethodReferencesSearch.search(method, projectScope, true).toArray(PsiReference.EMPTY_ARRAY);
169 for (PsiReference ref : refs) {
170 PsiElement element = ref.getElement();
171 boolean isToCatchExceptions = isToThrowExceptions && needToCatchExceptions(RefactoringUtil.getEnclosingMethod(element));
172 if (!isToCatchExceptions) {
173 if (RefactoringUtil.isMethodUsage(element)) {
174 PsiExpressionList list = RefactoringUtil.getArgumentListByMethodReference(element);
175 if (!method.isVarArgs() && list.getExpressions().length != parameterCount) continue;
178 if (RefactoringUtil.isMethodUsage(element)) {
179 result.add(new MethodCallUsageInfo(element, isToModifyArgs, isToCatchExceptions));
181 else if (element instanceof PsiDocTagValue) {
182 result.add(new UsageInfo(ref.getElement()));
184 else if (element instanceof PsiMethod && ((PsiMethod)element).isConstructor()) {
185 DefaultConstructorImplicitUsageInfo implicitUsageInfo = new DefaultConstructorImplicitUsageInfo((PsiMethod)element, method);
186 result.add(implicitUsageInfo);
188 else if(element instanceof PsiClass) {
189 result.add(new NoConstructorClassUsageInfo((PsiClass)element));
191 else if (ref instanceof PsiCallReference) {
192 result.add(new CallReferenceUsageInfo((PsiCallReference) ref));
194 else {
195 result.add(new MoveRenameUsageInfo(element, ref, method));
199 //if (method.isConstructor() && parameterCount == 0) {
200 // RefactoringUtil.visitImplicitConstructorUsages(method.getContainingClass(),
201 // new DefaultConstructorUsageCollector(result));
204 else if (myChangeInfo.isParameterTypesChanged) {
205 PsiReference[] refs = MethodReferencesSearch.search(method, projectScope, true).toArray(PsiReference.EMPTY_ARRAY);
206 for (PsiReference reference : refs) {
207 final PsiElement element = reference.getElement();
208 if (element instanceof PsiDocTagValue) {
209 result.add(new UsageInfo(reference));
211 else if (element instanceof XmlElement) {
212 result.add(new MoveRenameUsageInfo(reference, method));
217 // Conflicts
218 detectLocalsCollisionsInMethod(method, result, isOriginal);
219 for (final PsiMethod overridingMethod : overridingMethods) {
220 detectLocalsCollisionsInMethod(overridingMethod, result, isOriginal);
223 return overridingMethods;
226 private void findUsagesInCallers(final ArrayList<UsageInfo> usages) {
227 for (PsiMethod caller : myPropagateParametersMethods) {
228 usages.add(new CallerUsageInfo(caller, true, myPropagateExceptionsMethods.contains(caller)));
230 for (PsiMethod caller : myPropagateExceptionsMethods) {
231 usages.add(new CallerUsageInfo(caller, myPropagateParametersMethods.contains(caller), true));
233 Set<PsiMethod> merged = new HashSet<PsiMethod>();
234 merged.addAll(myPropagateParametersMethods);
235 merged.addAll(myPropagateExceptionsMethods);
236 for (final PsiMethod method : merged) {
237 findSimpleUsagesWithoutParameters(method, usages, myPropagateParametersMethods.contains(method),
238 myPropagateExceptionsMethods.contains(method), false);
242 private boolean needToChangeCalls() {
243 return myChangeInfo.isNameChanged || myChangeInfo.isParameterSetOrOrderChanged || myChangeInfo.isExceptionSetOrOrderChanged;
246 private boolean needToCatchExceptions(PsiMethod caller) {
247 return myChangeInfo.isExceptionSetOrOrderChanged && !myPropagateExceptionsMethods.contains(caller);
250 private void detectLocalsCollisionsInMethod(final PsiMethod method,
251 final ArrayList<UsageInfo> result,
252 boolean isOriginal) {
253 final PsiParameter[] parameters = method.getParameterList().getParameters();
254 final Set<PsiParameter> deletedOrRenamedParameters = new HashSet<PsiParameter>();
255 if (isOriginal) {
256 deletedOrRenamedParameters.addAll(Arrays.asList(parameters));
257 for (ParameterInfoImpl parameterInfo : myChangeInfo.newParms) {
258 if (parameterInfo.oldParameterIndex >= 0) {
259 final PsiParameter parameter = parameters[parameterInfo.oldParameterIndex];
260 if (parameterInfo.getName().equals(parameter.getName())) {
261 deletedOrRenamedParameters.remove(parameter);
267 for (ParameterInfoImpl parameterInfo : myChangeInfo.newParms) {
268 final int oldParameterIndex = parameterInfo.oldParameterIndex;
269 final String newName = parameterInfo.getName();
270 if (oldParameterIndex >= 0) {
271 if (isOriginal) { //Name changes take place only in primary method
272 final PsiParameter parameter = parameters[oldParameterIndex];
273 if (!newName.equals(parameter.getName())) {
274 JavaUnresolvableLocalCollisionDetector.visitLocalsCollisions(parameter, newName, method.getBody(), null, new JavaUnresolvableLocalCollisionDetector.CollidingVariableVisitor() {
275 public void visitCollidingElement(final PsiVariable collidingVariable) {
276 if (!(collidingVariable instanceof PsiField) && !deletedOrRenamedParameters.contains(collidingVariable)) {
277 result.add(new RenamedParameterCollidesWithLocalUsageInfo(parameter, collidingVariable, method));
284 else {
285 JavaUnresolvableLocalCollisionDetector.visitLocalsCollisions(method, newName, method.getBody(), null, new JavaUnresolvableLocalCollisionDetector.CollidingVariableVisitor() {
286 public void visitCollidingElement(PsiVariable collidingVariable) {
287 if (!(collidingVariable instanceof PsiField) && !deletedOrRenamedParameters.contains(collidingVariable)) {
288 result.add(new NewParameterCollidesWithLocalUsageInfo(collidingVariable, collidingVariable, method));
296 private void findParametersUsage(final PsiMethod method, ArrayList<UsageInfo> result, PsiMethod[] overriders) {
297 PsiParameter[] parameters = method.getParameterList().getParameters();
298 for (ParameterInfoImpl info : myChangeInfo.newParms) {
299 if (info.oldParameterIndex >= 0) {
300 PsiParameter parameter = parameters[info.oldParameterIndex];
301 if (!info.getName().equals(parameter.getName())) {
302 addParameterUsages(parameter, result, info);
304 for (PsiMethod overrider : overriders) {
305 PsiParameter parameter1 = overrider.getParameterList().getParameters()[info.oldParameterIndex];
306 if (parameter.getName().equals(parameter1.getName())) {
307 addParameterUsages(parameter1, result, info);
315 protected void refreshElements(PsiElement[] elements) {
316 boolean condition = elements.length == 1 && elements[0] instanceof PsiMethod;
317 LOG.assertTrue(condition);
318 myChangeInfo.updateMethod((PsiMethod) elements[0]);
321 private void addMethodConflicts(MultiMap<PsiElement, String> conflicts) {
322 String newMethodName = myChangeInfo.newName;
324 try {
325 PsiMethod prototype;
326 PsiManager manager = PsiManager.getInstance(myProject);
327 PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory();
328 final PsiMethod method = myChangeInfo.getMethod();
329 final CanonicalTypes.Type returnType = myChangeInfo.newReturnType;
330 if (returnType != null) {
331 prototype = factory.createMethod(newMethodName, returnType.getType(method, manager));
333 else {
334 prototype = factory.createConstructor();
335 prototype.setName(newMethodName);
337 ParameterInfoImpl[] parameters = myChangeInfo.newParms;
340 for (ParameterInfoImpl info : parameters) {
341 final PsiType parameterType = info.createType(method, manager);
342 PsiParameter param = factory.createParameter(info.getName(), parameterType);
343 prototype.getParameterList().add(param);
346 ConflictsUtil.checkMethodConflicts(
347 method.getContainingClass(),
348 method,
349 prototype, conflicts);
351 catch (IncorrectOperationException e) {
352 LOG.error(e);
357 protected boolean preprocessUsages(Ref<UsageInfo[]> refUsages) {
358 MultiMap<PsiElement, String> conflictDescriptions = new MultiMap<PsiElement, String>();
359 UsageInfo[] usagesIn = refUsages.get();
360 addMethodConflicts(conflictDescriptions);
361 RenameUtil.addConflictDescriptions(usagesIn, conflictDescriptions);
362 Set<UsageInfo> usagesSet = new HashSet<UsageInfo>(Arrays.asList(usagesIn));
363 RenameUtil.removeConflictUsages(usagesSet);
364 if (myChangeInfo.isVisibilityChanged) {
365 try {
366 addInaccessibilityDescriptions(usagesSet, conflictDescriptions);
368 catch (IncorrectOperationException e) {
369 LOG.error(e);
373 if (myPrepareSuccessfulSwingThreadCallback != null && !conflictDescriptions.isEmpty()) {
374 ConflictsDialog dialog = new ConflictsDialog(myProject, conflictDescriptions);
375 dialog.show();
376 if (!dialog.isOK()){
377 if (dialog.isShowConflicts()) prepareSuccessful();
378 return false;
382 if (myChangeInfo.isReturnTypeChanged) {
383 askToRemoveCovariantOverriders (usagesSet);
386 refUsages.set(usagesSet.toArray(new UsageInfo[usagesSet.size()]));
387 prepareSuccessful();
388 return true;
391 private void addInaccessibilityDescriptions(Set<UsageInfo> usages, MultiMap<PsiElement, String> conflictDescriptions) throws IncorrectOperationException {
392 PsiMethod method = myChangeInfo.getMethod();
393 PsiModifierList modifierList = (PsiModifierList)method.getModifierList().copy();
394 RefactoringConflictsUtil.setVisibility(modifierList, myNewVisibility);
396 for (Iterator<UsageInfo> iterator = usages.iterator(); iterator.hasNext();) {
397 UsageInfo usageInfo = iterator.next();
398 PsiElement element = usageInfo.getElement();
399 if (element != null) {
400 if (element instanceof PsiReferenceExpression) {
401 PsiClass accessObjectClass = null;
402 PsiExpression qualifier = ((PsiReferenceExpression)element).getQualifierExpression();
403 if (qualifier != null) {
404 accessObjectClass = (PsiClass)PsiUtil.getAccessObjectClass(qualifier).getElement();
407 if (!JavaPsiFacade.getInstance(element.getProject()).getResolveHelper()
408 .isAccessible(method, modifierList, element, accessObjectClass, null)) {
409 String message =
410 RefactoringBundle.message("0.with.1.visibility.is.not.accesible.from.2",
411 RefactoringUIUtil.getDescription(method, true),
412 myNewVisibility,
413 RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(element), true));
414 conflictDescriptions.putValue(method, message);
415 if (!needToChangeCalls()) {
416 iterator.remove();
424 private void askToRemoveCovariantOverriders(Set<UsageInfo> usages) {
425 if (PsiUtil.isLanguageLevel5OrHigher(myChangeInfo.getMethod())) {
426 List<UsageInfo> covariantOverriderInfos = new ArrayList<UsageInfo>();
427 for (UsageInfo usageInfo : usages) {
428 if (usageInfo instanceof OverriderUsageInfo) {
429 final OverriderUsageInfo info = (OverriderUsageInfo)usageInfo;
430 PsiMethod overrider = info.getElement();
431 PsiMethod baseMethod = info.getBaseMethod();
432 PsiSubstitutor substitutor = calculateSubstitutor(overrider, baseMethod);
433 PsiType type;
434 try {
435 type = substitutor.substitute(myChangeInfo.newReturnType.getType(myChangeInfo.getMethod(), myManager));
437 catch (IncorrectOperationException e) {
438 LOG.error(e);
439 return;
441 final PsiType overriderType = overrider.getReturnType();
442 if (overriderType != null && type.isAssignableFrom(overriderType)) {
443 covariantOverriderInfos.add(usageInfo);
448 // to be able to do filtering
449 preprocessCovariantOverriders(covariantOverriderInfos);
451 if (!covariantOverriderInfos.isEmpty()) {
452 if (ApplicationManager.getApplication().isUnitTestMode() || !isProcessCovariantOverriders()) {
453 for (UsageInfo usageInfo : covariantOverriderInfos) {
454 usages.remove(usageInfo);
461 protected void preprocessCovariantOverriders(final List<UsageInfo> covariantOverriderInfos) {
464 protected boolean isProcessCovariantOverriders() {
465 return Messages.showYesNoDialog(myProject, RefactoringBundle.message("do.you.want.to.process.overriding.methods.with.covariant.return.type"),
466 ChangeSignatureHandler.REFACTORING_NAME, Messages.getQuestionIcon())
467 == DialogWrapper.OK_EXIT_CODE;
470 protected void performRefactoring(UsageInfo[] usages) {
471 PsiElementFactory factory = JavaPsiFacade.getInstance(myManager.getProject()).getElementFactory();
473 try {
474 if (myChangeInfo.isNameChanged) {
475 myChangeInfo.newNameIdentifier = factory.createIdentifier(myChangeInfo.newName);
478 if (myChangeInfo.isReturnTypeChanged) {
479 myChangeInfo.newTypeElement = myChangeInfo.newReturnType.getType(myChangeInfo.getMethod(), myManager);
482 if (myGenerateDelegate) {
483 generateDelegate();
486 for (UsageInfo usage : usages) {
487 if (usage instanceof CallerUsageInfo) {
488 final CallerUsageInfo callerUsageInfo = (CallerUsageInfo)usage;
489 processCallerMethod(callerUsageInfo.getMethod(), null, callerUsageInfo.isToInsertParameter(),
490 callerUsageInfo.isToInsertException());
492 else if (usage instanceof OverriderUsageInfo) {
493 OverriderUsageInfo info = (OverriderUsageInfo)usage;
494 final PsiMethod method = info.getElement();
495 final PsiMethod baseMethod = info.getBaseMethod();
496 if (info.isOriginalOverrider()) {
497 processPrimaryMethod(method, baseMethod, false);
499 else {
500 processCallerMethod(method, baseMethod, info.isToInsertArgs(), info.isToCatchExceptions());
505 LOG.assertTrue(myChangeInfo.getMethod().isValid());
506 processPrimaryMethod(myChangeInfo.getMethod(), null, true);
507 List<UsageInfo> postponedUsages = new ArrayList<UsageInfo>();
509 for (UsageInfo usage : usages) {
510 PsiElement element = usage.getElement();
511 if (element == null) continue;
513 if (usage instanceof DefaultConstructorImplicitUsageInfo) {
514 final DefaultConstructorImplicitUsageInfo defConstructorUsage = (DefaultConstructorImplicitUsageInfo)usage;
515 addSuperCall(defConstructorUsage.getConstructor(), defConstructorUsage.getBaseConstructor(),usages);
517 else if (usage instanceof NoConstructorClassUsageInfo) {
518 addDefaultConstructor(((NoConstructorClassUsageInfo)usage).getPsiClass(),usages);
520 else if (element instanceof PsiJavaCodeReferenceElement) {
521 if (usage instanceof MethodCallUsageInfo) {
522 final MethodCallUsageInfo methodCallInfo = (MethodCallUsageInfo)usage;
523 processMethodUsage(methodCallInfo.getElement(), myChangeInfo, methodCallInfo.isToChangeArguments(),
524 methodCallInfo.isToCatchExceptions(), methodCallInfo.getReferencedMethod(), usages);
526 else if (usage instanceof MyParameterUsageInfo) {
527 String newName = ((MyParameterUsageInfo)usage).newParameterName;
528 String oldName = ((MyParameterUsageInfo)usage).oldParameterName;
529 processParameterUsage((PsiReferenceExpression)element, oldName, newName);
530 } else {
531 postponedUsages.add(usage);
534 else if (usage instanceof CallReferenceUsageInfo) {
535 ((CallReferenceUsageInfo) usage).getReference().handleChangeSignature(myChangeInfo);
537 else if (element instanceof PsiEnumConstant) {
538 fixActualArgumentsList(((PsiEnumConstant)element).getArgumentList(), myChangeInfo, true);
540 else if (!(usage instanceof OverriderUsageInfo)) {
541 postponedUsages.add(usage);
545 for (UsageInfo usageInfo : postponedUsages) {
546 PsiElement element = usageInfo.getElement();
547 if (element == null) continue;
548 PsiReference reference = usageInfo instanceof MoveRenameUsageInfo ?
549 usageInfo.getReference() :
550 element.getReference();
551 if (reference != null) {
552 PsiElement target = null;
553 if (usageInfo instanceof MyParameterUsageInfo) {
554 String newParameterName = ((MyParameterUsageInfo)usageInfo).newParameterName;
555 PsiParameter[] newParams = myChangeInfo.getMethod().getParameterList().getParameters();
556 for (PsiParameter newParam : newParams) {
557 if (newParam.getName().equals(newParameterName)) {
558 target = newParam;
559 break;
563 else {
564 target = myChangeInfo.getMethod();
566 if (target != null) {
567 reference.bindToElement(target);
572 LOG.assertTrue(myChangeInfo.getMethod().isValid());
573 } catch (IncorrectOperationException e) {
574 LOG.error(e);
578 private void generateDelegate() throws IncorrectOperationException {
579 final PsiMethod delegate = (PsiMethod)myChangeInfo.getMethod().copy();
580 final PsiClass targetClass = myChangeInfo.getMethod().getContainingClass();
581 LOG.assertTrue(!targetClass.isInterface());
582 makeEmptyBody(myFactory, delegate);
583 final PsiCallExpression callExpression = addDelegatingCallTemplate(delegate, myChangeInfo.newName);
584 addDelegateArguments(callExpression);
585 targetClass.addBefore(delegate, myChangeInfo.getMethod());
588 private void addDelegateArguments(final PsiCallExpression callExpression) throws IncorrectOperationException {
589 final ParameterInfoImpl[] newParms = myChangeInfo.newParms;
590 for (int i = 0; i < newParms.length; i++) {
591 ParameterInfoImpl newParm = newParms[i];
592 final PsiExpression actualArg;
593 if (newParm.oldParameterIndex >= 0) {
594 actualArg = myFactory.createExpressionFromText(myChangeInfo.oldParameterNames[newParm.oldParameterIndex], callExpression);
596 else {
597 actualArg = myChangeInfo.getValue(i, callExpression);
599 callExpression.getArgumentList().add(actualArg);
603 public static void makeEmptyBody(final PsiElementFactory factory, final PsiMethod delegate) throws IncorrectOperationException {
604 PsiCodeBlock body = delegate.getBody();
605 if (body != null) {
606 body.replace(factory.createCodeBlock());
608 else {
609 delegate.add(factory.createCodeBlock());
611 PsiUtil.setModifierProperty(delegate, PsiModifier.ABSTRACT, false);
614 public static PsiCallExpression addDelegatingCallTemplate(final PsiMethod delegate, final String newName) throws IncorrectOperationException {
615 Project project = delegate.getProject();
616 PsiElementFactory factory = JavaPsiFacade.getInstance(project).getElementFactory();
617 PsiCodeBlock body = delegate.getBody();
618 assert body != null;
619 final PsiCallExpression callExpression;
620 if (delegate.isConstructor()) {
621 PsiElement callStatement = factory.createStatementFromText("this();", null);
622 callStatement = CodeStyleManager.getInstance(project).reformat(callStatement);
623 callStatement = body.add(callStatement);
624 callExpression = (PsiCallExpression)((PsiExpressionStatement) callStatement).getExpression();
625 } else {
626 if (PsiType.VOID.equals(delegate.getReturnType())) {
627 PsiElement callStatement = factory.createStatementFromText(newName + "();", null);
628 callStatement = CodeStyleManager.getInstance(project).reformat(callStatement);
629 callStatement = body.add(callStatement);
630 callExpression = (PsiCallExpression)((PsiExpressionStatement) callStatement).getExpression();
632 else {
633 PsiElement callStatement = factory.createStatementFromText("return " + newName + "();", null);
634 callStatement = CodeStyleManager.getInstance(project).reformat(callStatement);
635 callStatement = body.add(callStatement);
636 callExpression = (PsiCallExpression)((PsiReturnStatement) callStatement).getReturnValue();
639 return callExpression;
642 private void addDefaultConstructor(PsiClass aClass, final UsageInfo[] usages) throws IncorrectOperationException {
643 if (!(aClass instanceof PsiAnonymousClass)) {
644 PsiMethod defaultConstructor = myFactory.createMethodFromText(aClass.getName() + "(){}", aClass);
645 defaultConstructor = (PsiMethod) CodeStyleManager.getInstance(myProject).reformat(defaultConstructor);
646 defaultConstructor = (PsiMethod) aClass.add(defaultConstructor);
647 PsiUtil.setModifierProperty(defaultConstructor, VisibilityUtil.getVisibilityModifier(aClass.getModifierList()), true);
648 addSuperCall(defaultConstructor, null, usages);
649 } else {
650 final PsiElement parent = aClass.getParent();
651 if (parent instanceof PsiNewExpression) {
652 final PsiExpressionList argumentList = ((PsiNewExpression) parent).getArgumentList();
653 fixActualArgumentsList(argumentList, myChangeInfo, true);
658 private void addSuperCall(PsiMethod constructor, PsiMethod callee, final UsageInfo[] usages) throws IncorrectOperationException {
659 PsiExpressionStatement superCall = (PsiExpressionStatement) myFactory.createStatementFromText("super();", constructor);
660 PsiCodeBlock body = constructor.getBody();
661 assert body != null;
662 PsiStatement[] statements = body.getStatements();
663 if (statements.length > 0) {
664 superCall = (PsiExpressionStatement) body.addBefore(superCall, statements[0]);
665 } else {
666 superCall = (PsiExpressionStatement) body.add(superCall);
668 PsiMethodCallExpression callExpression = (PsiMethodCallExpression) superCall.getExpression();
669 processMethodUsage(callExpression.getMethodExpression(), myChangeInfo, true, false, callee, usages);
672 private PsiParameter createNewParameter(ParameterInfoImpl newParm,
673 PsiSubstitutor substitutor) throws IncorrectOperationException {
674 final PsiElementFactory factory = JavaPsiFacade.getInstance(myProject).getElementFactory();
675 final PsiType type = substitutor.substitute(newParm.createType(myChangeInfo.getMethod().getParameterList(), myManager));
676 return factory.createParameter(newParm.getName(), type);
679 protected String getCommandName() {
680 return RefactoringBundle.message("changing.signature.of.0", UsageViewUtil.getDescriptiveName(myChangeInfo.getMethod()));
683 private void processMethodUsage(PsiElement ref,
684 ChangeInfoImpl changeInfo,
685 boolean toChangeArguments,
686 boolean toCatchExceptions,
687 PsiMethod callee, final UsageInfo[] usages) throws IncorrectOperationException {
688 if (changeInfo.isNameChanged) {
689 if (ref instanceof PsiJavaCodeReferenceElement) {
690 PsiElement last = ((PsiJavaCodeReferenceElement)ref).getReferenceNameElement();
691 if (last instanceof PsiIdentifier && last.getText().equals(changeInfo.oldName)) {
692 last.replace(changeInfo.newNameIdentifier);
697 final PsiMethod caller = RefactoringUtil.getEnclosingMethod(ref);
698 if (toChangeArguments) {
699 final PsiExpressionList list = RefactoringUtil.getArgumentListByMethodReference(ref);
700 boolean toInsertDefaultValue = !myPropagateParametersMethods.contains(caller);
701 if (toInsertDefaultValue && ref instanceof PsiReferenceExpression) {
702 final PsiExpression qualifierExpression = ((PsiReferenceExpression) ref).getQualifierExpression();
703 if (qualifierExpression instanceof PsiSuperExpression && callerSignatureIsAboutToChangeToo(caller, usages)) {
704 toInsertDefaultValue = false;
708 fixActualArgumentsList(list, changeInfo, toInsertDefaultValue);
711 if (toCatchExceptions) {
712 if (!(ref instanceof PsiReferenceExpression && ((PsiReferenceExpression)ref).getQualifierExpression() instanceof PsiSuperExpression)) {
713 if (needToCatchExceptions(caller)) {
714 PsiClassType[] newExceptions = callee != null ? getCalleeChangedExceptionInfo(callee) : getPrimaryChangedExceptionInfo(changeInfo);
715 fixExceptions(ref, newExceptions);
721 private static boolean callerSignatureIsAboutToChangeToo(final PsiMethod caller, final UsageInfo[] usages) {
722 for (UsageInfo usage : usages) {
723 if (usage instanceof MethodCallUsageInfo && MethodSignatureUtil.isSuperMethod(((MethodCallUsageInfo)usage).getReferencedMethod(), caller)) return true;
725 return false;
728 private static PsiClassType[] getCalleeChangedExceptionInfo(final PsiMethod callee) {
729 return callee.getThrowsList().getReferencedTypes(); //Callee method's throws list is already modified!
732 private PsiClassType[] getPrimaryChangedExceptionInfo(ChangeInfoImpl changeInfo) throws IncorrectOperationException {
733 PsiClassType[] newExceptions = new PsiClassType[changeInfo.newExceptions.length];
734 for (int i = 0; i < newExceptions.length; i++) {
735 newExceptions[i] = (PsiClassType)changeInfo.newExceptions[i].myType.getType(myChangeInfo.getMethod(), myManager); //context really does not matter here
737 return newExceptions;
740 private void fixExceptions(PsiElement ref, PsiClassType[] newExceptions) throws IncorrectOperationException {
741 //methods' throws lists are already modified, may use ExceptionUtil.collectUnhandledExceptions
742 newExceptions = filterCheckedExceptions(newExceptions);
744 PsiElement context = PsiTreeUtil.getParentOfType(ref, PsiTryStatement.class, PsiMethod.class);
745 if (context instanceof PsiTryStatement) {
746 PsiTryStatement tryStatement = (PsiTryStatement)context;
747 PsiCodeBlock tryBlock = tryStatement.getTryBlock();
749 //Remove unused catches
750 Collection<PsiClassType> classes = ExceptionUtil.collectUnhandledExceptions(tryBlock, tryBlock);
751 PsiParameter[] catchParameters = tryStatement.getCatchBlockParameters();
752 for (PsiParameter parameter : catchParameters) {
753 final PsiType caughtType = parameter.getType();
755 if (!(caughtType instanceof PsiClassType)) continue;
756 if (ExceptionUtil.isUncheckedExceptionOrSuperclass((PsiClassType)caughtType)) continue;
758 if (!isCatchParameterRedundant((PsiClassType)caughtType, classes)) continue;
759 parameter.getParent().delete(); //delete catch section
762 PsiClassType[] exceptionsToAdd = filterUnhandledExceptions(newExceptions, tryBlock);
763 addExceptions(exceptionsToAdd, tryStatement);
765 adjustPossibleEmptyTryStatement(tryStatement);
767 else {
768 newExceptions = filterUnhandledExceptions(newExceptions, ref);
769 if (newExceptions.length > 0) {
770 //Add new try statement
771 PsiElementFactory elementFactory = JavaPsiFacade.getInstance(myManager.getProject()).getElementFactory();
772 PsiTryStatement tryStatement = (PsiTryStatement)elementFactory.createStatementFromText("try {} catch (Exception e) {}", null);
773 PsiStatement anchor = PsiTreeUtil.getParentOfType(ref, PsiStatement.class);
774 LOG.assertTrue(anchor != null);
775 tryStatement.getTryBlock().add(anchor);
776 tryStatement = (PsiTryStatement)anchor.getParent().addAfter(tryStatement, anchor);
778 addExceptions(newExceptions, tryStatement);
779 anchor.delete();
780 tryStatement.getCatchSections()[0].delete(); //Delete dummy catch section
785 private static PsiClassType[] filterCheckedExceptions(PsiClassType[] exceptions) {
786 List<PsiClassType> result = new ArrayList<PsiClassType>();
787 for (PsiClassType exceptionType : exceptions) {
788 if (!ExceptionUtil.isUncheckedException(exceptionType)) result.add(exceptionType);
790 return result.toArray(new PsiClassType[result.size()]);
793 private static void adjustPossibleEmptyTryStatement(PsiTryStatement tryStatement) throws IncorrectOperationException {
794 PsiCodeBlock tryBlock = tryStatement.getTryBlock();
795 if (tryBlock != null) {
796 if (tryStatement.getCatchSections().length == 0 &&
797 tryStatement.getFinallyBlock() == null) {
798 PsiElement firstBodyElement = tryBlock.getFirstBodyElement();
799 if (firstBodyElement != null) {
800 tryStatement.getParent().addRangeAfter(firstBodyElement, tryBlock.getLastBodyElement(), tryStatement);
802 tryStatement.delete();
807 private static void addExceptions(PsiClassType[] exceptionsToAdd, PsiTryStatement tryStatement) throws IncorrectOperationException {
808 for (PsiClassType type : exceptionsToAdd) {
809 final JavaCodeStyleManager styleManager = JavaCodeStyleManager.getInstance(tryStatement.getProject());
810 String name = styleManager.suggestVariableName(VariableKind.PARAMETER, null, null, type).names[0];
811 name = styleManager.suggestUniqueVariableName(name, tryStatement, false);
813 PsiCatchSection catchSection =
814 JavaPsiFacade.getInstance(tryStatement.getProject()).getElementFactory().createCatchSection(type, name, tryStatement);
815 tryStatement.add(catchSection);
819 private void fixPrimaryThrowsLists(PsiMethod method, PsiClassType[] newExceptions) throws IncorrectOperationException {
820 PsiElementFactory elementFactory = JavaPsiFacade.getInstance(myManager.getProject()).getElementFactory();
821 PsiJavaCodeReferenceElement[] refs = new PsiJavaCodeReferenceElement[newExceptions.length];
822 for (int i = 0; i < refs.length; i++) {
823 refs[i] = elementFactory.createReferenceElementByType(newExceptions[i]);
825 PsiReferenceList throwsList = elementFactory.createReferenceList(refs);
827 replaceThrowsList(method, throwsList);
830 private void replaceThrowsList(PsiMethod method, PsiReferenceList throwsList) throws IncorrectOperationException {
831 PsiReferenceList methodThrowsList = (PsiReferenceList)method.getThrowsList().replace(throwsList);
832 methodThrowsList = (PsiReferenceList)JavaCodeStyleManager.getInstance(myProject).shortenClassReferences(methodThrowsList);
833 myManager.getCodeStyleManager().reformatRange(method, method.getParameterList().getTextRange().getEndOffset(),
834 methodThrowsList.getTextRange().getEndOffset());
837 private static PsiClassType[] filterUnhandledExceptions(PsiClassType[] exceptions, PsiElement place) {
838 List<PsiClassType> result = new ArrayList<PsiClassType>();
839 for (PsiClassType exception : exceptions) {
840 if (!ExceptionUtil.isHandled(exception, place)) result.add(exception);
842 return result.toArray(new PsiClassType[result.size()]);
845 private static boolean isCatchParameterRedundant (PsiClassType catchParamType, Collection<PsiClassType> thrownTypes) {
846 for (PsiType exceptionType : thrownTypes) {
847 if (exceptionType.isConvertibleFrom(catchParamType)) return false;
849 return true;
852 private static int getNonVarargCount(ChangeInfoImpl changeInfo, PsiExpression[] args) {
853 if (!changeInfo.wasVararg) return args.length;
854 return changeInfo.oldParameterTypes.length - 1;
857 //This methods works equally well for primary usages as well as for propagated callers' usages
858 private void fixActualArgumentsList(PsiExpressionList list,
859 ChangeInfoImpl changeInfo,
860 boolean toInsertDefaultValue) throws IncorrectOperationException {
861 final PsiElementFactory factory = JavaPsiFacade.getInstance(list.getProject()).getElementFactory();
862 if (changeInfo.isParameterSetOrOrderChanged) {
863 if (changeInfo.isPropagationEnabled) {
864 final ParameterInfoImpl[] createdParmsInfo = changeInfo.getCreatedParmsInfoWithoutVarargs();
865 for (ParameterInfoImpl info : createdParmsInfo) {
866 PsiExpression newArg;
867 if (toInsertDefaultValue) {
868 newArg = createDefaultValue(factory, info, list);
870 else {
871 newArg = factory.createExpressionFromText(info.getName(), list);
873 list.add(newArg);
876 else {
877 final PsiExpression[] args = list.getExpressions();
878 final int nonVarargCount = getNonVarargCount(changeInfo, args);
879 final int varargCount = args.length - nonVarargCount;
880 PsiExpression[] newVarargInitializers = null;
882 final int newArgsLength;
883 final int newNonVarargCount;
884 if (changeInfo.arrayToVarargs) {
885 newNonVarargCount = changeInfo.newParms.length - 1;
886 final ParameterInfoImpl lastNewParm = changeInfo.newParms[changeInfo.newParms.length - 1];
887 final PsiExpression arrayToConvert = args[lastNewParm.oldParameterIndex];
888 if (arrayToConvert instanceof PsiNewExpression) {
889 final PsiNewExpression expression = (PsiNewExpression)arrayToConvert;
890 final PsiArrayInitializerExpression arrayInitializer = expression.getArrayInitializer();
891 if (arrayInitializer != null) {
892 newVarargInitializers = arrayInitializer.getInitializers();
895 newArgsLength = newVarargInitializers == null ? changeInfo.newParms.length : newNonVarargCount + newVarargInitializers.length;
897 else if (changeInfo.retainsVarargs) {
898 newNonVarargCount = changeInfo.newParms.length - 1;
899 newArgsLength = newNonVarargCount + varargCount;
901 else if (changeInfo.obtainsVarags) {
902 newNonVarargCount = changeInfo.newParms.length - 1;
903 newArgsLength = newNonVarargCount;
905 else {
906 newNonVarargCount = changeInfo.newParms.length;
907 newArgsLength = changeInfo.newParms.length;
909 final PsiExpression[] newArgs = new PsiExpression[newArgsLength];
910 for (int i = 0; i < newNonVarargCount; i++) {
911 newArgs [i] = createActualArgument(list, changeInfo.newParms [i], toInsertDefaultValue, args);
913 if (changeInfo.arrayToVarargs) {
914 if (newVarargInitializers == null) {
915 newArgs [newNonVarargCount] = createActualArgument(list, changeInfo.newParms [newNonVarargCount], toInsertDefaultValue, args);
917 else {
918 for (int i = 0; i < newVarargInitializers.length; i++) {
919 newArgs [i + newNonVarargCount] = newVarargInitializers [i];
923 else {
924 final int newVarargCount = newArgsLength - newNonVarargCount;
925 LOG.assertTrue(newVarargCount == 0 || newVarargCount == varargCount);
926 for (int i = 0; i < newVarargCount; i++) {
927 newArgs[newNonVarargCount + i] = args[nonVarargCount + i];
930 ChangeSignatureUtil.synchronizeList(list, Arrays.asList(newArgs), ExpressionList.INSTANCE, changeInfo.toRemoveParm);
935 private PsiExpression createActualArgument(final PsiExpressionList list, final ParameterInfoImpl info, final boolean toInsertDefaultValue,
936 final PsiExpression[] args) throws IncorrectOperationException {
937 final PsiElementFactory factory = JavaPsiFacade.getInstance(list.getProject()).getElementFactory();
938 final int index = info.oldParameterIndex;
939 if (index >= 0) {
940 return args[index];
941 } else {
942 if (toInsertDefaultValue) {
943 return createDefaultValue(factory, info, list);
944 } else {
945 return factory.createExpressionFromText(info.getName(), list);
950 private PsiExpression createDefaultValue(final PsiElementFactory factory, final ParameterInfoImpl info, final PsiExpressionList list)
951 throws IncorrectOperationException {
952 if (info.useAnySingleVariable) {
953 final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(list.getProject()).getResolveHelper();
954 final PsiType type = info.getTypeWrapper().getType(myChangeInfo.getMethod(), myManager);
955 final VariablesProcessor processor = new VariablesProcessor(false) {
956 protected boolean check(PsiVariable var, ResolveState state) {
957 if (var instanceof PsiField && !resolveHelper.isAccessible((PsiField)var, list, null)) return false;
958 final PsiType varType = state.get(PsiSubstitutor.KEY).substitute(var.getType());
959 return type.isAssignableFrom(varType);
962 public boolean execute(PsiElement pe, ResolveState state) {
963 super.execute(pe, state);
964 return size() < 2;
967 PsiScopesUtil.treeWalkUp(processor, list, null);
968 if (processor.size() == 1) {
969 final PsiVariable result = processor.getResult(0);
970 return factory.createExpressionFromText(result.getName(), list);
973 final PsiCallExpression callExpression = PsiTreeUtil.getParentOfType(list, PsiCallExpression.class);
974 return callExpression != null ? info.getValue(callExpression) : factory.createExpressionFromText(info.defaultValue, list);
977 private static void addParameterUsages(PsiParameter parameter,
978 ArrayList<UsageInfo> results,
979 ParameterInfoImpl info) {
980 PsiManager manager = parameter.getManager();
981 GlobalSearchScope projectScope = GlobalSearchScope.projectScope(manager.getProject());
982 for (PsiReference psiReference : ReferencesSearch.search(parameter, projectScope, false)) {
983 PsiElement parmRef = psiReference.getElement();
984 UsageInfo usageInfo = new MyParameterUsageInfo(parmRef, parameter.getName(), info.getName());
985 results.add(usageInfo);
989 private void processCallerMethod(PsiMethod caller,
990 PsiMethod baseMethod,
991 boolean toInsertParams,
992 boolean toInsertThrows) throws IncorrectOperationException {
993 LOG.assertTrue(toInsertParams || toInsertThrows);
994 if (toInsertParams) {
995 List<PsiParameter> newParameters = new ArrayList<PsiParameter>();
996 newParameters.addAll(Arrays.asList(caller.getParameterList().getParameters()));
997 final ParameterInfoImpl[] primaryNewParms = myChangeInfo.newParms;
998 PsiSubstitutor substitutor = baseMethod == null ? PsiSubstitutor.EMPTY : calculateSubstitutor(caller, baseMethod);
999 for (ParameterInfoImpl info : primaryNewParms) {
1000 if (info.oldParameterIndex < 0) newParameters.add(createNewParameter(info, substitutor));
1002 PsiParameter[] arrayed = newParameters.toArray(new PsiParameter[newParameters.size()]);
1003 boolean[] toRemoveParm = new boolean[arrayed.length];
1004 Arrays.fill(toRemoveParm, false);
1005 resolveParameterVsFieldsConflicts(arrayed, caller, caller.getParameterList(), toRemoveParm);
1008 if (toInsertThrows) {
1009 List<PsiJavaCodeReferenceElement> newThrowns = new ArrayList<PsiJavaCodeReferenceElement>();
1010 final PsiReferenceList throwsList = caller.getThrowsList();
1011 newThrowns.addAll(Arrays.asList(throwsList.getReferenceElements()));
1012 final ThrownExceptionInfo[] primaryNewExns = myChangeInfo.newExceptions;
1013 for (ThrownExceptionInfo thrownExceptionInfo : primaryNewExns) {
1014 if (thrownExceptionInfo.oldIndex < 0) {
1015 final PsiClassType type = (PsiClassType)thrownExceptionInfo.createType(caller, myManager);
1016 final PsiJavaCodeReferenceElement ref =
1017 JavaPsiFacade.getInstance(caller.getProject()).getElementFactory().createReferenceElementByType(type);
1018 newThrowns.add(ref);
1021 PsiJavaCodeReferenceElement[] arrayed = newThrowns.toArray(new PsiJavaCodeReferenceElement[newThrowns.size()]);
1022 boolean[] toRemoveParm = new boolean[arrayed.length];
1023 Arrays.fill(toRemoveParm, false);
1024 ChangeSignatureUtil.synchronizeList(throwsList, Arrays.asList(arrayed), ThrowsList.INSTANCE, toRemoveParm);
1028 private void processPrimaryMethod(PsiMethod method,
1029 PsiMethod baseMethod,
1030 boolean isOriginal) throws IncorrectOperationException {
1031 PsiElementFactory factory = JavaPsiFacade.getInstance(method.getProject()).getElementFactory();
1033 if (myChangeInfo.isVisibilityChanged) {
1034 PsiModifierList modifierList = method.getModifierList();
1035 final String highestVisibility = isOriginal ?
1036 myNewVisibility :
1037 VisibilityUtil.getHighestVisibility(myNewVisibility, VisibilityUtil.getVisibilityModifier(modifierList));
1038 RefactoringConflictsUtil.setVisibility(modifierList, highestVisibility);
1041 if (myChangeInfo.isNameChanged) {
1042 String newName = baseMethod == null ? myChangeInfo.newName :
1043 RefactoringUtil.suggestNewOverriderName(method.getName(), baseMethod.getName(), myChangeInfo.newName);
1045 if (newName != null && !newName.equals(method.getName())) {
1046 final PsiIdentifier nameId = method.getNameIdentifier();
1047 assert nameId != null;
1048 nameId.replace(JavaPsiFacade.getInstance(myManager.getProject()).getElementFactory().createIdentifier(newName));
1052 final PsiSubstitutor substitutor = baseMethod == null ? PsiSubstitutor.EMPTY : calculateSubstitutor(method, baseMethod);
1054 if (myChangeInfo.isReturnTypeChanged) {
1055 final PsiType returnType = substitutor.substitute(myChangeInfo.newTypeElement);
1056 // don't modify return type for non-Java overriders (EJB)
1057 if (method.getName().equals(myChangeInfo.newName)) {
1058 final PsiTypeElement typeElement = method.getReturnTypeElement();
1059 if (typeElement != null) {
1060 typeElement.replace(factory.createTypeElement(returnType));
1065 PsiParameterList list = method.getParameterList();
1066 PsiParameter[] parameters = list.getParameters();
1068 PsiParameter[] newParms = new PsiParameter[myChangeInfo.newParms.length];
1069 for (int i = 0; i < newParms.length; i++) {
1070 ParameterInfoImpl info = myChangeInfo.newParms[i];
1071 int index = info.oldParameterIndex;
1072 if (index >= 0) {
1073 PsiParameter parameter = parameters[index];
1074 newParms[i] = parameter;
1076 String oldName = myChangeInfo.oldParameterNames[index];
1077 if (!oldName.equals(info.getName()) && oldName.equals(parameter.getName())) {
1078 PsiIdentifier newIdentifier = factory.createIdentifier(info.getName());
1079 parameter.getNameIdentifier().replace(newIdentifier);
1082 String oldType = myChangeInfo.oldParameterTypes[index];
1083 if (!oldType.equals(info.getTypeText())) {
1084 parameter.normalizeDeclaration();
1085 PsiType newType = substitutor.substitute(info.createType(myChangeInfo.getMethod().getParameterList(), myManager));
1087 parameter.getTypeElement().replace(factory.createTypeElement(newType));
1089 } else {
1090 newParms[i] = createNewParameter(info, substitutor);
1094 resolveParameterVsFieldsConflicts(newParms, method, list, myChangeInfo.toRemoveParm);
1095 fixJavadocsForChangedMethod(method);
1096 if (myChangeInfo.isExceptionSetOrOrderChanged) {
1097 final PsiClassType[] newExceptions = getPrimaryChangedExceptionInfo(myChangeInfo);
1098 fixPrimaryThrowsLists(method, newExceptions);
1102 private static void resolveParameterVsFieldsConflicts(final PsiParameter[] newParms,
1103 final PsiMethod method,
1104 final PsiParameterList list,
1105 boolean[] toRemoveParm) throws IncorrectOperationException {
1106 List<FieldConflictsResolver> conflictResolvers = new ArrayList<FieldConflictsResolver>();
1107 for (PsiParameter parameter : newParms) {
1108 conflictResolvers.add(new FieldConflictsResolver(parameter.getName(), method.getBody()));
1110 ChangeSignatureUtil.synchronizeList(list, Arrays.asList(newParms), ParameterList.INSTANCE, toRemoveParm);
1111 JavaCodeStyleManager.getInstance(list.getProject()).shortenClassReferences(list);
1112 for (FieldConflictsResolver fieldConflictsResolver : conflictResolvers) {
1113 fieldConflictsResolver.fix();
1117 private static PsiSubstitutor calculateSubstitutor(PsiMethod derivedMethod, PsiMethod baseMethod) {
1118 PsiSubstitutor substitutor;
1119 if (derivedMethod.getManager().areElementsEquivalent(derivedMethod, baseMethod)) {
1120 substitutor = PsiSubstitutor.EMPTY;
1121 } else {
1122 final PsiClass baseClass = baseMethod.getContainingClass();
1123 final PsiClass derivedClass = derivedMethod.getContainingClass();
1124 if(baseClass != null && derivedClass != null && InheritanceUtil.isInheritorOrSelf(derivedClass, baseClass, true)) {
1125 final PsiSubstitutor superClassSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(baseClass, derivedClass, PsiSubstitutor.EMPTY);
1126 final MethodSignature superMethodSignature = baseMethod.getSignature(superClassSubstitutor);
1127 final MethodSignature methodSignature = derivedMethod.getSignature(PsiSubstitutor.EMPTY);
1128 final PsiSubstitutor superMethodSubstitutor = MethodSignatureUtil.getSuperMethodSignatureSubstitutor(methodSignature, superMethodSignature);
1129 substitutor = superMethodSubstitutor != null ? superMethodSubstitutor : superClassSubstitutor;
1130 } else {
1131 substitutor = PsiSubstitutor.EMPTY;
1134 return substitutor;
1137 private static void processParameterUsage(PsiReferenceExpression ref, String oldName, String newName)
1138 throws IncorrectOperationException {
1140 PsiElement last = ref.getReferenceNameElement();
1141 if (last instanceof PsiIdentifier && last.getText().equals(oldName)) {
1142 PsiElementFactory factory = JavaPsiFacade.getInstance(ref.getProject()).getElementFactory();
1143 PsiIdentifier newNameIdentifier = factory.createIdentifier(newName);
1144 last.replace(newNameIdentifier);
1148 private static class MyParameterUsageInfo extends UsageInfo {
1149 final String oldParameterName;
1150 final String newParameterName;
1152 public MyParameterUsageInfo(PsiElement element, String oldParameterName, String newParameterName) {
1153 super(element);
1154 this.oldParameterName = oldParameterName;
1155 this.newParameterName = newParameterName;
1159 private static class RenamedParameterCollidesWithLocalUsageInfo extends UnresolvableCollisionUsageInfo {
1160 private final PsiElement myCollidingElement;
1161 private final PsiMethod myMethod;
1163 public RenamedParameterCollidesWithLocalUsageInfo(PsiParameter parameter, PsiElement collidingElement, PsiMethod method) {
1164 super(parameter, collidingElement);
1165 myCollidingElement = collidingElement;
1166 myMethod = method;
1169 public String getDescription() {
1170 return RefactoringBundle.message("there.is.already.a.0.in.the.1.it.will.conflict.with.the.renamed.parameter",
1171 RefactoringUIUtil.getDescription(myCollidingElement, true),
1172 RefactoringUIUtil.getDescription(myMethod, true));
1176 private void fixJavadocsForChangedMethod(PsiMethod method) throws IncorrectOperationException {
1177 final PsiParameter[] parameters = method.getParameterList().getParameters();
1178 final ParameterInfoImpl[] newParms = myChangeInfo.newParms;
1179 LOG.assertTrue(parameters.length == newParms.length);
1180 final Set<PsiParameter> newParameters = new HashSet<PsiParameter>();
1181 for (int i = 0; i < newParms.length; i++) {
1182 ParameterInfoImpl newParm = newParms[i];
1183 if (newParm.oldParameterIndex < 0 ||
1184 !newParm.getName().equals(myChangeInfo.oldParameterNames[newParm.oldParameterIndex])) {
1185 newParameters.add(parameters[i]);
1188 RefactoringUtil.fixJavadocsForParams(method, newParameters);
1191 private static class ExpressionList implements ChangeSignatureUtil.ChildrenGenerator<PsiExpressionList, PsiExpression> {
1192 public static final ExpressionList INSTANCE = new ExpressionList();
1193 public List<PsiExpression> getChildren(PsiExpressionList psiExpressionList) {
1194 return Arrays.asList(psiExpressionList.getExpressions());
1198 private static class ParameterList implements ChangeSignatureUtil.ChildrenGenerator<PsiParameterList, PsiParameter> {
1199 public static final ParameterList INSTANCE = new ParameterList();
1200 public List<PsiParameter> getChildren(PsiParameterList psiParameterList) {
1201 return Arrays.asList(psiParameterList.getParameters());
1205 private static class ThrowsList implements ChangeSignatureUtil.ChildrenGenerator<PsiReferenceList, PsiJavaCodeReferenceElement> {
1206 public static final ThrowsList INSTANCE = new ThrowsList();
1207 public List<PsiJavaCodeReferenceElement> getChildren(PsiReferenceList throwsList) {
1208 return Arrays.asList(throwsList.getReferenceElements());