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.
18 * created at Sep 17, 2001
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.Comparing;
30 import com.intellij.openapi.util.Ref;
31 import com.intellij.psi.*;
32 import com.intellij.psi.codeStyle.CodeStyleManager;
33 import com.intellij.psi.codeStyle.JavaCodeStyleManager;
34 import com.intellij.psi.codeStyle.VariableKind;
35 import com.intellij.psi.javadoc.PsiDocTagValue;
36 import com.intellij.psi.scope.processor.VariablesProcessor;
37 import com.intellij.psi.scope.util.PsiScopesUtil;
38 import com.intellij.psi.search.GlobalSearchScope;
39 import com.intellij.psi.search.searches.MethodReferencesSearch;
40 import com.intellij.psi.search.searches.OverridingMethodsSearch;
41 import com.intellij.psi.search.searches.ReferencesSearch;
42 import com.intellij.psi.util.*;
43 import com.intellij.psi.xml.XmlElement;
44 import com.intellij.refactoring.BaseRefactoringProcessor;
45 import com.intellij.refactoring.RefactoringBundle;
46 import com.intellij.refactoring.rename.JavaUnresolvableLocalCollisionDetector;
47 import com.intellij.refactoring.rename.RenameUtil;
48 import com.intellij.refactoring.rename.UnresolvableCollisionUsageInfo;
49 import com.intellij.refactoring.ui.ConflictsDialog;
50 import com.intellij.refactoring.util.*;
51 import com.intellij.refactoring.util.usageInfo.DefaultConstructorImplicitUsageInfo;
52 import com.intellij.refactoring.util.usageInfo.NoConstructorClassUsageInfo;
53 import com.intellij.usageView.UsageInfo;
54 import com.intellij.usageView.UsageViewDescriptor;
55 import com.intellij.usageView.UsageViewUtil;
56 import com.intellij.util.IncorrectOperationException;
57 import com.intellij.util.VisibilityUtil;
58 import com.intellij.util.containers.HashSet;
59 import com.intellij.util.containers.MultiMap;
60 import org.jetbrains.annotations.NotNull;
61 import org.jetbrains.annotations.Nullable;
65 public class ChangeSignatureProcessor extends BaseRefactoringProcessor {
66 private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.changeSignature.ChangeSignatureProcessor");
68 @Modifier private final String myNewVisibility;
69 private final ChangeInfoImpl myChangeInfo;
70 private final PsiManager myManager;
71 private final PsiElementFactory myFactory;
72 private final boolean myGenerateDelegate;
73 private final Set<PsiMethod> myPropagateParametersMethods;
74 private final Set<PsiMethod> myPropagateExceptionsMethods;
76 public ChangeSignatureProcessor(Project project,
78 final boolean generateDelegate,
79 @Modifier String newVisibility,
82 @NotNull ParameterInfoImpl[] parameterInfo) {
83 this(project, method, generateDelegate, newVisibility, newName,
84 newType != null ? CanonicalTypes.createTypeWrapper(newType) : null,
85 parameterInfo, null, null, null);
88 public ChangeSignatureProcessor(Project project,
90 final boolean generateDelegate,
94 ParameterInfoImpl[] parameterInfo,
95 ThrownExceptionInfo[] exceptionInfos) {
96 this(project, method, generateDelegate, newVisibility, newName,
97 newType != null ? CanonicalTypes.createTypeWrapper(newType) : null,
98 parameterInfo, exceptionInfos, null, null);
101 public ChangeSignatureProcessor(Project project,
103 boolean generateDelegate,
104 String newVisibility,
106 CanonicalTypes.Type newType,
107 @NotNull ParameterInfoImpl[] parameterInfo,
108 ThrownExceptionInfo[] thrownExceptions,
109 Set<PsiMethod> propagateParametersMethods,
110 Set<PsiMethod> propagateExceptionsMethods) {
112 myManager = PsiManager.getInstance(project);
113 myFactory = JavaPsiFacade.getInstance(myManager.getProject()).getElementFactory();
114 myGenerateDelegate = generateDelegate;
116 myPropagateParametersMethods = propagateParametersMethods != null ? propagateParametersMethods : new HashSet<PsiMethod>();
117 myPropagateExceptionsMethods = propagateExceptionsMethods != null ? propagateExceptionsMethods : new HashSet<PsiMethod>();
119 LOG.assertTrue(method.isValid());
120 if (newVisibility == null) {
121 myNewVisibility = VisibilityUtil.getVisibilityModifier(method.getModifierList());
123 myNewVisibility = newVisibility;
126 myChangeInfo = new ChangeInfoImpl(myNewVisibility, method, newName, newType, parameterInfo, thrownExceptions);
127 LOG.assertTrue(myChangeInfo.getMethod().isValid());
130 protected UsageViewDescriptor createUsageViewDescriptor(UsageInfo[] usages) {
131 return new ChangeSignatureViewDescriptor(myChangeInfo.getMethod());
135 protected UsageInfo[] findUsages() {
136 ArrayList<UsageInfo> result = new ArrayList<UsageInfo>();
137 final PsiMethod method = myChangeInfo.getMethod();
139 findSimpleUsages(method, result);
141 final UsageInfo[] usageInfos = result.toArray(new UsageInfo[result.size()]);
142 return UsageViewUtil.removeDuplicatedUsages(usageInfos);
145 private void findSimpleUsages(final PsiMethod method, final ArrayList<UsageInfo> result) {
146 PsiMethod[] overridingMethods = findSimpleUsagesWithoutParameters(method, result, true, true, true);
147 findUsagesInCallers (result);
149 //Parameter name changes are not propagated
150 findParametersUsage(method, result, overridingMethods);
153 private PsiMethod[] findSimpleUsagesWithoutParameters(final PsiMethod method,
154 final ArrayList<UsageInfo> result,
155 boolean isToModifyArgs,
156 boolean isToThrowExceptions,
157 boolean isOriginal) {
159 GlobalSearchScope projectScope = GlobalSearchScope.projectScope(myProject);
160 PsiMethod[] overridingMethods = OverridingMethodsSearch.search(method, method.getUseScope(), true).toArray(PsiMethod.EMPTY_ARRAY);
162 for (PsiMethod overridingMethod : overridingMethods) {
163 result.add(new OverriderUsageInfo(overridingMethod, method, isOriginal, isToModifyArgs, isToThrowExceptions));
166 boolean needToChangeCalls = !myGenerateDelegate && (myChangeInfo.isNameChanged || myChangeInfo.isParameterSetOrOrderChanged || myChangeInfo.isExceptionSetOrOrderChanged || myChangeInfo.isVisibilityChanged/*for checking inaccessible*/);
167 if (needToChangeCalls) {
168 int parameterCount = method.getParameterList().getParametersCount();
170 PsiReference[] refs = MethodReferencesSearch.search(method, projectScope, true).toArray(PsiReference.EMPTY_ARRAY);
171 for (PsiReference ref : refs) {
172 PsiElement element = ref.getElement();
173 boolean isToCatchExceptions = isToThrowExceptions && needToCatchExceptions(RefactoringUtil.getEnclosingMethod(element));
174 if (!isToCatchExceptions) {
175 if (RefactoringUtil.isMethodUsage(element)) {
176 PsiExpressionList list = RefactoringUtil.getArgumentListByMethodReference(element);
177 if (!method.isVarArgs() && list.getExpressions().length != parameterCount) continue;
180 if (RefactoringUtil.isMethodUsage(element)) {
181 result.add(new MethodCallUsageInfo(element, isToModifyArgs, isToCatchExceptions));
183 else if (element instanceof PsiDocTagValue) {
184 result.add(new UsageInfo(ref.getElement()));
186 else if (element instanceof PsiMethod && ((PsiMethod)element).isConstructor()) {
187 DefaultConstructorImplicitUsageInfo implicitUsageInfo = new DefaultConstructorImplicitUsageInfo((PsiMethod)element,
188 ((PsiMethod)element).getContainingClass(), method);
189 result.add(implicitUsageInfo);
191 else if(element instanceof PsiClass) {
192 LOG.assertTrue(method.isConstructor());
193 final PsiClass psiClass = (PsiClass)element;
194 if (shouldPropagateToNonPhysicalMethod(method, result, psiClass, myPropagateParametersMethods)) continue;
195 if (shouldPropagateToNonPhysicalMethod(method, result, psiClass, myPropagateExceptionsMethods)) continue;
196 result.add(new NoConstructorClassUsageInfo(psiClass));
198 else if (ref instanceof PsiCallReference) {
199 result.add(new CallReferenceUsageInfo((PsiCallReference) ref));
202 result.add(new MoveRenameUsageInfo(element, ref, method));
206 //if (method.isConstructor() && parameterCount == 0) {
207 // RefactoringUtil.visitImplicitConstructorUsages(method.getContainingClass(),
208 // new DefaultConstructorUsageCollector(result));
211 else if (myChangeInfo.isParameterTypesChanged) {
212 PsiReference[] refs = MethodReferencesSearch.search(method, projectScope, true).toArray(PsiReference.EMPTY_ARRAY);
213 for (PsiReference reference : refs) {
214 final PsiElement element = reference.getElement();
215 if (element instanceof PsiDocTagValue) {
216 result.add(new UsageInfo(reference));
218 else if (element instanceof XmlElement) {
219 result.add(new MoveRenameUsageInfo(reference, method));
225 detectLocalsCollisionsInMethod(method, result, isOriginal);
226 for (final PsiMethod overridingMethod : overridingMethods) {
227 detectLocalsCollisionsInMethod(overridingMethod, result, isOriginal);
230 return overridingMethods;
233 private static boolean shouldPropagateToNonPhysicalMethod(PsiMethod method, ArrayList<UsageInfo> result, PsiClass containingClass, final Set<PsiMethod> propagateMethods) {
234 for (PsiMethod psiMethod : propagateMethods) {
235 if (!psiMethod.isPhysical() && Comparing.strEqual(psiMethod.getName(), containingClass.getName())) {
236 result.add(new DefaultConstructorImplicitUsageInfo(psiMethod, containingClass, method));
243 private void findUsagesInCallers(final ArrayList<UsageInfo> usages) {
244 for (PsiMethod caller : myPropagateParametersMethods) {
245 usages.add(new CallerUsageInfo(caller, true, myPropagateExceptionsMethods.contains(caller)));
247 for (PsiMethod caller : myPropagateExceptionsMethods) {
248 usages.add(new CallerUsageInfo(caller, myPropagateParametersMethods.contains(caller), true));
250 Set<PsiMethod> merged = new HashSet<PsiMethod>();
251 merged.addAll(myPropagateParametersMethods);
252 merged.addAll(myPropagateExceptionsMethods);
253 for (final PsiMethod method : merged) {
254 findSimpleUsagesWithoutParameters(method, usages, myPropagateParametersMethods.contains(method),
255 myPropagateExceptionsMethods.contains(method), false);
259 private boolean needToChangeCalls() {
260 return myChangeInfo.isNameChanged || myChangeInfo.isParameterSetOrOrderChanged || myChangeInfo.isExceptionSetOrOrderChanged;
263 private boolean needToCatchExceptions(PsiMethod caller) {
264 return myChangeInfo.isExceptionSetOrOrderChanged && !myPropagateExceptionsMethods.contains(caller);
267 private void detectLocalsCollisionsInMethod(final PsiMethod method,
268 final ArrayList<UsageInfo> result,
269 boolean isOriginal) {
270 final PsiParameter[] parameters = method.getParameterList().getParameters();
271 final Set<PsiParameter> deletedOrRenamedParameters = new HashSet<PsiParameter>();
273 deletedOrRenamedParameters.addAll(Arrays.asList(parameters));
274 for (ParameterInfoImpl parameterInfo : myChangeInfo.newParms) {
275 if (parameterInfo.oldParameterIndex >= 0) {
276 final PsiParameter parameter = parameters[parameterInfo.oldParameterIndex];
277 if (parameterInfo.getName().equals(parameter.getName())) {
278 deletedOrRenamedParameters.remove(parameter);
284 for (ParameterInfoImpl parameterInfo : myChangeInfo.newParms) {
285 final int oldParameterIndex = parameterInfo.oldParameterIndex;
286 final String newName = parameterInfo.getName();
287 if (oldParameterIndex >= 0) {
288 if (isOriginal) { //Name changes take place only in primary method
289 final PsiParameter parameter = parameters[oldParameterIndex];
290 if (!newName.equals(parameter.getName())) {
291 JavaUnresolvableLocalCollisionDetector.visitLocalsCollisions(parameter, newName, method.getBody(), null, new JavaUnresolvableLocalCollisionDetector.CollidingVariableVisitor() {
292 public void visitCollidingElement(final PsiVariable collidingVariable) {
293 if (!deletedOrRenamedParameters.contains(collidingVariable)) {
294 result.add(new RenamedParameterCollidesWithLocalUsageInfo(parameter, collidingVariable, method));
302 JavaUnresolvableLocalCollisionDetector.visitLocalsCollisions(method, newName, method.getBody(), null, new JavaUnresolvableLocalCollisionDetector.CollidingVariableVisitor() {
303 public void visitCollidingElement(PsiVariable collidingVariable) {
304 if (!deletedOrRenamedParameters.contains(collidingVariable)) {
305 result.add(new NewParameterCollidesWithLocalUsageInfo(collidingVariable, collidingVariable, method));
313 private void findParametersUsage(final PsiMethod method, ArrayList<UsageInfo> result, PsiMethod[] overriders) {
314 PsiParameter[] parameters = method.getParameterList().getParameters();
315 for (ParameterInfoImpl info : myChangeInfo.newParms) {
316 if (info.oldParameterIndex >= 0) {
317 PsiParameter parameter = parameters[info.oldParameterIndex];
318 if (!info.getName().equals(parameter.getName())) {
319 addParameterUsages(parameter, result, info);
321 for (PsiMethod overrider : overriders) {
322 PsiParameter parameter1 = overrider.getParameterList().getParameters()[info.oldParameterIndex];
323 if (parameter.getName().equals(parameter1.getName())) {
324 addParameterUsages(parameter1, result, info);
332 protected void refreshElements(PsiElement[] elements) {
333 boolean condition = elements.length == 1 && elements[0] instanceof PsiMethod;
334 LOG.assertTrue(condition);
335 myChangeInfo.updateMethod((PsiMethod) elements[0]);
338 private void addMethodConflicts(MultiMap<PsiElement, String> conflicts) {
339 String newMethodName = myChangeInfo.newName;
343 PsiManager manager = PsiManager.getInstance(myProject);
344 PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory();
345 final PsiMethod method = myChangeInfo.getMethod();
346 final CanonicalTypes.Type returnType = myChangeInfo.newReturnType;
347 if (returnType != null) {
348 prototype = factory.createMethod(newMethodName, returnType.getType(method, manager));
351 prototype = factory.createConstructor();
352 prototype.setName(newMethodName);
354 ParameterInfoImpl[] parameters = myChangeInfo.newParms;
357 for (ParameterInfoImpl info : parameters) {
358 final PsiType parameterType = info.createType(method, manager);
359 PsiParameter param = factory.createParameter(info.getName(), parameterType);
360 prototype.getParameterList().add(param);
363 ConflictsUtil.checkMethodConflicts(
364 method.getContainingClass(),
366 prototype, conflicts);
368 catch (IncorrectOperationException e) {
374 protected boolean preprocessUsages(Ref<UsageInfo[]> refUsages) {
375 MultiMap<PsiElement, String> conflictDescriptions = new MultiMap<PsiElement, String>();
376 UsageInfo[] usagesIn = refUsages.get();
377 addMethodConflicts(conflictDescriptions);
378 RenameUtil.addConflictDescriptions(usagesIn, conflictDescriptions);
379 Set<UsageInfo> usagesSet = new HashSet<UsageInfo>(Arrays.asList(usagesIn));
380 RenameUtil.removeConflictUsages(usagesSet);
381 if (myChangeInfo.isVisibilityChanged) {
383 addInaccessibilityDescriptions(usagesSet, conflictDescriptions);
385 catch (IncorrectOperationException e) {
390 if (myPrepareSuccessfulSwingThreadCallback != null && !conflictDescriptions.isEmpty()) {
391 ConflictsDialog dialog = new ConflictsDialog(myProject, conflictDescriptions);
394 if (dialog.isShowConflicts()) prepareSuccessful();
399 if (myChangeInfo.isReturnTypeChanged) {
400 askToRemoveCovariantOverriders (usagesSet);
403 refUsages.set(usagesSet.toArray(new UsageInfo[usagesSet.size()]));
408 private void addInaccessibilityDescriptions(Set<UsageInfo> usages, MultiMap<PsiElement, String> conflictDescriptions) throws IncorrectOperationException {
409 PsiMethod method = myChangeInfo.getMethod();
410 PsiModifierList modifierList = (PsiModifierList)method.getModifierList().copy();
411 VisibilityUtil.setVisibility(modifierList, myNewVisibility);
413 for (Iterator<UsageInfo> iterator = usages.iterator(); iterator.hasNext();) {
414 UsageInfo usageInfo = iterator.next();
415 PsiElement element = usageInfo.getElement();
416 if (element != null) {
417 if (element instanceof PsiReferenceExpression) {
418 PsiClass accessObjectClass = null;
419 PsiExpression qualifier = ((PsiReferenceExpression)element).getQualifierExpression();
420 if (qualifier != null) {
421 accessObjectClass = (PsiClass)PsiUtil.getAccessObjectClass(qualifier).getElement();
424 if (!JavaPsiFacade.getInstance(element.getProject()).getResolveHelper()
425 .isAccessible(method, modifierList, element, accessObjectClass, null)) {
427 RefactoringBundle.message("0.with.1.visibility.is.not.accesible.from.2",
428 RefactoringUIUtil.getDescription(method, true),
430 RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(element), true));
431 conflictDescriptions.putValue(method, message);
432 if (!needToChangeCalls()) {
441 private void askToRemoveCovariantOverriders(Set<UsageInfo> usages) {
442 if (PsiUtil.isLanguageLevel5OrHigher(myChangeInfo.getMethod())) {
443 List<UsageInfo> covariantOverriderInfos = new ArrayList<UsageInfo>();
444 for (UsageInfo usageInfo : usages) {
445 if (usageInfo instanceof OverriderUsageInfo) {
446 final OverriderUsageInfo info = (OverriderUsageInfo)usageInfo;
447 PsiMethod overrider = info.getElement();
448 PsiMethod baseMethod = info.getBaseMethod();
449 PsiSubstitutor substitutor = calculateSubstitutor(overrider, baseMethod);
452 type = substitutor.substitute(myChangeInfo.newReturnType.getType(myChangeInfo.getMethod(), myManager));
454 catch (IncorrectOperationException e) {
458 final PsiType overriderType = overrider.getReturnType();
459 if (overriderType != null && type.isAssignableFrom(overriderType)) {
460 covariantOverriderInfos.add(usageInfo);
465 // to be able to do filtering
466 preprocessCovariantOverriders(covariantOverriderInfos);
468 if (!covariantOverriderInfos.isEmpty()) {
469 if (ApplicationManager.getApplication().isUnitTestMode() || !isProcessCovariantOverriders()) {
470 for (UsageInfo usageInfo : covariantOverriderInfos) {
471 usages.remove(usageInfo);
478 protected void preprocessCovariantOverriders(final List<UsageInfo> covariantOverriderInfos) {
481 protected boolean isProcessCovariantOverriders() {
482 return Messages.showYesNoDialog(myProject, RefactoringBundle.message("do.you.want.to.process.overriding.methods.with.covariant.return.type"),
483 JavaChangeSignatureHandler.REFACTORING_NAME, Messages.getQuestionIcon())
484 == DialogWrapper.OK_EXIT_CODE;
487 protected void performRefactoring(UsageInfo[] usages) {
488 PsiElementFactory factory = JavaPsiFacade.getInstance(myManager.getProject()).getElementFactory();
491 if (myChangeInfo.isNameChanged) {
492 myChangeInfo.newNameIdentifier = factory.createIdentifier(myChangeInfo.newName);
495 if (myChangeInfo.isReturnTypeChanged) {
496 myChangeInfo.newTypeElement = myChangeInfo.newReturnType.getType(myChangeInfo.getMethod(), myManager);
499 if (myGenerateDelegate) {
503 for (UsageInfo usage : usages) {
504 if (usage instanceof CallerUsageInfo) {
505 final CallerUsageInfo callerUsageInfo = (CallerUsageInfo)usage;
506 processCallerMethod(callerUsageInfo.getMethod(), null, callerUsageInfo.isToInsertParameter(),
507 callerUsageInfo.isToInsertException());
509 else if (usage instanceof OverriderUsageInfo) {
510 OverriderUsageInfo info = (OverriderUsageInfo)usage;
511 final PsiMethod method = info.getElement();
512 final PsiMethod baseMethod = info.getBaseMethod();
513 if (info.isOriginalOverrider()) {
514 processPrimaryMethod(method, baseMethod, false);
517 processCallerMethod(method, baseMethod, info.isToInsertArgs(), info.isToCatchExceptions());
522 LOG.assertTrue(myChangeInfo.getMethod().isValid());
523 processPrimaryMethod(myChangeInfo.getMethod(), null, true);
524 List<UsageInfo> postponedUsages = new ArrayList<UsageInfo>();
526 for (UsageInfo usage : usages) {
527 PsiElement element = usage.getElement();
528 if (element == null) continue;
530 if (usage instanceof DefaultConstructorImplicitUsageInfo) {
531 final DefaultConstructorImplicitUsageInfo defConstructorUsage = (DefaultConstructorImplicitUsageInfo)usage;
532 PsiMethod constructor = defConstructorUsage.getConstructor();
533 if (!constructor.isPhysical()) {
534 final boolean toPropagate = myPropagateParametersMethods.remove(constructor);
535 final PsiClass containingClass = defConstructorUsage.getContainingClass();
536 constructor = (PsiMethod)containingClass.add(constructor);
537 PsiUtil.setModifierProperty(constructor, VisibilityUtil.getVisibilityModifier(containingClass.getModifierList()), true);
539 myPropagateParametersMethods.add(constructor);
542 addSuperCall(constructor, defConstructorUsage.getBaseConstructor(),usages);
544 else if (usage instanceof NoConstructorClassUsageInfo) {
545 addDefaultConstructor(((NoConstructorClassUsageInfo)usage).getPsiClass(),usages);
547 else if (element instanceof PsiJavaCodeReferenceElement) {
548 if (usage instanceof MethodCallUsageInfo) {
549 final MethodCallUsageInfo methodCallInfo = (MethodCallUsageInfo)usage;
550 processMethodUsage(methodCallInfo.getElement(), myChangeInfo, methodCallInfo.isToChangeArguments(),
551 methodCallInfo.isToCatchExceptions(), methodCallInfo.getReferencedMethod(), usages);
553 else if (usage instanceof MyParameterUsageInfo) {
554 String newName = ((MyParameterUsageInfo)usage).newParameterName;
555 String oldName = ((MyParameterUsageInfo)usage).oldParameterName;
556 processParameterUsage((PsiReferenceExpression)element, oldName, newName);
558 postponedUsages.add(usage);
561 else if (usage instanceof CallReferenceUsageInfo) {
562 ((CallReferenceUsageInfo) usage).getReference().handleChangeSignature(myChangeInfo);
564 else if (element instanceof PsiEnumConstant) {
565 fixActualArgumentsList(((PsiEnumConstant)element).getArgumentList(), myChangeInfo, true);
567 else if (!(usage instanceof OverriderUsageInfo)) {
568 postponedUsages.add(usage);
572 for (UsageInfo usageInfo : postponedUsages) {
573 PsiElement element = usageInfo.getElement();
574 if (element == null) continue;
575 PsiReference reference = usageInfo instanceof MoveRenameUsageInfo ?
576 usageInfo.getReference() :
577 element.getReference();
578 if (reference != null) {
579 PsiElement target = null;
580 if (usageInfo instanceof MyParameterUsageInfo) {
581 String newParameterName = ((MyParameterUsageInfo)usageInfo).newParameterName;
582 PsiParameter[] newParams = myChangeInfo.getMethod().getParameterList().getParameters();
583 for (PsiParameter newParam : newParams) {
584 if (newParam.getName().equals(newParameterName)) {
591 target = myChangeInfo.getMethod();
593 if (target != null) {
594 reference.bindToElement(target);
599 LOG.assertTrue(myChangeInfo.getMethod().isValid());
600 } catch (IncorrectOperationException e) {
605 private void generateDelegate() throws IncorrectOperationException {
606 final PsiMethod delegate = (PsiMethod)myChangeInfo.getMethod().copy();
607 final PsiClass targetClass = myChangeInfo.getMethod().getContainingClass();
608 LOG.assertTrue(!targetClass.isInterface());
609 makeEmptyBody(myFactory, delegate);
610 final PsiCallExpression callExpression = addDelegatingCallTemplate(delegate, myChangeInfo.newName);
611 addDelegateArguments(callExpression);
612 targetClass.addBefore(delegate, myChangeInfo.getMethod());
615 private void addDelegateArguments(final PsiCallExpression callExpression) throws IncorrectOperationException {
616 final ParameterInfoImpl[] newParms = myChangeInfo.newParms;
617 for (int i = 0; i < newParms.length; i++) {
618 ParameterInfoImpl newParm = newParms[i];
619 final PsiExpression actualArg;
620 if (newParm.oldParameterIndex >= 0) {
621 actualArg = myFactory.createExpressionFromText(myChangeInfo.oldParameterNames[newParm.oldParameterIndex], callExpression);
624 actualArg = myChangeInfo.getValue(i, callExpression);
626 callExpression.getArgumentList().add(actualArg);
630 public static void makeEmptyBody(final PsiElementFactory factory, final PsiMethod delegate) throws IncorrectOperationException {
631 PsiCodeBlock body = delegate.getBody();
633 body.replace(factory.createCodeBlock());
636 delegate.add(factory.createCodeBlock());
638 PsiUtil.setModifierProperty(delegate, PsiModifier.ABSTRACT, false);
641 public static PsiCallExpression addDelegatingCallTemplate(final PsiMethod delegate, final String newName) throws IncorrectOperationException {
642 Project project = delegate.getProject();
643 PsiElementFactory factory = JavaPsiFacade.getInstance(project).getElementFactory();
644 PsiCodeBlock body = delegate.getBody();
646 final PsiCallExpression callExpression;
647 if (delegate.isConstructor()) {
648 PsiElement callStatement = factory.createStatementFromText("this();", null);
649 callStatement = CodeStyleManager.getInstance(project).reformat(callStatement);
650 callStatement = body.add(callStatement);
651 callExpression = (PsiCallExpression)((PsiExpressionStatement) callStatement).getExpression();
653 if (PsiType.VOID.equals(delegate.getReturnType())) {
654 PsiElement callStatement = factory.createStatementFromText(newName + "();", null);
655 callStatement = CodeStyleManager.getInstance(project).reformat(callStatement);
656 callStatement = body.add(callStatement);
657 callExpression = (PsiCallExpression)((PsiExpressionStatement) callStatement).getExpression();
660 PsiElement callStatement = factory.createStatementFromText("return " + newName + "();", null);
661 callStatement = CodeStyleManager.getInstance(project).reformat(callStatement);
662 callStatement = body.add(callStatement);
663 callExpression = (PsiCallExpression)((PsiReturnStatement) callStatement).getReturnValue();
666 return callExpression;
669 private void addDefaultConstructor(PsiClass aClass, final UsageInfo[] usages) throws IncorrectOperationException {
670 if (!(aClass instanceof PsiAnonymousClass)) {
671 PsiMethod defaultConstructor = myFactory.createMethodFromText(aClass.getName() + "(){}", aClass);
672 defaultConstructor = (PsiMethod) CodeStyleManager.getInstance(myProject).reformat(defaultConstructor);
673 defaultConstructor = (PsiMethod) aClass.add(defaultConstructor);
674 PsiUtil.setModifierProperty(defaultConstructor, VisibilityUtil.getVisibilityModifier(aClass.getModifierList()), true);
675 addSuperCall(defaultConstructor, null, usages);
677 final PsiElement parent = aClass.getParent();
678 if (parent instanceof PsiNewExpression) {
679 final PsiExpressionList argumentList = ((PsiNewExpression) parent).getArgumentList();
680 fixActualArgumentsList(argumentList, myChangeInfo, true);
685 private void addSuperCall(PsiMethod constructor, PsiMethod callee, final UsageInfo[] usages) throws IncorrectOperationException {
686 PsiExpressionStatement superCall = (PsiExpressionStatement) myFactory.createStatementFromText("super();", constructor);
687 PsiCodeBlock body = constructor.getBody();
689 PsiStatement[] statements = body.getStatements();
690 if (statements.length > 0) {
691 superCall = (PsiExpressionStatement) body.addBefore(superCall, statements[0]);
693 superCall = (PsiExpressionStatement) body.add(superCall);
695 PsiMethodCallExpression callExpression = (PsiMethodCallExpression) superCall.getExpression();
696 processMethodUsage(callExpression.getMethodExpression(), myChangeInfo, true, false, callee, usages);
699 private PsiParameter createNewParameter(ParameterInfoImpl newParm,
700 PsiSubstitutor substitutor) throws IncorrectOperationException {
701 final PsiElementFactory factory = JavaPsiFacade.getInstance(myProject).getElementFactory();
702 final PsiType type = substitutor.substitute(newParm.createType(myChangeInfo.getMethod().getParameterList(), myManager));
703 return factory.createParameter(newParm.getName(), type);
706 protected String getCommandName() {
707 return RefactoringBundle.message("changing.signature.of.0", UsageViewUtil.getDescriptiveName(myChangeInfo.getMethod()));
710 private void processMethodUsage(PsiElement ref,
711 ChangeInfoImpl changeInfo,
712 boolean toChangeArguments,
713 boolean toCatchExceptions,
714 PsiMethod callee, final UsageInfo[] usages) throws IncorrectOperationException {
715 if (changeInfo.isNameChanged) {
716 if (ref instanceof PsiJavaCodeReferenceElement) {
717 PsiElement last = ((PsiJavaCodeReferenceElement)ref).getReferenceNameElement();
718 if (last instanceof PsiIdentifier && last.getText().equals(changeInfo.oldName)) {
719 last.replace(changeInfo.newNameIdentifier);
724 final PsiMethod caller = RefactoringUtil.getEnclosingMethod(ref);
725 if (toChangeArguments) {
726 final PsiExpressionList list = RefactoringUtil.getArgumentListByMethodReference(ref);
727 boolean toInsertDefaultValue = !myPropagateParametersMethods.contains(caller);
728 if (toInsertDefaultValue && ref instanceof PsiReferenceExpression) {
729 final PsiExpression qualifierExpression = ((PsiReferenceExpression) ref).getQualifierExpression();
730 if (qualifierExpression instanceof PsiSuperExpression && callerSignatureIsAboutToChangeToo(caller, usages)) {
731 toInsertDefaultValue = false;
735 fixActualArgumentsList(list, changeInfo, toInsertDefaultValue);
738 if (toCatchExceptions) {
739 if (!(ref instanceof PsiReferenceExpression && ((PsiReferenceExpression)ref).getQualifierExpression() instanceof PsiSuperExpression)) {
740 if (needToCatchExceptions(caller)) {
741 PsiClassType[] newExceptions = callee != null ? getCalleeChangedExceptionInfo(callee) : getPrimaryChangedExceptionInfo(changeInfo);
742 fixExceptions(ref, newExceptions);
748 private static boolean callerSignatureIsAboutToChangeToo(final PsiMethod caller, final UsageInfo[] usages) {
749 for (UsageInfo usage : usages) {
750 if (usage instanceof MethodCallUsageInfo && MethodSignatureUtil.isSuperMethod(((MethodCallUsageInfo)usage).getReferencedMethod(), caller)) return true;
755 private static PsiClassType[] getCalleeChangedExceptionInfo(final PsiMethod callee) {
756 return callee.getThrowsList().getReferencedTypes(); //Callee method's throws list is already modified!
759 private PsiClassType[] getPrimaryChangedExceptionInfo(ChangeInfoImpl changeInfo) throws IncorrectOperationException {
760 PsiClassType[] newExceptions = new PsiClassType[changeInfo.newExceptions.length];
761 for (int i = 0; i < newExceptions.length; i++) {
762 newExceptions[i] = (PsiClassType)changeInfo.newExceptions[i].myType.getType(myChangeInfo.getMethod(), myManager); //context really does not matter here
764 return newExceptions;
767 private void fixExceptions(PsiElement ref, PsiClassType[] newExceptions) throws IncorrectOperationException {
768 //methods' throws lists are already modified, may use ExceptionUtil.collectUnhandledExceptions
769 newExceptions = filterCheckedExceptions(newExceptions);
771 PsiElement context = PsiTreeUtil.getParentOfType(ref, PsiTryStatement.class, PsiMethod.class);
772 if (context instanceof PsiTryStatement) {
773 PsiTryStatement tryStatement = (PsiTryStatement)context;
774 PsiCodeBlock tryBlock = tryStatement.getTryBlock();
776 //Remove unused catches
777 Collection<PsiClassType> classes = ExceptionUtil.collectUnhandledExceptions(tryBlock, tryBlock);
778 PsiParameter[] catchParameters = tryStatement.getCatchBlockParameters();
779 for (PsiParameter parameter : catchParameters) {
780 final PsiType caughtType = parameter.getType();
782 if (!(caughtType instanceof PsiClassType)) continue;
783 if (ExceptionUtil.isUncheckedExceptionOrSuperclass((PsiClassType)caughtType)) continue;
785 if (!isCatchParameterRedundant((PsiClassType)caughtType, classes)) continue;
786 parameter.getParent().delete(); //delete catch section
789 PsiClassType[] exceptionsToAdd = filterUnhandledExceptions(newExceptions, tryBlock);
790 addExceptions(exceptionsToAdd, tryStatement);
792 adjustPossibleEmptyTryStatement(tryStatement);
795 newExceptions = filterUnhandledExceptions(newExceptions, ref);
796 if (newExceptions.length > 0) {
797 //Add new try statement
798 PsiElementFactory elementFactory = JavaPsiFacade.getInstance(myManager.getProject()).getElementFactory();
799 PsiTryStatement tryStatement = (PsiTryStatement)elementFactory.createStatementFromText("try {} catch (Exception e) {}", null);
800 PsiStatement anchor = PsiTreeUtil.getParentOfType(ref, PsiStatement.class);
801 LOG.assertTrue(anchor != null);
802 tryStatement.getTryBlock().add(anchor);
803 tryStatement = (PsiTryStatement)anchor.getParent().addAfter(tryStatement, anchor);
805 addExceptions(newExceptions, tryStatement);
807 tryStatement.getCatchSections()[0].delete(); //Delete dummy catch section
812 private static PsiClassType[] filterCheckedExceptions(PsiClassType[] exceptions) {
813 List<PsiClassType> result = new ArrayList<PsiClassType>();
814 for (PsiClassType exceptionType : exceptions) {
815 if (!ExceptionUtil.isUncheckedException(exceptionType)) result.add(exceptionType);
817 return result.toArray(new PsiClassType[result.size()]);
820 private static void adjustPossibleEmptyTryStatement(PsiTryStatement tryStatement) throws IncorrectOperationException {
821 PsiCodeBlock tryBlock = tryStatement.getTryBlock();
822 if (tryBlock != null) {
823 if (tryStatement.getCatchSections().length == 0 &&
824 tryStatement.getFinallyBlock() == null) {
825 PsiElement firstBodyElement = tryBlock.getFirstBodyElement();
826 if (firstBodyElement != null) {
827 tryStatement.getParent().addRangeAfter(firstBodyElement, tryBlock.getLastBodyElement(), tryStatement);
829 tryStatement.delete();
834 private static void addExceptions(PsiClassType[] exceptionsToAdd, PsiTryStatement tryStatement) throws IncorrectOperationException {
835 for (PsiClassType type : exceptionsToAdd) {
836 final JavaCodeStyleManager styleManager = JavaCodeStyleManager.getInstance(tryStatement.getProject());
837 String name = styleManager.suggestVariableName(VariableKind.PARAMETER, null, null, type).names[0];
838 name = styleManager.suggestUniqueVariableName(name, tryStatement, false);
840 PsiCatchSection catchSection =
841 JavaPsiFacade.getInstance(tryStatement.getProject()).getElementFactory().createCatchSection(type, name, tryStatement);
842 tryStatement.add(catchSection);
846 private void fixPrimaryThrowsLists(PsiMethod method, PsiClassType[] newExceptions) throws IncorrectOperationException {
847 PsiElementFactory elementFactory = JavaPsiFacade.getInstance(myManager.getProject()).getElementFactory();
848 PsiJavaCodeReferenceElement[] refs = new PsiJavaCodeReferenceElement[newExceptions.length];
849 for (int i = 0; i < refs.length; i++) {
850 refs[i] = elementFactory.createReferenceElementByType(newExceptions[i]);
852 PsiReferenceList throwsList = elementFactory.createReferenceList(refs);
854 replaceThrowsList(method, throwsList);
857 private void replaceThrowsList(PsiMethod method, PsiReferenceList throwsList) throws IncorrectOperationException {
858 PsiReferenceList methodThrowsList = (PsiReferenceList)method.getThrowsList().replace(throwsList);
859 methodThrowsList = (PsiReferenceList)JavaCodeStyleManager.getInstance(myProject).shortenClassReferences(methodThrowsList);
860 myManager.getCodeStyleManager().reformatRange(method, method.getParameterList().getTextRange().getEndOffset(),
861 methodThrowsList.getTextRange().getEndOffset());
864 private static PsiClassType[] filterUnhandledExceptions(PsiClassType[] exceptions, PsiElement place) {
865 List<PsiClassType> result = new ArrayList<PsiClassType>();
866 for (PsiClassType exception : exceptions) {
867 if (!ExceptionUtil.isHandled(exception, place)) result.add(exception);
869 return result.toArray(new PsiClassType[result.size()]);
872 private static boolean isCatchParameterRedundant (PsiClassType catchParamType, Collection<PsiClassType> thrownTypes) {
873 for (PsiType exceptionType : thrownTypes) {
874 if (exceptionType.isConvertibleFrom(catchParamType)) return false;
879 private static int getNonVarargCount(ChangeInfoImpl changeInfo, PsiExpression[] args) {
880 if (!changeInfo.wasVararg) return args.length;
881 return changeInfo.oldParameterTypes.length - 1;
884 //This methods works equally well for primary usages as well as for propagated callers' usages
885 private void fixActualArgumentsList(PsiExpressionList list,
886 ChangeInfoImpl changeInfo,
887 boolean toInsertDefaultValue) throws IncorrectOperationException {
888 final PsiElementFactory factory = JavaPsiFacade.getInstance(list.getProject()).getElementFactory();
889 if (changeInfo.isParameterSetOrOrderChanged) {
890 if (changeInfo.isPropagationEnabled) {
891 final ParameterInfoImpl[] createdParmsInfo = changeInfo.getCreatedParmsInfoWithoutVarargs();
892 for (ParameterInfoImpl info : createdParmsInfo) {
893 PsiExpression newArg;
894 if (toInsertDefaultValue) {
895 newArg = createDefaultValue(factory, info, list);
898 newArg = factory.createExpressionFromText(info.getName(), list);
904 final PsiExpression[] args = list.getExpressions();
905 final int nonVarargCount = getNonVarargCount(changeInfo, args);
906 final int varargCount = args.length - nonVarargCount;
907 PsiExpression[] newVarargInitializers = null;
909 final int newArgsLength;
910 final int newNonVarargCount;
911 if (changeInfo.arrayToVarargs) {
912 newNonVarargCount = changeInfo.newParms.length - 1;
913 final ParameterInfoImpl lastNewParm = changeInfo.newParms[changeInfo.newParms.length - 1];
914 final PsiExpression arrayToConvert = args[lastNewParm.oldParameterIndex];
915 if (arrayToConvert instanceof PsiNewExpression) {
916 final PsiNewExpression expression = (PsiNewExpression)arrayToConvert;
917 final PsiArrayInitializerExpression arrayInitializer = expression.getArrayInitializer();
918 if (arrayInitializer != null) {
919 newVarargInitializers = arrayInitializer.getInitializers();
922 newArgsLength = newVarargInitializers == null ? changeInfo.newParms.length : newNonVarargCount + newVarargInitializers.length;
924 else if (changeInfo.retainsVarargs) {
925 newNonVarargCount = changeInfo.newParms.length - 1;
926 newArgsLength = newNonVarargCount + varargCount;
928 else if (changeInfo.obtainsVarags) {
929 newNonVarargCount = changeInfo.newParms.length - 1;
930 newArgsLength = newNonVarargCount;
933 newNonVarargCount = changeInfo.newParms.length;
934 newArgsLength = changeInfo.newParms.length;
936 final PsiExpression[] newArgs = new PsiExpression[newArgsLength];
937 for (int i = 0; i < newNonVarargCount; i++) {
938 newArgs [i] = createActualArgument(list, changeInfo.newParms [i], toInsertDefaultValue, args);
940 if (changeInfo.arrayToVarargs) {
941 if (newVarargInitializers == null) {
942 newArgs [newNonVarargCount] = createActualArgument(list, changeInfo.newParms [newNonVarargCount], toInsertDefaultValue, args);
945 System.arraycopy(newVarargInitializers, 0, newArgs, newNonVarargCount, newVarargInitializers.length);
949 final int newVarargCount = newArgsLength - newNonVarargCount;
950 LOG.assertTrue(newVarargCount == 0 || newVarargCount == varargCount);
951 System.arraycopy(args, nonVarargCount, newArgs, newNonVarargCount, newVarargCount);
953 ChangeSignatureUtil.synchronizeList(list, Arrays.asList(newArgs), ExpressionList.INSTANCE, changeInfo.toRemoveParm);
958 private PsiExpression createActualArgument(final PsiExpressionList list, final ParameterInfoImpl info, final boolean toInsertDefaultValue,
959 final PsiExpression[] args) throws IncorrectOperationException {
960 final PsiElementFactory factory = JavaPsiFacade.getInstance(list.getProject()).getElementFactory();
961 final int index = info.oldParameterIndex;
965 if (toInsertDefaultValue) {
966 return createDefaultValue(factory, info, list);
968 return factory.createExpressionFromText(info.getName(), list);
974 private PsiExpression createDefaultValue(final PsiElementFactory factory, final ParameterInfoImpl info, final PsiExpressionList list)
975 throws IncorrectOperationException {
976 if (info.useAnySingleVariable) {
977 final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(list.getProject()).getResolveHelper();
978 final PsiType type = info.getTypeWrapper().getType(myChangeInfo.getMethod(), myManager);
979 final VariablesProcessor processor = new VariablesProcessor(false) {
980 protected boolean check(PsiVariable var, ResolveState state) {
981 if (var instanceof PsiField && !resolveHelper.isAccessible((PsiField)var, list, null)) return false;
982 final PsiType varType = state.get(PsiSubstitutor.KEY).substitute(var.getType());
983 return type.isAssignableFrom(varType);
986 public boolean execute(PsiElement pe, ResolveState state) {
987 super.execute(pe, state);
991 PsiScopesUtil.treeWalkUp(processor, list, null);
992 if (processor.size() == 1) {
993 final PsiVariable result = processor.getResult(0);
994 return factory.createExpressionFromText(result.getName(), list);
997 final PsiCallExpression callExpression = PsiTreeUtil.getParentOfType(list, PsiCallExpression.class);
998 return callExpression != null ? info.getValue(callExpression) : factory.createExpressionFromText(info.defaultValue, list);
1001 private static void addParameterUsages(PsiParameter parameter,
1002 ArrayList<UsageInfo> results,
1003 ParameterInfoImpl info) {
1004 PsiManager manager = parameter.getManager();
1005 GlobalSearchScope projectScope = GlobalSearchScope.projectScope(manager.getProject());
1006 for (PsiReference psiReference : ReferencesSearch.search(parameter, projectScope, false)) {
1007 PsiElement parmRef = psiReference.getElement();
1008 UsageInfo usageInfo = new MyParameterUsageInfo(parmRef, parameter.getName(), info.getName());
1009 results.add(usageInfo);
1013 private void processCallerMethod(PsiMethod caller,
1014 PsiMethod baseMethod,
1015 boolean toInsertParams,
1016 boolean toInsertThrows) throws IncorrectOperationException {
1017 LOG.assertTrue(toInsertParams || toInsertThrows);
1018 if (toInsertParams) {
1019 List<PsiParameter> newParameters = new ArrayList<PsiParameter>();
1020 newParameters.addAll(Arrays.asList(caller.getParameterList().getParameters()));
1021 final ParameterInfoImpl[] primaryNewParms = myChangeInfo.newParms;
1022 PsiSubstitutor substitutor = baseMethod == null ? PsiSubstitutor.EMPTY : calculateSubstitutor(caller, baseMethod);
1023 for (ParameterInfoImpl info : primaryNewParms) {
1024 if (info.oldParameterIndex < 0) newParameters.add(createNewParameter(info, substitutor));
1026 PsiParameter[] arrayed = newParameters.toArray(new PsiParameter[newParameters.size()]);
1027 boolean[] toRemoveParm = new boolean[arrayed.length];
1028 Arrays.fill(toRemoveParm, false);
1029 resolveParameterVsFieldsConflicts(arrayed, caller, caller.getParameterList(), toRemoveParm);
1032 if (toInsertThrows) {
1033 List<PsiJavaCodeReferenceElement> newThrowns = new ArrayList<PsiJavaCodeReferenceElement>();
1034 final PsiReferenceList throwsList = caller.getThrowsList();
1035 newThrowns.addAll(Arrays.asList(throwsList.getReferenceElements()));
1036 final ThrownExceptionInfo[] primaryNewExns = myChangeInfo.newExceptions;
1037 for (ThrownExceptionInfo thrownExceptionInfo : primaryNewExns) {
1038 if (thrownExceptionInfo.oldIndex < 0) {
1039 final PsiClassType type = (PsiClassType)thrownExceptionInfo.createType(caller, myManager);
1040 final PsiJavaCodeReferenceElement ref =
1041 JavaPsiFacade.getInstance(caller.getProject()).getElementFactory().createReferenceElementByType(type);
1042 newThrowns.add(ref);
1045 PsiJavaCodeReferenceElement[] arrayed = newThrowns.toArray(new PsiJavaCodeReferenceElement[newThrowns.size()]);
1046 boolean[] toRemoveParm = new boolean[arrayed.length];
1047 Arrays.fill(toRemoveParm, false);
1048 ChangeSignatureUtil.synchronizeList(throwsList, Arrays.asList(arrayed), ThrowsList.INSTANCE, toRemoveParm);
1052 private void processPrimaryMethod(PsiMethod method,
1053 PsiMethod baseMethod,
1054 boolean isOriginal) throws IncorrectOperationException {
1055 PsiElementFactory factory = JavaPsiFacade.getInstance(method.getProject()).getElementFactory();
1057 if (myChangeInfo.isVisibilityChanged) {
1058 PsiModifierList modifierList = method.getModifierList();
1059 final String highestVisibility = isOriginal ?
1061 VisibilityUtil.getHighestVisibility(myNewVisibility, VisibilityUtil.getVisibilityModifier(modifierList));
1062 VisibilityUtil.setVisibility(modifierList, highestVisibility);
1065 if (myChangeInfo.isNameChanged) {
1066 String newName = baseMethod == null ? myChangeInfo.newName :
1067 RefactoringUtil.suggestNewOverriderName(method.getName(), baseMethod.getName(), myChangeInfo.newName);
1069 if (newName != null && !newName.equals(method.getName())) {
1070 final PsiIdentifier nameId = method.getNameIdentifier();
1071 assert nameId != null;
1072 nameId.replace(JavaPsiFacade.getInstance(myManager.getProject()).getElementFactory().createIdentifier(newName));
1076 final PsiSubstitutor substitutor = baseMethod == null ? PsiSubstitutor.EMPTY : calculateSubstitutor(method, baseMethod);
1078 if (myChangeInfo.isReturnTypeChanged) {
1079 final PsiType returnType = substitutor.substitute(myChangeInfo.newTypeElement);
1080 // don't modify return type for non-Java overriders (EJB)
1081 if (method.getName().equals(myChangeInfo.newName)) {
1082 final PsiTypeElement typeElement = method.getReturnTypeElement();
1083 if (typeElement != null) {
1084 typeElement.replace(factory.createTypeElement(returnType));
1089 PsiParameterList list = method.getParameterList();
1090 PsiParameter[] parameters = list.getParameters();
1092 PsiParameter[] newParms = new PsiParameter[myChangeInfo.newParms.length];
1093 for (int i = 0; i < newParms.length; i++) {
1094 ParameterInfoImpl info = myChangeInfo.newParms[i];
1095 int index = info.oldParameterIndex;
1097 PsiParameter parameter = parameters[index];
1098 newParms[i] = parameter;
1100 String oldName = myChangeInfo.oldParameterNames[index];
1101 if (!oldName.equals(info.getName()) && oldName.equals(parameter.getName())) {
1102 PsiIdentifier newIdentifier = factory.createIdentifier(info.getName());
1103 parameter.getNameIdentifier().replace(newIdentifier);
1106 String oldType = myChangeInfo.oldParameterTypes[index];
1107 if (!oldType.equals(info.getTypeText())) {
1108 parameter.normalizeDeclaration();
1109 PsiType newType = substitutor.substitute(info.createType(myChangeInfo.getMethod().getParameterList(), myManager));
1111 parameter.getTypeElement().replace(factory.createTypeElement(newType));
1114 newParms[i] = createNewParameter(info, substitutor);
1118 resolveParameterVsFieldsConflicts(newParms, method, list, myChangeInfo.toRemoveParm);
1119 fixJavadocsForChangedMethod(method);
1120 if (myChangeInfo.isExceptionSetOrOrderChanged) {
1121 final PsiClassType[] newExceptions = getPrimaryChangedExceptionInfo(myChangeInfo);
1122 fixPrimaryThrowsLists(method, newExceptions);
1126 private static void resolveParameterVsFieldsConflicts(final PsiParameter[] newParms,
1127 final PsiMethod method,
1128 final PsiParameterList list,
1129 boolean[] toRemoveParm) throws IncorrectOperationException {
1130 List<FieldConflictsResolver> conflictResolvers = new ArrayList<FieldConflictsResolver>();
1131 for (PsiParameter parameter : newParms) {
1132 conflictResolvers.add(new FieldConflictsResolver(parameter.getName(), method.getBody()));
1134 ChangeSignatureUtil.synchronizeList(list, Arrays.asList(newParms), ParameterList.INSTANCE, toRemoveParm);
1135 JavaCodeStyleManager.getInstance(list.getProject()).shortenClassReferences(list);
1136 for (FieldConflictsResolver fieldConflictsResolver : conflictResolvers) {
1137 fieldConflictsResolver.fix();
1141 private static PsiSubstitutor calculateSubstitutor(PsiMethod derivedMethod, PsiMethod baseMethod) {
1142 PsiSubstitutor substitutor;
1143 if (derivedMethod.getManager().areElementsEquivalent(derivedMethod, baseMethod)) {
1144 substitutor = PsiSubstitutor.EMPTY;
1146 final PsiClass baseClass = baseMethod.getContainingClass();
1147 final PsiClass derivedClass = derivedMethod.getContainingClass();
1148 if(baseClass != null && derivedClass != null && InheritanceUtil.isInheritorOrSelf(derivedClass, baseClass, true)) {
1149 final PsiSubstitutor superClassSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(baseClass, derivedClass, PsiSubstitutor.EMPTY);
1150 final MethodSignature superMethodSignature = baseMethod.getSignature(superClassSubstitutor);
1151 final MethodSignature methodSignature = derivedMethod.getSignature(PsiSubstitutor.EMPTY);
1152 final PsiSubstitutor superMethodSubstitutor = MethodSignatureUtil.getSuperMethodSignatureSubstitutor(methodSignature, superMethodSignature);
1153 substitutor = superMethodSubstitutor != null ? superMethodSubstitutor : superClassSubstitutor;
1155 substitutor = PsiSubstitutor.EMPTY;
1161 private static void processParameterUsage(PsiReferenceExpression ref, String oldName, String newName)
1162 throws IncorrectOperationException {
1164 PsiElement last = ref.getReferenceNameElement();
1165 if (last instanceof PsiIdentifier && last.getText().equals(oldName)) {
1166 PsiElementFactory factory = JavaPsiFacade.getInstance(ref.getProject()).getElementFactory();
1167 PsiIdentifier newNameIdentifier = factory.createIdentifier(newName);
1168 last.replace(newNameIdentifier);
1172 private static class MyParameterUsageInfo extends UsageInfo {
1173 final String oldParameterName;
1174 final String newParameterName;
1176 public MyParameterUsageInfo(PsiElement element, String oldParameterName, String newParameterName) {
1178 this.oldParameterName = oldParameterName;
1179 this.newParameterName = newParameterName;
1183 private static class RenamedParameterCollidesWithLocalUsageInfo extends UnresolvableCollisionUsageInfo {
1184 private final PsiElement myCollidingElement;
1185 private final PsiMethod myMethod;
1187 public RenamedParameterCollidesWithLocalUsageInfo(PsiParameter parameter, PsiElement collidingElement, PsiMethod method) {
1188 super(parameter, collidingElement);
1189 myCollidingElement = collidingElement;
1193 public String getDescription() {
1194 return RefactoringBundle.message("there.is.already.a.0.in.the.1.it.will.conflict.with.the.renamed.parameter",
1195 RefactoringUIUtil.getDescription(myCollidingElement, true),
1196 RefactoringUIUtil.getDescription(myMethod, true));
1200 private void fixJavadocsForChangedMethod(PsiMethod method) throws IncorrectOperationException {
1201 final PsiParameter[] parameters = method.getParameterList().getParameters();
1202 final ParameterInfoImpl[] newParms = myChangeInfo.newParms;
1203 LOG.assertTrue(parameters.length == newParms.length);
1204 final Set<PsiParameter> newParameters = new HashSet<PsiParameter>();
1205 for (int i = 0; i < newParms.length; i++) {
1206 ParameterInfoImpl newParm = newParms[i];
1207 if (newParm.oldParameterIndex < 0 ||
1208 !newParm.getName().equals(myChangeInfo.oldParameterNames[newParm.oldParameterIndex])) {
1209 newParameters.add(parameters[i]);
1212 RefactoringUtil.fixJavadocsForParams(method, newParameters);
1215 private static class ExpressionList implements ChangeSignatureUtil.ChildrenGenerator<PsiExpressionList, PsiExpression> {
1216 public static final ExpressionList INSTANCE = new ExpressionList();
1217 public List<PsiExpression> getChildren(PsiExpressionList psiExpressionList) {
1218 return Arrays.asList(psiExpressionList.getExpressions());
1222 private static class ParameterList implements ChangeSignatureUtil.ChildrenGenerator<PsiParameterList, PsiParameter> {
1223 public static final ParameterList INSTANCE = new ParameterList();
1224 public List<PsiParameter> getChildren(PsiParameterList psiParameterList) {
1225 return Arrays.asList(psiParameterList.getParameters());
1229 private static class ThrowsList implements ChangeSignatureUtil.ChildrenGenerator<PsiReferenceList, PsiJavaCodeReferenceElement> {
1230 public static final ThrowsList INSTANCE = new ThrowsList();
1231 public List<PsiJavaCodeReferenceElement> getChildren(PsiReferenceList throwsList) {
1232 return Arrays.asList(throwsList.getReferenceElements());