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