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
;
64 public class ChangeSignatureProcessor
extends BaseRefactoringProcessor
{
65 private static final Logger LOG
= Logger
.getInstance("#com.intellij.refactoring.changeSignature.ChangeSignatureProcessor");
67 @Modifier private final String myNewVisibility
;
68 private final ChangeInfoImpl myChangeInfo
;
69 private final PsiManager myManager
;
70 private final PsiElementFactory myFactory
;
71 private final boolean myGenerateDelegate
;
72 private final Set
<PsiMethod
> myPropagateParametersMethods
;
73 private final Set
<PsiMethod
> myPropagateExceptionsMethods
;
75 public ChangeSignatureProcessor(Project project
,
77 final boolean generateDelegate
,
78 @Modifier String newVisibility
,
81 @NotNull ParameterInfoImpl
[] parameterInfo
) {
82 this(project
, method
, generateDelegate
, newVisibility
, newName
,
83 newType
!= null ? CanonicalTypes
.createTypeWrapper(newType
) : null,
84 parameterInfo
, null, null, null);
87 public ChangeSignatureProcessor(Project project
,
89 final boolean generateDelegate
,
93 ParameterInfoImpl
[] parameterInfo
,
94 ThrownExceptionInfo
[] exceptionInfos
) {
95 this(project
, method
, generateDelegate
, newVisibility
, newName
,
96 newType
!= null ? CanonicalTypes
.createTypeWrapper(newType
) : null,
97 parameterInfo
, exceptionInfos
, null, null);
100 public ChangeSignatureProcessor(Project project
,
102 boolean generateDelegate
,
103 String newVisibility
,
105 CanonicalTypes
.Type newType
,
106 @NotNull ParameterInfoImpl
[] parameterInfo
,
107 ThrownExceptionInfo
[] thrownExceptions
,
108 Set
<PsiMethod
> propagateParametersMethods
,
109 Set
<PsiMethod
> propagateExceptionsMethods
) {
111 myManager
= PsiManager
.getInstance(project
);
112 myFactory
= JavaPsiFacade
.getInstance(myManager
.getProject()).getElementFactory();
113 myGenerateDelegate
= generateDelegate
;
115 myPropagateParametersMethods
= propagateParametersMethods
!= null ? propagateParametersMethods
: new HashSet
<PsiMethod
>();
116 myPropagateExceptionsMethods
= propagateExceptionsMethods
!= null ? propagateExceptionsMethods
: new HashSet
<PsiMethod
>();
118 LOG
.assertTrue(method
.isValid());
119 if (newVisibility
== null) {
120 myNewVisibility
= VisibilityUtil
.getVisibilityModifier(method
.getModifierList());
122 myNewVisibility
= newVisibility
;
125 myChangeInfo
= new ChangeInfoImpl(myNewVisibility
, method
, newName
, newType
, parameterInfo
, thrownExceptions
);
126 LOG
.assertTrue(myChangeInfo
.getMethod().isValid());
129 protected UsageViewDescriptor
createUsageViewDescriptor(UsageInfo
[] usages
) {
130 return new ChangeSignatureViewDescriptor(myChangeInfo
.getMethod());
134 protected UsageInfo
[] findUsages() {
135 ArrayList
<UsageInfo
> result
= new ArrayList
<UsageInfo
>();
136 final PsiMethod method
= myChangeInfo
.getMethod();
138 findSimpleUsages(method
, result
);
140 final UsageInfo
[] usageInfos
= result
.toArray(new UsageInfo
[result
.size()]);
141 return UsageViewUtil
.removeDuplicatedUsages(usageInfos
);
144 private void findSimpleUsages(final PsiMethod method
, final ArrayList
<UsageInfo
> result
) {
145 PsiMethod
[] overridingMethods
= findSimpleUsagesWithoutParameters(method
, result
, true, true, true);
146 findUsagesInCallers (result
);
148 //Parameter name changes are not propagated
149 findParametersUsage(method
, result
, overridingMethods
);
152 private PsiMethod
[] findSimpleUsagesWithoutParameters(final PsiMethod method
,
153 final ArrayList
<UsageInfo
> result
,
154 boolean isToModifyArgs
,
155 boolean isToThrowExceptions
,
156 boolean isOriginal
) {
158 GlobalSearchScope projectScope
= GlobalSearchScope
.projectScope(myProject
);
159 PsiMethod
[] overridingMethods
= OverridingMethodsSearch
.search(method
, method
.getUseScope(), true).toArray(PsiMethod
.EMPTY_ARRAY
);
161 for (PsiMethod overridingMethod
: overridingMethods
) {
162 result
.add(new OverriderUsageInfo(overridingMethod
, method
, isOriginal
, isToModifyArgs
, isToThrowExceptions
));
165 boolean needToChangeCalls
= !myGenerateDelegate
&& (myChangeInfo
.isNameChanged
|| myChangeInfo
.isParameterSetOrOrderChanged
|| myChangeInfo
.isExceptionSetOrOrderChanged
|| myChangeInfo
.isVisibilityChanged
/*for checking inaccessible*/);
166 if (needToChangeCalls
) {
167 int parameterCount
= method
.getParameterList().getParametersCount();
169 PsiReference
[] refs
= MethodReferencesSearch
.search(method
, projectScope
, true).toArray(PsiReference
.EMPTY_ARRAY
);
170 for (PsiReference ref
: refs
) {
171 PsiElement element
= ref
.getElement();
172 boolean isToCatchExceptions
= isToThrowExceptions
&& needToCatchExceptions(RefactoringUtil
.getEnclosingMethod(element
));
173 if (!isToCatchExceptions
) {
174 if (RefactoringUtil
.isMethodUsage(element
)) {
175 PsiExpressionList list
= RefactoringUtil
.getArgumentListByMethodReference(element
);
176 if (!method
.isVarArgs() && list
.getExpressions().length
!= parameterCount
) continue;
179 if (RefactoringUtil
.isMethodUsage(element
)) {
180 result
.add(new MethodCallUsageInfo(element
, isToModifyArgs
, isToCatchExceptions
));
182 else if (element
instanceof PsiDocTagValue
) {
183 result
.add(new UsageInfo(ref
.getElement()));
185 else if (element
instanceof PsiMethod
&& ((PsiMethod
)element
).isConstructor()) {
186 DefaultConstructorImplicitUsageInfo implicitUsageInfo
= new DefaultConstructorImplicitUsageInfo((PsiMethod
)element
,
187 ((PsiMethod
)element
).getContainingClass(), method
);
188 result
.add(implicitUsageInfo
);
190 else if(element
instanceof PsiClass
) {
191 LOG
.assertTrue(method
.isConstructor());
192 final PsiClass psiClass
= (PsiClass
)element
;
193 if (shouldPropagateToNonPhysicalMethod(method
, result
, psiClass
, myPropagateParametersMethods
)) continue;
194 if (shouldPropagateToNonPhysicalMethod(method
, result
, psiClass
, myPropagateExceptionsMethods
)) continue;
195 result
.add(new NoConstructorClassUsageInfo(psiClass
));
197 else if (ref
instanceof PsiCallReference
) {
198 result
.add(new CallReferenceUsageInfo((PsiCallReference
) ref
));
201 result
.add(new MoveRenameUsageInfo(element
, ref
, method
));
205 //if (method.isConstructor() && parameterCount == 0) {
206 // RefactoringUtil.visitImplicitConstructorUsages(method.getContainingClass(),
207 // new DefaultConstructorUsageCollector(result));
210 else if (myChangeInfo
.isParameterTypesChanged
) {
211 PsiReference
[] refs
= MethodReferencesSearch
.search(method
, projectScope
, true).toArray(PsiReference
.EMPTY_ARRAY
);
212 for (PsiReference reference
: refs
) {
213 final PsiElement element
= reference
.getElement();
214 if (element
instanceof PsiDocTagValue
) {
215 result
.add(new UsageInfo(reference
));
217 else if (element
instanceof XmlElement
) {
218 result
.add(new MoveRenameUsageInfo(reference
, method
));
224 detectLocalsCollisionsInMethod(method
, result
, isOriginal
);
225 for (final PsiMethod overridingMethod
: overridingMethods
) {
226 detectLocalsCollisionsInMethod(overridingMethod
, result
, isOriginal
);
229 return overridingMethods
;
232 private static boolean shouldPropagateToNonPhysicalMethod(PsiMethod method
, ArrayList
<UsageInfo
> result
, PsiClass containingClass
, final Set
<PsiMethod
> propagateMethods
) {
233 for (PsiMethod psiMethod
: propagateMethods
) {
234 if (!psiMethod
.isPhysical() && Comparing
.strEqual(psiMethod
.getName(), containingClass
.getName())) {
235 result
.add(new DefaultConstructorImplicitUsageInfo(psiMethod
, containingClass
, method
));
242 private void findUsagesInCallers(final ArrayList
<UsageInfo
> usages
) {
243 for (PsiMethod caller
: myPropagateParametersMethods
) {
244 usages
.add(new CallerUsageInfo(caller
, true, myPropagateExceptionsMethods
.contains(caller
)));
246 for (PsiMethod caller
: myPropagateExceptionsMethods
) {
247 usages
.add(new CallerUsageInfo(caller
, myPropagateParametersMethods
.contains(caller
), true));
249 Set
<PsiMethod
> merged
= new HashSet
<PsiMethod
>();
250 merged
.addAll(myPropagateParametersMethods
);
251 merged
.addAll(myPropagateExceptionsMethods
);
252 for (final PsiMethod method
: merged
) {
253 findSimpleUsagesWithoutParameters(method
, usages
, myPropagateParametersMethods
.contains(method
),
254 myPropagateExceptionsMethods
.contains(method
), false);
258 private boolean needToChangeCalls() {
259 return myChangeInfo
.isNameChanged
|| myChangeInfo
.isParameterSetOrOrderChanged
|| myChangeInfo
.isExceptionSetOrOrderChanged
;
262 private boolean needToCatchExceptions(PsiMethod caller
) {
263 return myChangeInfo
.isExceptionSetOrOrderChanged
&& !myPropagateExceptionsMethods
.contains(caller
);
266 private void detectLocalsCollisionsInMethod(final PsiMethod method
,
267 final ArrayList
<UsageInfo
> result
,
268 boolean isOriginal
) {
269 final PsiParameter
[] parameters
= method
.getParameterList().getParameters();
270 final Set
<PsiParameter
> deletedOrRenamedParameters
= new HashSet
<PsiParameter
>();
272 deletedOrRenamedParameters
.addAll(Arrays
.asList(parameters
));
273 for (ParameterInfoImpl parameterInfo
: myChangeInfo
.newParms
) {
274 if (parameterInfo
.oldParameterIndex
>= 0) {
275 final PsiParameter parameter
= parameters
[parameterInfo
.oldParameterIndex
];
276 if (parameterInfo
.getName().equals(parameter
.getName())) {
277 deletedOrRenamedParameters
.remove(parameter
);
283 for (ParameterInfoImpl parameterInfo
: myChangeInfo
.newParms
) {
284 final int oldParameterIndex
= parameterInfo
.oldParameterIndex
;
285 final String newName
= parameterInfo
.getName();
286 if (oldParameterIndex
>= 0) {
287 if (isOriginal
) { //Name changes take place only in primary method
288 final PsiParameter parameter
= parameters
[oldParameterIndex
];
289 if (!newName
.equals(parameter
.getName())) {
290 JavaUnresolvableLocalCollisionDetector
.visitLocalsCollisions(parameter
, newName
, method
.getBody(), null, new JavaUnresolvableLocalCollisionDetector
.CollidingVariableVisitor() {
291 public void visitCollidingElement(final PsiVariable collidingVariable
) {
292 if (!deletedOrRenamedParameters
.contains(collidingVariable
)) {
293 result
.add(new RenamedParameterCollidesWithLocalUsageInfo(parameter
, collidingVariable
, method
));
301 JavaUnresolvableLocalCollisionDetector
.visitLocalsCollisions(method
, newName
, method
.getBody(), null, new JavaUnresolvableLocalCollisionDetector
.CollidingVariableVisitor() {
302 public void visitCollidingElement(PsiVariable collidingVariable
) {
303 if (!deletedOrRenamedParameters
.contains(collidingVariable
)) {
304 result
.add(new NewParameterCollidesWithLocalUsageInfo(collidingVariable
, collidingVariable
, method
));
312 private void findParametersUsage(final PsiMethod method
, ArrayList
<UsageInfo
> result
, PsiMethod
[] overriders
) {
313 PsiParameter
[] parameters
= method
.getParameterList().getParameters();
314 for (ParameterInfoImpl info
: myChangeInfo
.newParms
) {
315 if (info
.oldParameterIndex
>= 0) {
316 PsiParameter parameter
= parameters
[info
.oldParameterIndex
];
317 if (!info
.getName().equals(parameter
.getName())) {
318 addParameterUsages(parameter
, result
, info
);
320 for (PsiMethod overrider
: overriders
) {
321 PsiParameter parameter1
= overrider
.getParameterList().getParameters()[info
.oldParameterIndex
];
322 if (parameter
.getName().equals(parameter1
.getName())) {
323 addParameterUsages(parameter1
, result
, info
);
331 protected void refreshElements(PsiElement
[] elements
) {
332 boolean condition
= elements
.length
== 1 && elements
[0] instanceof PsiMethod
;
333 LOG
.assertTrue(condition
);
334 myChangeInfo
.updateMethod((PsiMethod
) elements
[0]);
337 private void addMethodConflicts(MultiMap
<PsiElement
, String
> conflicts
) {
338 String newMethodName
= myChangeInfo
.newName
;
342 PsiManager manager
= PsiManager
.getInstance(myProject
);
343 PsiElementFactory factory
= JavaPsiFacade
.getInstance(manager
.getProject()).getElementFactory();
344 final PsiMethod method
= myChangeInfo
.getMethod();
345 final CanonicalTypes
.Type returnType
= myChangeInfo
.newReturnType
;
346 if (returnType
!= null) {
347 prototype
= factory
.createMethod(newMethodName
, returnType
.getType(method
, manager
));
350 prototype
= factory
.createConstructor();
351 prototype
.setName(newMethodName
);
353 ParameterInfoImpl
[] parameters
= myChangeInfo
.newParms
;
356 for (ParameterInfoImpl info
: parameters
) {
357 final PsiType parameterType
= info
.createType(method
, manager
);
358 PsiParameter param
= factory
.createParameter(info
.getName(), parameterType
);
359 prototype
.getParameterList().add(param
);
362 ConflictsUtil
.checkMethodConflicts(
363 method
.getContainingClass(),
365 prototype
, conflicts
);
367 catch (IncorrectOperationException e
) {
373 protected boolean preprocessUsages(Ref
<UsageInfo
[]> refUsages
) {
374 MultiMap
<PsiElement
, String
> conflictDescriptions
= new MultiMap
<PsiElement
, String
>();
375 UsageInfo
[] usagesIn
= refUsages
.get();
376 addMethodConflicts(conflictDescriptions
);
377 RenameUtil
.addConflictDescriptions(usagesIn
, conflictDescriptions
);
378 Set
<UsageInfo
> usagesSet
= new HashSet
<UsageInfo
>(Arrays
.asList(usagesIn
));
379 RenameUtil
.removeConflictUsages(usagesSet
);
380 if (myChangeInfo
.isVisibilityChanged
) {
382 addInaccessibilityDescriptions(usagesSet
, conflictDescriptions
);
384 catch (IncorrectOperationException e
) {
389 if (myPrepareSuccessfulSwingThreadCallback
!= null && !conflictDescriptions
.isEmpty()) {
390 ConflictsDialog dialog
= new ConflictsDialog(myProject
, conflictDescriptions
);
393 if (dialog
.isShowConflicts()) prepareSuccessful();
398 if (myChangeInfo
.isReturnTypeChanged
) {
399 askToRemoveCovariantOverriders (usagesSet
);
402 refUsages
.set(usagesSet
.toArray(new UsageInfo
[usagesSet
.size()]));
407 private void addInaccessibilityDescriptions(Set
<UsageInfo
> usages
, MultiMap
<PsiElement
, String
> conflictDescriptions
) throws IncorrectOperationException
{
408 PsiMethod method
= myChangeInfo
.getMethod();
409 PsiModifierList modifierList
= (PsiModifierList
)method
.getModifierList().copy();
410 VisibilityUtil
.setVisibility(modifierList
, myNewVisibility
);
412 for (Iterator
<UsageInfo
> iterator
= usages
.iterator(); iterator
.hasNext();) {
413 UsageInfo usageInfo
= iterator
.next();
414 PsiElement element
= usageInfo
.getElement();
415 if (element
!= null) {
416 if (element
instanceof PsiReferenceExpression
) {
417 PsiClass accessObjectClass
= null;
418 PsiExpression qualifier
= ((PsiReferenceExpression
)element
).getQualifierExpression();
419 if (qualifier
!= null) {
420 accessObjectClass
= (PsiClass
)PsiUtil
.getAccessObjectClass(qualifier
).getElement();
423 if (!JavaPsiFacade
.getInstance(element
.getProject()).getResolveHelper()
424 .isAccessible(method
, modifierList
, element
, accessObjectClass
, null)) {
426 RefactoringBundle
.message("0.with.1.visibility.is.not.accesible.from.2",
427 RefactoringUIUtil
.getDescription(method
, true),
429 RefactoringUIUtil
.getDescription(ConflictsUtil
.getContainer(element
), true));
430 conflictDescriptions
.putValue(method
, message
);
431 if (!needToChangeCalls()) {
440 private void askToRemoveCovariantOverriders(Set
<UsageInfo
> usages
) {
441 if (PsiUtil
.isLanguageLevel5OrHigher(myChangeInfo
.getMethod())) {
442 List
<UsageInfo
> covariantOverriderInfos
= new ArrayList
<UsageInfo
>();
443 for (UsageInfo usageInfo
: usages
) {
444 if (usageInfo
instanceof OverriderUsageInfo
) {
445 final OverriderUsageInfo info
= (OverriderUsageInfo
)usageInfo
;
446 PsiMethod overrider
= info
.getElement();
447 PsiMethod baseMethod
= info
.getBaseMethod();
448 PsiSubstitutor substitutor
= calculateSubstitutor(overrider
, baseMethod
);
451 type
= substitutor
.substitute(myChangeInfo
.newReturnType
.getType(myChangeInfo
.getMethod(), myManager
));
453 catch (IncorrectOperationException e
) {
457 final PsiType overriderType
= overrider
.getReturnType();
458 if (overriderType
!= null && type
.isAssignableFrom(overriderType
)) {
459 covariantOverriderInfos
.add(usageInfo
);
464 // to be able to do filtering
465 preprocessCovariantOverriders(covariantOverriderInfos
);
467 if (!covariantOverriderInfos
.isEmpty()) {
468 if (ApplicationManager
.getApplication().isUnitTestMode() || !isProcessCovariantOverriders()) {
469 for (UsageInfo usageInfo
: covariantOverriderInfos
) {
470 usages
.remove(usageInfo
);
477 protected void preprocessCovariantOverriders(final List
<UsageInfo
> covariantOverriderInfos
) {
480 protected boolean isProcessCovariantOverriders() {
481 return Messages
.showYesNoDialog(myProject
, RefactoringBundle
.message("do.you.want.to.process.overriding.methods.with.covariant.return.type"),
482 ChangeSignatureHandler
.REFACTORING_NAME
, Messages
.getQuestionIcon())
483 == DialogWrapper
.OK_EXIT_CODE
;
486 protected void performRefactoring(UsageInfo
[] usages
) {
487 PsiElementFactory factory
= JavaPsiFacade
.getInstance(myManager
.getProject()).getElementFactory();
490 if (myChangeInfo
.isNameChanged
) {
491 myChangeInfo
.newNameIdentifier
= factory
.createIdentifier(myChangeInfo
.newName
);
494 if (myChangeInfo
.isReturnTypeChanged
) {
495 myChangeInfo
.newTypeElement
= myChangeInfo
.newReturnType
.getType(myChangeInfo
.getMethod(), myManager
);
498 if (myGenerateDelegate
) {
502 for (UsageInfo usage
: usages
) {
503 if (usage
instanceof CallerUsageInfo
) {
504 final CallerUsageInfo callerUsageInfo
= (CallerUsageInfo
)usage
;
505 processCallerMethod(callerUsageInfo
.getMethod(), null, callerUsageInfo
.isToInsertParameter(),
506 callerUsageInfo
.isToInsertException());
508 else if (usage
instanceof OverriderUsageInfo
) {
509 OverriderUsageInfo info
= (OverriderUsageInfo
)usage
;
510 final PsiMethod method
= info
.getElement();
511 final PsiMethod baseMethod
= info
.getBaseMethod();
512 if (info
.isOriginalOverrider()) {
513 processPrimaryMethod(method
, baseMethod
, false);
516 processCallerMethod(method
, baseMethod
, info
.isToInsertArgs(), info
.isToCatchExceptions());
521 LOG
.assertTrue(myChangeInfo
.getMethod().isValid());
522 processPrimaryMethod(myChangeInfo
.getMethod(), null, true);
523 List
<UsageInfo
> postponedUsages
= new ArrayList
<UsageInfo
>();
525 for (UsageInfo usage
: usages
) {
526 PsiElement element
= usage
.getElement();
527 if (element
== null) continue;
529 if (usage
instanceof DefaultConstructorImplicitUsageInfo
) {
530 final DefaultConstructorImplicitUsageInfo defConstructorUsage
= (DefaultConstructorImplicitUsageInfo
)usage
;
531 PsiMethod constructor
= defConstructorUsage
.getConstructor();
532 if (!constructor
.isPhysical()) {
533 final boolean toPropagate
= myPropagateParametersMethods
.remove(constructor
);
534 final PsiClass containingClass
= defConstructorUsage
.getContainingClass();
535 constructor
= (PsiMethod
)containingClass
.add(constructor
);
536 PsiUtil
.setModifierProperty(constructor
, VisibilityUtil
.getVisibilityModifier(containingClass
.getModifierList()), true);
538 myPropagateParametersMethods
.add(constructor
);
541 addSuperCall(constructor
, defConstructorUsage
.getBaseConstructor(),usages
);
543 else if (usage
instanceof NoConstructorClassUsageInfo
) {
544 addDefaultConstructor(((NoConstructorClassUsageInfo
)usage
).getPsiClass(),usages
);
546 else if (element
instanceof PsiJavaCodeReferenceElement
) {
547 if (usage
instanceof MethodCallUsageInfo
) {
548 final MethodCallUsageInfo methodCallInfo
= (MethodCallUsageInfo
)usage
;
549 processMethodUsage(methodCallInfo
.getElement(), myChangeInfo
, methodCallInfo
.isToChangeArguments(),
550 methodCallInfo
.isToCatchExceptions(), methodCallInfo
.getReferencedMethod(), usages
);
552 else if (usage
instanceof MyParameterUsageInfo
) {
553 String newName
= ((MyParameterUsageInfo
)usage
).newParameterName
;
554 String oldName
= ((MyParameterUsageInfo
)usage
).oldParameterName
;
555 processParameterUsage((PsiReferenceExpression
)element
, oldName
, newName
);
557 postponedUsages
.add(usage
);
560 else if (usage
instanceof CallReferenceUsageInfo
) {
561 ((CallReferenceUsageInfo
) usage
).getReference().handleChangeSignature(myChangeInfo
);
563 else if (element
instanceof PsiEnumConstant
) {
564 fixActualArgumentsList(((PsiEnumConstant
)element
).getArgumentList(), myChangeInfo
, true);
566 else if (!(usage
instanceof OverriderUsageInfo
)) {
567 postponedUsages
.add(usage
);
571 for (UsageInfo usageInfo
: postponedUsages
) {
572 PsiElement element
= usageInfo
.getElement();
573 if (element
== null) continue;
574 PsiReference reference
= usageInfo
instanceof MoveRenameUsageInfo ?
575 usageInfo
.getReference() :
576 element
.getReference();
577 if (reference
!= null) {
578 PsiElement target
= null;
579 if (usageInfo
instanceof MyParameterUsageInfo
) {
580 String newParameterName
= ((MyParameterUsageInfo
)usageInfo
).newParameterName
;
581 PsiParameter
[] newParams
= myChangeInfo
.getMethod().getParameterList().getParameters();
582 for (PsiParameter newParam
: newParams
) {
583 if (newParam
.getName().equals(newParameterName
)) {
590 target
= myChangeInfo
.getMethod();
592 if (target
!= null) {
593 reference
.bindToElement(target
);
598 LOG
.assertTrue(myChangeInfo
.getMethod().isValid());
599 } catch (IncorrectOperationException e
) {
604 private void generateDelegate() throws IncorrectOperationException
{
605 final PsiMethod delegate
= (PsiMethod
)myChangeInfo
.getMethod().copy();
606 final PsiClass targetClass
= myChangeInfo
.getMethod().getContainingClass();
607 LOG
.assertTrue(!targetClass
.isInterface());
608 makeEmptyBody(myFactory
, delegate
);
609 final PsiCallExpression callExpression
= addDelegatingCallTemplate(delegate
, myChangeInfo
.newName
);
610 addDelegateArguments(callExpression
);
611 targetClass
.addBefore(delegate
, myChangeInfo
.getMethod());
614 private void addDelegateArguments(final PsiCallExpression callExpression
) throws IncorrectOperationException
{
615 final ParameterInfoImpl
[] newParms
= myChangeInfo
.newParms
;
616 for (int i
= 0; i
< newParms
.length
; i
++) {
617 ParameterInfoImpl newParm
= newParms
[i
];
618 final PsiExpression actualArg
;
619 if (newParm
.oldParameterIndex
>= 0) {
620 actualArg
= myFactory
.createExpressionFromText(myChangeInfo
.oldParameterNames
[newParm
.oldParameterIndex
], callExpression
);
623 actualArg
= myChangeInfo
.getValue(i
, callExpression
);
625 callExpression
.getArgumentList().add(actualArg
);
629 public static void makeEmptyBody(final PsiElementFactory factory
, final PsiMethod delegate
) throws IncorrectOperationException
{
630 PsiCodeBlock body
= delegate
.getBody();
632 body
.replace(factory
.createCodeBlock());
635 delegate
.add(factory
.createCodeBlock());
637 PsiUtil
.setModifierProperty(delegate
, PsiModifier
.ABSTRACT
, false);
640 public static PsiCallExpression
addDelegatingCallTemplate(final PsiMethod delegate
, final String newName
) throws IncorrectOperationException
{
641 Project project
= delegate
.getProject();
642 PsiElementFactory factory
= JavaPsiFacade
.getInstance(project
).getElementFactory();
643 PsiCodeBlock body
= delegate
.getBody();
645 final PsiCallExpression callExpression
;
646 if (delegate
.isConstructor()) {
647 PsiElement callStatement
= factory
.createStatementFromText("this();", null);
648 callStatement
= CodeStyleManager
.getInstance(project
).reformat(callStatement
);
649 callStatement
= body
.add(callStatement
);
650 callExpression
= (PsiCallExpression
)((PsiExpressionStatement
) callStatement
).getExpression();
652 if (PsiType
.VOID
.equals(delegate
.getReturnType())) {
653 PsiElement callStatement
= factory
.createStatementFromText(newName
+ "();", null);
654 callStatement
= CodeStyleManager
.getInstance(project
).reformat(callStatement
);
655 callStatement
= body
.add(callStatement
);
656 callExpression
= (PsiCallExpression
)((PsiExpressionStatement
) callStatement
).getExpression();
659 PsiElement callStatement
= factory
.createStatementFromText("return " + newName
+ "();", null);
660 callStatement
= CodeStyleManager
.getInstance(project
).reformat(callStatement
);
661 callStatement
= body
.add(callStatement
);
662 callExpression
= (PsiCallExpression
)((PsiReturnStatement
) callStatement
).getReturnValue();
665 return callExpression
;
668 private void addDefaultConstructor(PsiClass aClass
, final UsageInfo
[] usages
) throws IncorrectOperationException
{
669 if (!(aClass
instanceof PsiAnonymousClass
)) {
670 PsiMethod defaultConstructor
= myFactory
.createMethodFromText(aClass
.getName() + "(){}", aClass
);
671 defaultConstructor
= (PsiMethod
) CodeStyleManager
.getInstance(myProject
).reformat(defaultConstructor
);
672 defaultConstructor
= (PsiMethod
) aClass
.add(defaultConstructor
);
673 PsiUtil
.setModifierProperty(defaultConstructor
, VisibilityUtil
.getVisibilityModifier(aClass
.getModifierList()), true);
674 addSuperCall(defaultConstructor
, null, usages
);
676 final PsiElement parent
= aClass
.getParent();
677 if (parent
instanceof PsiNewExpression
) {
678 final PsiExpressionList argumentList
= ((PsiNewExpression
) parent
).getArgumentList();
679 fixActualArgumentsList(argumentList
, myChangeInfo
, true);
684 private void addSuperCall(PsiMethod constructor
, PsiMethod callee
, final UsageInfo
[] usages
) throws IncorrectOperationException
{
685 PsiExpressionStatement superCall
= (PsiExpressionStatement
) myFactory
.createStatementFromText("super();", constructor
);
686 PsiCodeBlock body
= constructor
.getBody();
688 PsiStatement
[] statements
= body
.getStatements();
689 if (statements
.length
> 0) {
690 superCall
= (PsiExpressionStatement
) body
.addBefore(superCall
, statements
[0]);
692 superCall
= (PsiExpressionStatement
) body
.add(superCall
);
694 PsiMethodCallExpression callExpression
= (PsiMethodCallExpression
) superCall
.getExpression();
695 processMethodUsage(callExpression
.getMethodExpression(), myChangeInfo
, true, false, callee
, usages
);
698 private PsiParameter
createNewParameter(ParameterInfoImpl newParm
,
699 PsiSubstitutor substitutor
) throws IncorrectOperationException
{
700 final PsiElementFactory factory
= JavaPsiFacade
.getInstance(myProject
).getElementFactory();
701 final PsiType type
= substitutor
.substitute(newParm
.createType(myChangeInfo
.getMethod().getParameterList(), myManager
));
702 return factory
.createParameter(newParm
.getName(), type
);
705 protected String
getCommandName() {
706 return RefactoringBundle
.message("changing.signature.of.0", UsageViewUtil
.getDescriptiveName(myChangeInfo
.getMethod()));
709 private void processMethodUsage(PsiElement ref
,
710 ChangeInfoImpl changeInfo
,
711 boolean toChangeArguments
,
712 boolean toCatchExceptions
,
713 PsiMethod callee
, final UsageInfo
[] usages
) throws IncorrectOperationException
{
714 if (changeInfo
.isNameChanged
) {
715 if (ref
instanceof PsiJavaCodeReferenceElement
) {
716 PsiElement last
= ((PsiJavaCodeReferenceElement
)ref
).getReferenceNameElement();
717 if (last
instanceof PsiIdentifier
&& last
.getText().equals(changeInfo
.oldName
)) {
718 last
.replace(changeInfo
.newNameIdentifier
);
723 final PsiMethod caller
= RefactoringUtil
.getEnclosingMethod(ref
);
724 if (toChangeArguments
) {
725 final PsiExpressionList list
= RefactoringUtil
.getArgumentListByMethodReference(ref
);
726 boolean toInsertDefaultValue
= !myPropagateParametersMethods
.contains(caller
);
727 if (toInsertDefaultValue
&& ref
instanceof PsiReferenceExpression
) {
728 final PsiExpression qualifierExpression
= ((PsiReferenceExpression
) ref
).getQualifierExpression();
729 if (qualifierExpression
instanceof PsiSuperExpression
&& callerSignatureIsAboutToChangeToo(caller
, usages
)) {
730 toInsertDefaultValue
= false;
734 fixActualArgumentsList(list
, changeInfo
, toInsertDefaultValue
);
737 if (toCatchExceptions
) {
738 if (!(ref
instanceof PsiReferenceExpression
&& ((PsiReferenceExpression
)ref
).getQualifierExpression() instanceof PsiSuperExpression
)) {
739 if (needToCatchExceptions(caller
)) {
740 PsiClassType
[] newExceptions
= callee
!= null ?
getCalleeChangedExceptionInfo(callee
) : getPrimaryChangedExceptionInfo(changeInfo
);
741 fixExceptions(ref
, newExceptions
);
747 private static boolean callerSignatureIsAboutToChangeToo(final PsiMethod caller
, final UsageInfo
[] usages
) {
748 for (UsageInfo usage
: usages
) {
749 if (usage
instanceof MethodCallUsageInfo
&& MethodSignatureUtil
.isSuperMethod(((MethodCallUsageInfo
)usage
).getReferencedMethod(), caller
)) return true;
754 private static PsiClassType
[] getCalleeChangedExceptionInfo(final PsiMethod callee
) {
755 return callee
.getThrowsList().getReferencedTypes(); //Callee method's throws list is already modified!
758 private PsiClassType
[] getPrimaryChangedExceptionInfo(ChangeInfoImpl changeInfo
) throws IncorrectOperationException
{
759 PsiClassType
[] newExceptions
= new PsiClassType
[changeInfo
.newExceptions
.length
];
760 for (int i
= 0; i
< newExceptions
.length
; i
++) {
761 newExceptions
[i
] = (PsiClassType
)changeInfo
.newExceptions
[i
].myType
.getType(myChangeInfo
.getMethod(), myManager
); //context really does not matter here
763 return newExceptions
;
766 private void fixExceptions(PsiElement ref
, PsiClassType
[] newExceptions
) throws IncorrectOperationException
{
767 //methods' throws lists are already modified, may use ExceptionUtil.collectUnhandledExceptions
768 newExceptions
= filterCheckedExceptions(newExceptions
);
770 PsiElement context
= PsiTreeUtil
.getParentOfType(ref
, PsiTryStatement
.class, PsiMethod
.class);
771 if (context
instanceof PsiTryStatement
) {
772 PsiTryStatement tryStatement
= (PsiTryStatement
)context
;
773 PsiCodeBlock tryBlock
= tryStatement
.getTryBlock();
775 //Remove unused catches
776 Collection
<PsiClassType
> classes
= ExceptionUtil
.collectUnhandledExceptions(tryBlock
, tryBlock
);
777 PsiParameter
[] catchParameters
= tryStatement
.getCatchBlockParameters();
778 for (PsiParameter parameter
: catchParameters
) {
779 final PsiType caughtType
= parameter
.getType();
781 if (!(caughtType
instanceof PsiClassType
)) continue;
782 if (ExceptionUtil
.isUncheckedExceptionOrSuperclass((PsiClassType
)caughtType
)) continue;
784 if (!isCatchParameterRedundant((PsiClassType
)caughtType
, classes
)) continue;
785 parameter
.getParent().delete(); //delete catch section
788 PsiClassType
[] exceptionsToAdd
= filterUnhandledExceptions(newExceptions
, tryBlock
);
789 addExceptions(exceptionsToAdd
, tryStatement
);
791 adjustPossibleEmptyTryStatement(tryStatement
);
794 newExceptions
= filterUnhandledExceptions(newExceptions
, ref
);
795 if (newExceptions
.length
> 0) {
796 //Add new try statement
797 PsiElementFactory elementFactory
= JavaPsiFacade
.getInstance(myManager
.getProject()).getElementFactory();
798 PsiTryStatement tryStatement
= (PsiTryStatement
)elementFactory
.createStatementFromText("try {} catch (Exception e) {}", null);
799 PsiStatement anchor
= PsiTreeUtil
.getParentOfType(ref
, PsiStatement
.class);
800 LOG
.assertTrue(anchor
!= null);
801 tryStatement
.getTryBlock().add(anchor
);
802 tryStatement
= (PsiTryStatement
)anchor
.getParent().addAfter(tryStatement
, anchor
);
804 addExceptions(newExceptions
, tryStatement
);
806 tryStatement
.getCatchSections()[0].delete(); //Delete dummy catch section
811 private static PsiClassType
[] filterCheckedExceptions(PsiClassType
[] exceptions
) {
812 List
<PsiClassType
> result
= new ArrayList
<PsiClassType
>();
813 for (PsiClassType exceptionType
: exceptions
) {
814 if (!ExceptionUtil
.isUncheckedException(exceptionType
)) result
.add(exceptionType
);
816 return result
.toArray(new PsiClassType
[result
.size()]);
819 private static void adjustPossibleEmptyTryStatement(PsiTryStatement tryStatement
) throws IncorrectOperationException
{
820 PsiCodeBlock tryBlock
= tryStatement
.getTryBlock();
821 if (tryBlock
!= null) {
822 if (tryStatement
.getCatchSections().length
== 0 &&
823 tryStatement
.getFinallyBlock() == null) {
824 PsiElement firstBodyElement
= tryBlock
.getFirstBodyElement();
825 if (firstBodyElement
!= null) {
826 tryStatement
.getParent().addRangeAfter(firstBodyElement
, tryBlock
.getLastBodyElement(), tryStatement
);
828 tryStatement
.delete();
833 private static void addExceptions(PsiClassType
[] exceptionsToAdd
, PsiTryStatement tryStatement
) throws IncorrectOperationException
{
834 for (PsiClassType type
: exceptionsToAdd
) {
835 final JavaCodeStyleManager styleManager
= JavaCodeStyleManager
.getInstance(tryStatement
.getProject());
836 String name
= styleManager
.suggestVariableName(VariableKind
.PARAMETER
, null, null, type
).names
[0];
837 name
= styleManager
.suggestUniqueVariableName(name
, tryStatement
, false);
839 PsiCatchSection catchSection
=
840 JavaPsiFacade
.getInstance(tryStatement
.getProject()).getElementFactory().createCatchSection(type
, name
, tryStatement
);
841 tryStatement
.add(catchSection
);
845 private void fixPrimaryThrowsLists(PsiMethod method
, PsiClassType
[] newExceptions
) throws IncorrectOperationException
{
846 PsiElementFactory elementFactory
= JavaPsiFacade
.getInstance(myManager
.getProject()).getElementFactory();
847 PsiJavaCodeReferenceElement
[] refs
= new PsiJavaCodeReferenceElement
[newExceptions
.length
];
848 for (int i
= 0; i
< refs
.length
; i
++) {
849 refs
[i
] = elementFactory
.createReferenceElementByType(newExceptions
[i
]);
851 PsiReferenceList throwsList
= elementFactory
.createReferenceList(refs
);
853 replaceThrowsList(method
, throwsList
);
856 private void replaceThrowsList(PsiMethod method
, PsiReferenceList throwsList
) throws IncorrectOperationException
{
857 PsiReferenceList methodThrowsList
= (PsiReferenceList
)method
.getThrowsList().replace(throwsList
);
858 methodThrowsList
= (PsiReferenceList
)JavaCodeStyleManager
.getInstance(myProject
).shortenClassReferences(methodThrowsList
);
859 myManager
.getCodeStyleManager().reformatRange(method
, method
.getParameterList().getTextRange().getEndOffset(),
860 methodThrowsList
.getTextRange().getEndOffset());
863 private static PsiClassType
[] filterUnhandledExceptions(PsiClassType
[] exceptions
, PsiElement place
) {
864 List
<PsiClassType
> result
= new ArrayList
<PsiClassType
>();
865 for (PsiClassType exception
: exceptions
) {
866 if (!ExceptionUtil
.isHandled(exception
, place
)) result
.add(exception
);
868 return result
.toArray(new PsiClassType
[result
.size()]);
871 private static boolean isCatchParameterRedundant (PsiClassType catchParamType
, Collection
<PsiClassType
> thrownTypes
) {
872 for (PsiType exceptionType
: thrownTypes
) {
873 if (exceptionType
.isConvertibleFrom(catchParamType
)) return false;
878 private static int getNonVarargCount(ChangeInfoImpl changeInfo
, PsiExpression
[] args
) {
879 if (!changeInfo
.wasVararg
) return args
.length
;
880 return changeInfo
.oldParameterTypes
.length
- 1;
883 //This methods works equally well for primary usages as well as for propagated callers' usages
884 private void fixActualArgumentsList(PsiExpressionList list
,
885 ChangeInfoImpl changeInfo
,
886 boolean toInsertDefaultValue
) throws IncorrectOperationException
{
887 final PsiElementFactory factory
= JavaPsiFacade
.getInstance(list
.getProject()).getElementFactory();
888 if (changeInfo
.isParameterSetOrOrderChanged
) {
889 if (changeInfo
.isPropagationEnabled
) {
890 final ParameterInfoImpl
[] createdParmsInfo
= changeInfo
.getCreatedParmsInfoWithoutVarargs();
891 for (ParameterInfoImpl info
: createdParmsInfo
) {
892 PsiExpression newArg
;
893 if (toInsertDefaultValue
) {
894 newArg
= createDefaultValue(factory
, info
, list
);
897 newArg
= factory
.createExpressionFromText(info
.getName(), list
);
903 final PsiExpression
[] args
= list
.getExpressions();
904 final int nonVarargCount
= getNonVarargCount(changeInfo
, args
);
905 final int varargCount
= args
.length
- nonVarargCount
;
906 PsiExpression
[] newVarargInitializers
= null;
908 final int newArgsLength
;
909 final int newNonVarargCount
;
910 if (changeInfo
.arrayToVarargs
) {
911 newNonVarargCount
= changeInfo
.newParms
.length
- 1;
912 final ParameterInfoImpl lastNewParm
= changeInfo
.newParms
[changeInfo
.newParms
.length
- 1];
913 final PsiExpression arrayToConvert
= args
[lastNewParm
.oldParameterIndex
];
914 if (arrayToConvert
instanceof PsiNewExpression
) {
915 final PsiNewExpression expression
= (PsiNewExpression
)arrayToConvert
;
916 final PsiArrayInitializerExpression arrayInitializer
= expression
.getArrayInitializer();
917 if (arrayInitializer
!= null) {
918 newVarargInitializers
= arrayInitializer
.getInitializers();
921 newArgsLength
= newVarargInitializers
== null ? changeInfo
.newParms
.length
: newNonVarargCount
+ newVarargInitializers
.length
;
923 else if (changeInfo
.retainsVarargs
) {
924 newNonVarargCount
= changeInfo
.newParms
.length
- 1;
925 newArgsLength
= newNonVarargCount
+ varargCount
;
927 else if (changeInfo
.obtainsVarags
) {
928 newNonVarargCount
= changeInfo
.newParms
.length
- 1;
929 newArgsLength
= newNonVarargCount
;
932 newNonVarargCount
= changeInfo
.newParms
.length
;
933 newArgsLength
= changeInfo
.newParms
.length
;
935 final PsiExpression
[] newArgs
= new PsiExpression
[newArgsLength
];
936 for (int i
= 0; i
< newNonVarargCount
; i
++) {
937 newArgs
[i
] = createActualArgument(list
, changeInfo
.newParms
[i
], toInsertDefaultValue
, args
);
939 if (changeInfo
.arrayToVarargs
) {
940 if (newVarargInitializers
== null) {
941 newArgs
[newNonVarargCount
] = createActualArgument(list
, changeInfo
.newParms
[newNonVarargCount
], toInsertDefaultValue
, args
);
944 for (int i
= 0; i
< newVarargInitializers
.length
; i
++) {
945 newArgs
[i
+ newNonVarargCount
] = newVarargInitializers
[i
];
950 final int newVarargCount
= newArgsLength
- newNonVarargCount
;
951 LOG
.assertTrue(newVarargCount
== 0 || newVarargCount
== varargCount
);
952 for (int i
= 0; i
< newVarargCount
; i
++) {
953 newArgs
[newNonVarargCount
+ i
] = args
[nonVarargCount
+ i
];
956 ChangeSignatureUtil
.synchronizeList(list
, Arrays
.asList(newArgs
), ExpressionList
.INSTANCE
, changeInfo
.toRemoveParm
);
961 private PsiExpression
createActualArgument(final PsiExpressionList list
, final ParameterInfoImpl info
, final boolean toInsertDefaultValue
,
962 final PsiExpression
[] args
) throws IncorrectOperationException
{
963 final PsiElementFactory factory
= JavaPsiFacade
.getInstance(list
.getProject()).getElementFactory();
964 final int index
= info
.oldParameterIndex
;
968 if (toInsertDefaultValue
) {
969 return createDefaultValue(factory
, info
, list
);
971 return factory
.createExpressionFromText(info
.getName(), list
);
976 private PsiExpression
createDefaultValue(final PsiElementFactory factory
, final ParameterInfoImpl info
, final PsiExpressionList list
)
977 throws IncorrectOperationException
{
978 if (info
.useAnySingleVariable
) {
979 final PsiResolveHelper resolveHelper
= JavaPsiFacade
.getInstance(list
.getProject()).getResolveHelper();
980 final PsiType type
= info
.getTypeWrapper().getType(myChangeInfo
.getMethod(), myManager
);
981 final VariablesProcessor processor
= new VariablesProcessor(false) {
982 protected boolean check(PsiVariable var
, ResolveState state
) {
983 if (var
instanceof PsiField
&& !resolveHelper
.isAccessible((PsiField
)var
, list
, null)) return false;
984 final PsiType varType
= state
.get(PsiSubstitutor
.KEY
).substitute(var
.getType());
985 return type
.isAssignableFrom(varType
);
988 public boolean execute(PsiElement pe
, ResolveState state
) {
989 super.execute(pe
, state
);
993 PsiScopesUtil
.treeWalkUp(processor
, list
, null);
994 if (processor
.size() == 1) {
995 final PsiVariable result
= processor
.getResult(0);
996 return factory
.createExpressionFromText(result
.getName(), list
);
999 final PsiCallExpression callExpression
= PsiTreeUtil
.getParentOfType(list
, PsiCallExpression
.class);
1000 return callExpression
!= null ? info
.getValue(callExpression
) : factory
.createExpressionFromText(info
.defaultValue
, list
);
1003 private static void addParameterUsages(PsiParameter parameter
,
1004 ArrayList
<UsageInfo
> results
,
1005 ParameterInfoImpl info
) {
1006 PsiManager manager
= parameter
.getManager();
1007 GlobalSearchScope projectScope
= GlobalSearchScope
.projectScope(manager
.getProject());
1008 for (PsiReference psiReference
: ReferencesSearch
.search(parameter
, projectScope
, false)) {
1009 PsiElement parmRef
= psiReference
.getElement();
1010 UsageInfo usageInfo
= new MyParameterUsageInfo(parmRef
, parameter
.getName(), info
.getName());
1011 results
.add(usageInfo
);
1015 private void processCallerMethod(PsiMethod caller
,
1016 PsiMethod baseMethod
,
1017 boolean toInsertParams
,
1018 boolean toInsertThrows
) throws IncorrectOperationException
{
1019 LOG
.assertTrue(toInsertParams
|| toInsertThrows
);
1020 if (toInsertParams
) {
1021 List
<PsiParameter
> newParameters
= new ArrayList
<PsiParameter
>();
1022 newParameters
.addAll(Arrays
.asList(caller
.getParameterList().getParameters()));
1023 final ParameterInfoImpl
[] primaryNewParms
= myChangeInfo
.newParms
;
1024 PsiSubstitutor substitutor
= baseMethod
== null ? PsiSubstitutor
.EMPTY
: calculateSubstitutor(caller
, baseMethod
);
1025 for (ParameterInfoImpl info
: primaryNewParms
) {
1026 if (info
.oldParameterIndex
< 0) newParameters
.add(createNewParameter(info
, substitutor
));
1028 PsiParameter
[] arrayed
= newParameters
.toArray(new PsiParameter
[newParameters
.size()]);
1029 boolean[] toRemoveParm
= new boolean[arrayed
.length
];
1030 Arrays
.fill(toRemoveParm
, false);
1031 resolveParameterVsFieldsConflicts(arrayed
, caller
, caller
.getParameterList(), toRemoveParm
);
1034 if (toInsertThrows
) {
1035 List
<PsiJavaCodeReferenceElement
> newThrowns
= new ArrayList
<PsiJavaCodeReferenceElement
>();
1036 final PsiReferenceList throwsList
= caller
.getThrowsList();
1037 newThrowns
.addAll(Arrays
.asList(throwsList
.getReferenceElements()));
1038 final ThrownExceptionInfo
[] primaryNewExns
= myChangeInfo
.newExceptions
;
1039 for (ThrownExceptionInfo thrownExceptionInfo
: primaryNewExns
) {
1040 if (thrownExceptionInfo
.oldIndex
< 0) {
1041 final PsiClassType type
= (PsiClassType
)thrownExceptionInfo
.createType(caller
, myManager
);
1042 final PsiJavaCodeReferenceElement ref
=
1043 JavaPsiFacade
.getInstance(caller
.getProject()).getElementFactory().createReferenceElementByType(type
);
1044 newThrowns
.add(ref
);
1047 PsiJavaCodeReferenceElement
[] arrayed
= newThrowns
.toArray(new PsiJavaCodeReferenceElement
[newThrowns
.size()]);
1048 boolean[] toRemoveParm
= new boolean[arrayed
.length
];
1049 Arrays
.fill(toRemoveParm
, false);
1050 ChangeSignatureUtil
.synchronizeList(throwsList
, Arrays
.asList(arrayed
), ThrowsList
.INSTANCE
, toRemoveParm
);
1054 private void processPrimaryMethod(PsiMethod method
,
1055 PsiMethod baseMethod
,
1056 boolean isOriginal
) throws IncorrectOperationException
{
1057 PsiElementFactory factory
= JavaPsiFacade
.getInstance(method
.getProject()).getElementFactory();
1059 if (myChangeInfo
.isVisibilityChanged
) {
1060 PsiModifierList modifierList
= method
.getModifierList();
1061 final String highestVisibility
= isOriginal ?
1063 VisibilityUtil
.getHighestVisibility(myNewVisibility
, VisibilityUtil
.getVisibilityModifier(modifierList
));
1064 VisibilityUtil
.setVisibility(modifierList
, highestVisibility
);
1067 if (myChangeInfo
.isNameChanged
) {
1068 String newName
= baseMethod
== null ? myChangeInfo
.newName
:
1069 RefactoringUtil
.suggestNewOverriderName(method
.getName(), baseMethod
.getName(), myChangeInfo
.newName
);
1071 if (newName
!= null && !newName
.equals(method
.getName())) {
1072 final PsiIdentifier nameId
= method
.getNameIdentifier();
1073 assert nameId
!= null;
1074 nameId
.replace(JavaPsiFacade
.getInstance(myManager
.getProject()).getElementFactory().createIdentifier(newName
));
1078 final PsiSubstitutor substitutor
= baseMethod
== null ? PsiSubstitutor
.EMPTY
: calculateSubstitutor(method
, baseMethod
);
1080 if (myChangeInfo
.isReturnTypeChanged
) {
1081 final PsiType returnType
= substitutor
.substitute(myChangeInfo
.newTypeElement
);
1082 // don't modify return type for non-Java overriders (EJB)
1083 if (method
.getName().equals(myChangeInfo
.newName
)) {
1084 final PsiTypeElement typeElement
= method
.getReturnTypeElement();
1085 if (typeElement
!= null) {
1086 typeElement
.replace(factory
.createTypeElement(returnType
));
1091 PsiParameterList list
= method
.getParameterList();
1092 PsiParameter
[] parameters
= list
.getParameters();
1094 PsiParameter
[] newParms
= new PsiParameter
[myChangeInfo
.newParms
.length
];
1095 for (int i
= 0; i
< newParms
.length
; i
++) {
1096 ParameterInfoImpl info
= myChangeInfo
.newParms
[i
];
1097 int index
= info
.oldParameterIndex
;
1099 PsiParameter parameter
= parameters
[index
];
1100 newParms
[i
] = parameter
;
1102 String oldName
= myChangeInfo
.oldParameterNames
[index
];
1103 if (!oldName
.equals(info
.getName()) && oldName
.equals(parameter
.getName())) {
1104 PsiIdentifier newIdentifier
= factory
.createIdentifier(info
.getName());
1105 parameter
.getNameIdentifier().replace(newIdentifier
);
1108 String oldType
= myChangeInfo
.oldParameterTypes
[index
];
1109 if (!oldType
.equals(info
.getTypeText())) {
1110 parameter
.normalizeDeclaration();
1111 PsiType newType
= substitutor
.substitute(info
.createType(myChangeInfo
.getMethod().getParameterList(), myManager
));
1113 parameter
.getTypeElement().replace(factory
.createTypeElement(newType
));
1116 newParms
[i
] = createNewParameter(info
, substitutor
);
1120 resolveParameterVsFieldsConflicts(newParms
, method
, list
, myChangeInfo
.toRemoveParm
);
1121 fixJavadocsForChangedMethod(method
);
1122 if (myChangeInfo
.isExceptionSetOrOrderChanged
) {
1123 final PsiClassType
[] newExceptions
= getPrimaryChangedExceptionInfo(myChangeInfo
);
1124 fixPrimaryThrowsLists(method
, newExceptions
);
1128 private static void resolveParameterVsFieldsConflicts(final PsiParameter
[] newParms
,
1129 final PsiMethod method
,
1130 final PsiParameterList list
,
1131 boolean[] toRemoveParm
) throws IncorrectOperationException
{
1132 List
<FieldConflictsResolver
> conflictResolvers
= new ArrayList
<FieldConflictsResolver
>();
1133 for (PsiParameter parameter
: newParms
) {
1134 conflictResolvers
.add(new FieldConflictsResolver(parameter
.getName(), method
.getBody()));
1136 ChangeSignatureUtil
.synchronizeList(list
, Arrays
.asList(newParms
), ParameterList
.INSTANCE
, toRemoveParm
);
1137 JavaCodeStyleManager
.getInstance(list
.getProject()).shortenClassReferences(list
);
1138 for (FieldConflictsResolver fieldConflictsResolver
: conflictResolvers
) {
1139 fieldConflictsResolver
.fix();
1143 private static PsiSubstitutor
calculateSubstitutor(PsiMethod derivedMethod
, PsiMethod baseMethod
) {
1144 PsiSubstitutor substitutor
;
1145 if (derivedMethod
.getManager().areElementsEquivalent(derivedMethod
, baseMethod
)) {
1146 substitutor
= PsiSubstitutor
.EMPTY
;
1148 final PsiClass baseClass
= baseMethod
.getContainingClass();
1149 final PsiClass derivedClass
= derivedMethod
.getContainingClass();
1150 if(baseClass
!= null && derivedClass
!= null && InheritanceUtil
.isInheritorOrSelf(derivedClass
, baseClass
, true)) {
1151 final PsiSubstitutor superClassSubstitutor
= TypeConversionUtil
.getSuperClassSubstitutor(baseClass
, derivedClass
, PsiSubstitutor
.EMPTY
);
1152 final MethodSignature superMethodSignature
= baseMethod
.getSignature(superClassSubstitutor
);
1153 final MethodSignature methodSignature
= derivedMethod
.getSignature(PsiSubstitutor
.EMPTY
);
1154 final PsiSubstitutor superMethodSubstitutor
= MethodSignatureUtil
.getSuperMethodSignatureSubstitutor(methodSignature
, superMethodSignature
);
1155 substitutor
= superMethodSubstitutor
!= null ? superMethodSubstitutor
: superClassSubstitutor
;
1157 substitutor
= PsiSubstitutor
.EMPTY
;
1163 private static void processParameterUsage(PsiReferenceExpression ref
, String oldName
, String newName
)
1164 throws IncorrectOperationException
{
1166 PsiElement last
= ref
.getReferenceNameElement();
1167 if (last
instanceof PsiIdentifier
&& last
.getText().equals(oldName
)) {
1168 PsiElementFactory factory
= JavaPsiFacade
.getInstance(ref
.getProject()).getElementFactory();
1169 PsiIdentifier newNameIdentifier
= factory
.createIdentifier(newName
);
1170 last
.replace(newNameIdentifier
);
1174 private static class MyParameterUsageInfo
extends UsageInfo
{
1175 final String oldParameterName
;
1176 final String newParameterName
;
1178 public MyParameterUsageInfo(PsiElement element
, String oldParameterName
, String newParameterName
) {
1180 this.oldParameterName
= oldParameterName
;
1181 this.newParameterName
= newParameterName
;
1185 private static class RenamedParameterCollidesWithLocalUsageInfo
extends UnresolvableCollisionUsageInfo
{
1186 private final PsiElement myCollidingElement
;
1187 private final PsiMethod myMethod
;
1189 public RenamedParameterCollidesWithLocalUsageInfo(PsiParameter parameter
, PsiElement collidingElement
, PsiMethod method
) {
1190 super(parameter
, collidingElement
);
1191 myCollidingElement
= collidingElement
;
1195 public String
getDescription() {
1196 return RefactoringBundle
.message("there.is.already.a.0.in.the.1.it.will.conflict.with.the.renamed.parameter",
1197 RefactoringUIUtil
.getDescription(myCollidingElement
, true),
1198 RefactoringUIUtil
.getDescription(myMethod
, true));
1202 private void fixJavadocsForChangedMethod(PsiMethod method
) throws IncorrectOperationException
{
1203 final PsiParameter
[] parameters
= method
.getParameterList().getParameters();
1204 final ParameterInfoImpl
[] newParms
= myChangeInfo
.newParms
;
1205 LOG
.assertTrue(parameters
.length
== newParms
.length
);
1206 final Set
<PsiParameter
> newParameters
= new HashSet
<PsiParameter
>();
1207 for (int i
= 0; i
< newParms
.length
; i
++) {
1208 ParameterInfoImpl newParm
= newParms
[i
];
1209 if (newParm
.oldParameterIndex
< 0 ||
1210 !newParm
.getName().equals(myChangeInfo
.oldParameterNames
[newParm
.oldParameterIndex
])) {
1211 newParameters
.add(parameters
[i
]);
1214 RefactoringUtil
.fixJavadocsForParams(method
, newParameters
);
1217 private static class ExpressionList
implements ChangeSignatureUtil
.ChildrenGenerator
<PsiExpressionList
, PsiExpression
> {
1218 public static final ExpressionList INSTANCE
= new ExpressionList();
1219 public List
<PsiExpression
> getChildren(PsiExpressionList psiExpressionList
) {
1220 return Arrays
.asList(psiExpressionList
.getExpressions());
1224 private static class ParameterList
implements ChangeSignatureUtil
.ChildrenGenerator
<PsiParameterList
, PsiParameter
> {
1225 public static final ParameterList INSTANCE
= new ParameterList();
1226 public List
<PsiParameter
> getChildren(PsiParameterList psiParameterList
) {
1227 return Arrays
.asList(psiParameterList
.getParameters());
1231 private static class ThrowsList
implements ChangeSignatureUtil
.ChildrenGenerator
<PsiReferenceList
, PsiJavaCodeReferenceElement
> {
1232 public static final ThrowsList INSTANCE
= new ThrowsList();
1233 public List
<PsiJavaCodeReferenceElement
> getChildren(PsiReferenceList throwsList
) {
1234 return Arrays
.asList(throwsList
.getReferenceElements());