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 by IntelliJ IDEA.
22 * To change template for new class use
23 * Code Style | Class Templates options (Tools | IDE Options).
25 package com
.intellij
.refactoring
.memberPullUp
;
27 import com
.intellij
.codeInsight
.AnnotationUtil
;
28 import com
.intellij
.codeInsight
.ChangeContextUtil
;
29 import com
.intellij
.codeInsight
.PsiEquivalenceUtil
;
30 import com
.intellij
.codeInsight
.intention
.AddAnnotationFix
;
31 import com
.intellij
.openapi
.diagnostic
.Logger
;
32 import com
.intellij
.openapi
.util
.Condition
;
33 import com
.intellij
.psi
.*;
34 import com
.intellij
.psi
.codeStyle
.CodeStyleSettings
;
35 import com
.intellij
.psi
.codeStyle
.CodeStyleSettingsManager
;
36 import com
.intellij
.psi
.search
.LocalSearchScope
;
37 import com
.intellij
.psi
.search
.searches
.OverridingMethodsSearch
;
38 import com
.intellij
.psi
.search
.searches
.ReferencesSearch
;
39 import com
.intellij
.psi
.util
.InheritanceUtil
;
40 import com
.intellij
.psi
.util
.MethodSignatureUtil
;
41 import com
.intellij
.psi
.util
.PsiTreeUtil
;
42 import com
.intellij
.psi
.util
.PsiUtil
;
43 import com
.intellij
.refactoring
.listeners
.JavaRefactoringListenerManager
;
44 import com
.intellij
.refactoring
.listeners
.impl
.JavaRefactoringListenerManagerImpl
;
45 import com
.intellij
.refactoring
.util
.DocCommentPolicy
;
46 import com
.intellij
.refactoring
.util
.RefactoringHierarchyUtil
;
47 import com
.intellij
.refactoring
.util
.RefactoringUtil
;
48 import com
.intellij
.refactoring
.util
.classMembers
.ClassMemberReferencesVisitor
;
49 import com
.intellij
.refactoring
.util
.classMembers
.MemberInfo
;
50 import com
.intellij
.util
.IncorrectOperationException
;
51 import com
.intellij
.util
.VisibilityUtil
;
52 import com
.intellij
.util
.containers
.HashMap
;
53 import org
.jetbrains
.annotations
.Nullable
;
57 public class PullUpHelper
{
58 private static final Logger LOG
= Logger
.getInstance("#com.intellij.refactoring.memberPullUp.PullUpHelper");
59 private final PsiClass mySourceClass
;
60 private final PsiClass myTargetSuperClass
;
61 private final boolean myIsTargetInterface
;
62 private final MemberInfo
[] myMembersToMove
;
63 private final DocCommentPolicy myJavaDocPolicy
;
64 private HashSet
<PsiMember
> myMembersAfterMove
= null;
65 private final PsiManager myManager
;
68 public PullUpHelper(PsiClass sourceClass
, PsiClass targetSuperClass
, MemberInfo
[] membersToMove
,
69 DocCommentPolicy javaDocPolicy
) {
70 mySourceClass
= sourceClass
;
71 myTargetSuperClass
= targetSuperClass
;
72 myMembersToMove
= membersToMove
;
73 myJavaDocPolicy
= javaDocPolicy
;
74 myIsTargetInterface
= targetSuperClass
.isInterface();
75 myManager
= mySourceClass
.getManager();
78 public void moveMembersToBase()
79 throws IncorrectOperationException
{
80 final HashSet
<PsiMember
> movedMembers
= new HashSet
<PsiMember
>();
81 myMembersAfterMove
= new HashSet
<PsiMember
>();
84 for (MemberInfo info
: myMembersToMove
) {
85 movedMembers
.add(info
.getMember());
88 // correct private member visibility
89 for (MemberInfo info
: myMembersToMove
) {
90 if (info
.getMember() instanceof PsiClass
&& info
.getOverrides() != null) continue;
91 PsiModifierListOwner modifierListOwner
= info
.getMember();
92 if (myIsTargetInterface
) {
93 PsiUtil
.setModifierProperty(modifierListOwner
, PsiModifier
.PUBLIC
, true);
95 else if (modifierListOwner
.hasModifierProperty(PsiModifier
.PRIVATE
)) {
96 if (info
.isToAbstract() || willBeUsedInSubclass(modifierListOwner
, movedMembers
, myTargetSuperClass
, mySourceClass
)) {
97 PsiUtil
.setModifierProperty(modifierListOwner
, PsiModifier
.PROTECTED
, true);
100 ChangeContextUtil
.encodeContextInfo(info
.getMember(), true);
104 for (MemberInfo info
: myMembersToMove
) {
105 if (info
.getMember() instanceof PsiMethod
) {
106 PsiMethod method
= (PsiMethod
)info
.getMember();
107 final boolean isOriginalMethodAbstract
= method
.hasModifierProperty(PsiModifier
.ABSTRACT
);
108 if (myIsTargetInterface
|| info
.isToAbstract()) {
109 PsiMethod methodCopy
= (PsiMethod
)method
.copy();
110 ChangeContextUtil
.clearContextInfo(method
);
111 RefactoringUtil
.abstractizeMethod(myTargetSuperClass
, methodCopy
);
113 myJavaDocPolicy
.processCopiedJavaDoc(methodCopy
.getDocComment(), method
.getDocComment(), isOriginalMethodAbstract
);
115 final PsiMember movedElement
= (PsiMember
)myTargetSuperClass
.add(methodCopy
);
116 CodeStyleSettings styleSettings
= CodeStyleSettingsManager
.getSettings(method
.getProject());
117 if (styleSettings
.INSERT_OVERRIDE_ANNOTATION
) {
118 if (PsiUtil
.isLanguageLevel5OrHigher(mySourceClass
) && !myTargetSuperClass
.isInterface() || PsiUtil
.isLanguageLevel6OrHigher(mySourceClass
)) {
119 new AddAnnotationFix("java.lang.Override", method
).invoke(method
.getProject(), null, mySourceClass
.getContainingFile());
122 if (isOriginalMethodAbstract
&& myTargetSuperClass
.isInterface() && !PsiUtil
.isLanguageLevel6OrHigher(mySourceClass
)) {
123 for (PsiMethod oMethod
: OverridingMethodsSearch
.search(method
)) {
124 final PsiAnnotation annotation
= AnnotationUtil
.findAnnotation(oMethod
, Override
.class.getName());
125 if (annotation
!= null) {
130 myMembersAfterMove
.add(movedElement
);
131 if (isOriginalMethodAbstract
) {
136 if (isOriginalMethodAbstract
) {
137 PsiUtil
.setModifierProperty(myTargetSuperClass
, PsiModifier
.ABSTRACT
, true);
139 fixReferencesToStatic(method
, movedMembers
);
140 final PsiMethod superClassMethod
= myTargetSuperClass
.findMethodBySignature(method
, false);
141 if (superClassMethod
!= null && superClassMethod
.hasModifierProperty(PsiModifier
.ABSTRACT
)) {
142 superClassMethod
.replace(method
);
145 final PsiMember movedElement
= (PsiMember
)myTargetSuperClass
.add(method
);
146 myMembersAfterMove
.add(movedElement
);
151 else if (info
.getMember() instanceof PsiField
) {
152 PsiField field
= (PsiField
)info
.getMember();
153 field
.normalizeDeclaration();
154 fixReferencesToStatic(field
, movedMembers
);
155 if (myIsTargetInterface
) {
156 PsiUtil
.setModifierProperty(field
, PsiModifier
.PUBLIC
, true);
158 final PsiMember movedElement
= (PsiMember
)myTargetSuperClass
.add(field
);
159 myMembersAfterMove
.add(movedElement
);
162 else if (info
.getMember() instanceof PsiClass
) {
163 PsiClass aClass
= (PsiClass
)info
.getMember();
164 if (Boolean
.FALSE
.equals(info
.getOverrides())) {
165 final PsiReferenceList sourceReferenceList
= info
.getSourceReferenceList();
166 LOG
.assertTrue(sourceReferenceList
!= null);
167 PsiJavaCodeReferenceElement ref
= mySourceClass
.equals(sourceReferenceList
.getParent()) ?
168 RefactoringUtil
.removeFromReferenceList(sourceReferenceList
, aClass
) :
169 RefactoringUtil
.findReferenceToClass(sourceReferenceList
, aClass
);
171 final PsiReferenceList referenceList
=
172 myTargetSuperClass
.isInterface() ? myTargetSuperClass
.getExtendsList() : myTargetSuperClass
.getImplementsList();
173 assert referenceList
!= null;
174 referenceList
.add(ref
);
178 fixReferencesToStatic(aClass
, movedMembers
);
179 final PsiMember movedElement
= (PsiMember
)myTargetSuperClass
.add(aClass
);
180 myMembersAfterMove
.add(movedElement
);
186 ExplicitSuperDeleter explicitSuperDeleter
= new ExplicitSuperDeleter();
187 for (PsiMember member
: myMembersAfterMove
) {
188 member
.accept(explicitSuperDeleter
);
190 explicitSuperDeleter
.fixSupers();
192 final QualifiedThisSuperAdjuster qualifiedThisSuperAdjuster
= new QualifiedThisSuperAdjuster();
193 for (PsiMember member
: myMembersAfterMove
) {
194 member
.accept(qualifiedThisSuperAdjuster
);
197 ChangeContextUtil
.decodeContextInfo(myTargetSuperClass
, null, null);
199 for (final PsiMember movedMember
: myMembersAfterMove
) {
200 final JavaRefactoringListenerManager listenerManager
= JavaRefactoringListenerManager
.getInstance(movedMember
.getProject());
201 ((JavaRefactoringListenerManagerImpl
)listenerManager
).fireMemberMoved(mySourceClass
, movedMember
);
205 public void moveFieldInitializations() throws IncorrectOperationException
{
206 LOG
.assertTrue(myMembersAfterMove
!= null);
208 final LinkedHashSet
<PsiField
> movedFields
= new LinkedHashSet
<PsiField
>();
209 for (PsiMember member
: myMembersAfterMove
) {
210 if (member
instanceof PsiField
) {
211 movedFields
.add((PsiField
)member
);
215 if (movedFields
.isEmpty()) return;
216 PsiMethod
[] constructors
= myTargetSuperClass
.getConstructors();
218 if (constructors
.length
== 0) {
219 constructors
= new PsiMethod
[]{null};
222 HashMap
<PsiMethod
,HashSet
<PsiMethod
>> constructorsToSubConstructors
= buildConstructorsToSubConstructorsMap(constructors
);
223 for (PsiMethod constructor
: constructors
) {
224 HashSet
<PsiMethod
> subConstructors
= constructorsToSubConstructors
.get(constructor
);
225 tryToMoveInitializers(constructor
, subConstructors
, movedFields
);
229 private static class Initializer
{
230 public final PsiStatement initializer
;
231 public final Set
<PsiField
> movedFieldsUsed
;
232 public final Set
<PsiParameter
> usedParameters
;
233 public final List
<PsiElement
> statementsToRemove
;
235 private Initializer(PsiStatement initializer
, Set
<PsiField
> movedFieldsUsed
, Set
<PsiParameter
> usedParameters
, List
<PsiElement
> statementsToRemove
) {
236 this.initializer
= initializer
;
237 this.movedFieldsUsed
= movedFieldsUsed
;
238 this.statementsToRemove
= statementsToRemove
;
239 this.usedParameters
= usedParameters
;
243 private void tryToMoveInitializers(PsiMethod constructor
, HashSet
<PsiMethod
> subConstructors
, LinkedHashSet
<PsiField
> movedFields
) throws IncorrectOperationException
{
244 final LinkedHashMap
<PsiField
, Initializer
> fieldsToInitializers
= new LinkedHashMap
<PsiField
, Initializer
>();
245 boolean anyFound
= false;
247 for (PsiField field
: movedFields
) {
248 PsiStatement commonInitializer
= null;
249 final ArrayList
<PsiElement
> fieldInitializersToRemove
= new ArrayList
<PsiElement
>();
250 for (PsiMethod subConstructor
: subConstructors
) {
251 commonInitializer
= hasCommonInitializer(commonInitializer
, subConstructor
, field
, fieldInitializersToRemove
);
252 if (commonInitializer
== null) break;
254 if (commonInitializer
!= null) {
255 final ParametersAndMovedFieldsUsedCollector visitor
= new ParametersAndMovedFieldsUsedCollector(movedFields
);
256 commonInitializer
.accept(visitor
);
257 fieldsToInitializers
.put(field
, new Initializer(commonInitializer
,
258 visitor
.getUsedFields(), visitor
.getUsedParameters(), fieldInitializersToRemove
));
263 if (!anyFound
) return;
268 final Set
<PsiField
> initializedFields
= fieldsToInitializers
.keySet();
269 Set
<PsiField
> unmovable
= RefactoringUtil
.transitiveClosure(
270 new RefactoringUtil
.Graph
<PsiField
>() {
271 public Set
<PsiField
> getVertices() {
272 return initializedFields
;
275 public Set
<PsiField
> getTargets(PsiField source
) {
276 return fieldsToInitializers
.get(source
).movedFieldsUsed
;
279 new Condition
<PsiField
>() {
280 public boolean value(PsiField object
) {
281 return !initializedFields
.contains(object
);
286 for (PsiField psiField
: unmovable
) {
287 fieldsToInitializers
.remove(psiField
);
291 final PsiElementFactory factory
= JavaPsiFacade
.getInstance(myManager
.getProject()).getElementFactory();
293 if (constructor
== null) {
294 constructor
= (PsiMethod
) myTargetSuperClass
.add(factory
.createConstructor());
295 final String visibilityModifier
= VisibilityUtil
.getVisibilityModifier(myTargetSuperClass
.getModifierList());
296 PsiUtil
.setModifierProperty(constructor
, visibilityModifier
, true);
300 ArrayList
<PsiField
> initializedFields
= new ArrayList
<PsiField
>(fieldsToInitializers
.keySet());
302 Collections
.sort(initializedFields
, new Comparator
<PsiField
>() {
303 public int compare(PsiField field1
, PsiField field2
) {
304 Initializer i1
= fieldsToInitializers
.get(field1
);
305 Initializer i2
= fieldsToInitializers
.get(field2
);
306 if(i1
.movedFieldsUsed
.contains(field2
)) return 1;
307 if(i2
.movedFieldsUsed
.contains(field1
)) return -1;
312 for (final PsiField initializedField
: initializedFields
) {
313 Initializer initializer
= fieldsToInitializers
.get(initializedField
);
315 //correct constructor parameters and subConstructors super calls
316 final PsiParameterList parameterList
= constructor
.getParameterList();
317 for (final PsiParameter parameter
: initializer
.usedParameters
) {
318 parameterList
.add(parameter
);
321 for (final PsiMethod subConstructor
: subConstructors
) {
322 modifySuperCall(subConstructor
, initializer
.usedParameters
);
325 PsiStatement assignmentStatement
= (PsiStatement
)constructor
.getBody().add(initializer
.initializer
);
327 ChangeContextUtil
.decodeContextInfo(assignmentStatement
,
328 myTargetSuperClass
, RefactoringUtil
.createThisExpression(myManager
, null));
329 for (PsiElement psiElement
: initializer
.statementsToRemove
) {
335 private static void modifySuperCall(final PsiMethod subConstructor
, final Set
<PsiParameter
> parametersToPassToSuper
) {
336 final PsiCodeBlock body
= subConstructor
.getBody();
338 PsiMethodCallExpression superCall
= null;
339 final PsiStatement
[] statements
= body
.getStatements();
340 if (statements
.length
> 0) {
341 if (statements
[0] instanceof PsiExpressionStatement
) {
342 final PsiExpression expression
= ((PsiExpressionStatement
)statements
[0]).getExpression();
343 if (expression
instanceof PsiMethodCallExpression
) {
344 final PsiMethodCallExpression methodCall
= (PsiMethodCallExpression
)expression
;
345 if ("super".equals(methodCall
.getMethodExpression().getText())) {
346 superCall
= methodCall
;
352 final PsiElementFactory factory
= JavaPsiFacade
.getInstance(subConstructor
.getProject()).getElementFactory();
354 if (superCall
== null) {
355 PsiExpressionStatement statement
=
356 (PsiExpressionStatement
)factory
.createStatementFromText("super();", null);
357 statement
= (PsiExpressionStatement
)body
.addAfter(statement
, null);
358 superCall
= (PsiMethodCallExpression
)statement
.getExpression();
361 final PsiExpressionList argList
= superCall
.getArgumentList();
362 for (final PsiParameter parameter
: parametersToPassToSuper
) {
363 argList
.add(factory
.createExpressionFromText(parameter
.getName(), null));
366 catch (IncorrectOperationException e
) {
373 private PsiStatement
hasCommonInitializer(PsiStatement commonInitializer
, PsiMethod subConstructor
, PsiField field
, ArrayList
<PsiElement
> statementsToRemove
) {
374 final PsiCodeBlock body
= subConstructor
.getBody();
375 if (body
== null) return null;
376 final PsiStatement
[] statements
= body
.getStatements();
378 // Algorithm: there should be only one write usage of field in a subConstructor,
379 // and in that usage field must be a target of top-level assignment, and RHS of assignment
380 // should be the same as commonInitializer if latter is non-null.
382 // There should be no usages before that initializer, and there should be
383 // no write usages afterwards.
384 PsiStatement commonInitializerCandidate
= null;
385 for (PsiStatement statement
: statements
) {
386 final HashSet
<PsiStatement
> collectedStatements
= new HashSet
<PsiStatement
>();
387 collectPsiStatements(statement
, collectedStatements
);
388 boolean doLookup
= true;
389 for (PsiStatement collectedStatement
: collectedStatements
) {
390 if (collectedStatement
instanceof PsiExpressionStatement
) {
391 final PsiExpression expression
= ((PsiExpressionStatement
)collectedStatement
).getExpression();
392 if (expression
instanceof PsiAssignmentExpression
) {
393 final PsiAssignmentExpression assignmentExpression
= (PsiAssignmentExpression
)expression
;
394 final PsiExpression lExpression
= assignmentExpression
.getLExpression();
395 if (lExpression
instanceof PsiReferenceExpression
) {
396 final PsiReferenceExpression lRef
= (PsiReferenceExpression
)lExpression
;
397 if (lRef
.getQualifierExpression() == null || lRef
.getQualifierExpression() instanceof PsiThisExpression
) {
398 final PsiElement resolved
= lRef
.resolve();
399 if (resolved
== field
) {
401 if (commonInitializerCandidate
== null) {
402 final PsiExpression initializer
= assignmentExpression
.getRExpression();
403 if (initializer
== null) return null;
404 if (commonInitializer
== null) {
405 final IsMovableInitializerVisitor visitor
= new IsMovableInitializerVisitor();
406 statement
.accept(visitor
);
407 if (visitor
.isMovable()) {
408 ChangeContextUtil
.encodeContextInfo(statement
, true);
409 PsiStatement statementCopy
= (PsiStatement
)statement
.copy();
410 ChangeContextUtil
.clearContextInfo(statement
);
411 statementsToRemove
.add(statement
);
412 commonInitializerCandidate
= statementCopy
;
419 if (PsiEquivalenceUtil
.areElementsEquivalent(commonInitializer
, statement
)) {
420 statementsToRemove
.add(statement
);
421 commonInitializerCandidate
= commonInitializer
;
428 else if (!PsiEquivalenceUtil
.areElementsEquivalent(commonInitializerCandidate
, statement
)){
438 final PsiReference
[] references
=
439 ReferencesSearch
.search(field
, new LocalSearchScope(statement
), false).toArray(new PsiReference
[0]);
440 if (commonInitializerCandidate
== null && references
.length
> 0) {
444 for (PsiReference reference
: references
) {
445 if (RefactoringUtil
.isAssignmentLHS(reference
.getElement())) return null;
449 return commonInitializerCandidate
;
452 private static void collectPsiStatements(PsiElement root
, Set
<PsiStatement
> collected
) {
453 if (root
instanceof PsiStatement
){
454 collected
.add((PsiStatement
)root
);
457 for (PsiElement element
: root
.getChildren()) {
458 collectPsiStatements(element
, collected
);
462 private static class ParametersAndMovedFieldsUsedCollector
extends JavaRecursiveElementWalkingVisitor
{
463 private final Set
<PsiField
> myMovedFields
;
464 private final Set
<PsiField
> myUsedFields
;
466 private final Set
<PsiParameter
> myUsedParameters
= new HashSet
<PsiParameter
>();
468 private ParametersAndMovedFieldsUsedCollector(HashSet
<PsiField
> movedFields
) {
469 myMovedFields
= movedFields
;
470 myUsedFields
= new HashSet
<PsiField
>();
473 public Set
<PsiParameter
> getUsedParameters() {
474 return myUsedParameters
;
477 public Set
<PsiField
> getUsedFields() {
481 @Override public void visitReferenceExpression(PsiReferenceExpression expression
) {
482 final PsiExpression qualifierExpression
= expression
.getQualifierExpression();
483 if (qualifierExpression
!= null
484 && !(qualifierExpression
instanceof PsiThisExpression
)) {
487 final PsiElement resolved
= expression
.resolve();
488 if (resolved
instanceof PsiParameter
) {
489 myUsedParameters
.add((PsiParameter
)resolved
);
490 } else if (myMovedFields
.contains(resolved
)) {
491 myUsedFields
.add((PsiField
)resolved
);
496 private class IsMovableInitializerVisitor
extends JavaRecursiveElementWalkingVisitor
{
497 private boolean myIsMovable
= true;
499 public boolean isMovable() {
503 @Override public void visitReferenceExpression(PsiReferenceExpression expression
) {
504 visitReferenceElement(expression
);
507 @Override public void visitReferenceElement(PsiJavaCodeReferenceElement referenceElement
) {
508 if (!myIsMovable
) return;
509 final PsiExpression qualifier
;
510 if (referenceElement
instanceof PsiReferenceExpression
) {
511 qualifier
= ((PsiReferenceExpression
) referenceElement
).getQualifierExpression();
515 if (qualifier
== null || qualifier
instanceof PsiThisExpression
|| qualifier
instanceof PsiSuperExpression
) {
516 final PsiElement resolved
= referenceElement
.resolve();
517 if (!(resolved
instanceof PsiParameter
)) {
518 if (resolved
instanceof PsiClass
&& (((PsiClass
) resolved
).hasModifierProperty(PsiModifier
.STATIC
) || ((PsiClass
)resolved
).getContainingClass() == null)) {
521 PsiClass containingClass
= null;
522 if (resolved
instanceof PsiMember
&& !((PsiMember
)resolved
).hasModifierProperty(PsiModifier
.STATIC
)) {
523 containingClass
= ((PsiMember
) resolved
).getContainingClass();
525 myIsMovable
= containingClass
!= null && InheritanceUtil
.isInheritorOrSelf(myTargetSuperClass
, containingClass
, true);
528 qualifier
.accept(this);
532 @Override public void visitElement(PsiElement element
) {
534 super.visitElement(element
);
539 private HashMap
<PsiMethod
,HashSet
<PsiMethod
>> buildConstructorsToSubConstructorsMap(final PsiMethod
[] constructors
) {
540 final HashMap
<PsiMethod
,HashSet
<PsiMethod
>> constructorsToSubConstructors
= new HashMap
<PsiMethod
, HashSet
<PsiMethod
>>();
541 for (PsiMethod constructor
: constructors
) {
542 final HashSet
<PsiMethod
> referencingSubConstructors
= new HashSet
<PsiMethod
>();
543 constructorsToSubConstructors
.put(constructor
, referencingSubConstructors
);
544 if (constructor
!= null) {
546 for (PsiReference reference
: ReferencesSearch
.search(constructor
, new LocalSearchScope(mySourceClass
), false)) {
547 final PsiElement element
= reference
.getElement();
548 if (element
!= null && "super".equals(element
.getText())) {
549 PsiMethod parentMethod
= PsiTreeUtil
.getParentOfType(element
, PsiMethod
.class);
550 if (parentMethod
!= null && parentMethod
.isConstructor()) {
551 referencingSubConstructors
.add(parentMethod
);
557 // check default constructor
558 if (constructor
== null || constructor
.getParameterList().getParametersCount() == 0) {
559 RefactoringUtil
.visitImplicitSuperConstructorUsages(mySourceClass
, new RefactoringUtil
.ImplicitConstructorUsageVisitor() {
560 public void visitConstructor(PsiMethod constructor
, PsiMethod baseConstructor
) {
561 referencingSubConstructors
.add(constructor
);
564 public void visitClassWithoutConstructors(PsiClass aClass
) {
566 }, myTargetSuperClass
);
570 return constructorsToSubConstructors
;
573 private void fixReferencesToStatic(PsiElement classMember
, Set
<PsiMember
> movedMembers
) throws IncorrectOperationException
{
574 StaticReferencesCollector collector
= new StaticReferencesCollector(movedMembers
);
575 classMember
.accept(collector
);
576 ArrayList
<PsiJavaCodeReferenceElement
> refs
= collector
.getReferences();
577 ArrayList
<PsiElement
> members
= collector
.getReferees();
578 ArrayList
<PsiClass
> classes
= collector
.getRefereeClasses();
579 PsiElementFactory factory
= JavaPsiFacade
.getInstance(classMember
.getProject()).getElementFactory();
581 for (int i
= 0; i
< refs
.size(); i
++) {
582 PsiJavaCodeReferenceElement ref
= refs
.get(i
);
583 PsiElement namedElement
= members
.get(i
);
584 PsiClass aClass
= classes
.get(i
);
586 if (namedElement
instanceof PsiNamedElement
) {
587 PsiReferenceExpression newRef
=
588 (PsiReferenceExpression
) factory
.createExpressionFromText
589 ("a." + ((PsiNamedElement
) namedElement
).getName(),
591 final PsiExpression qualifierExpression
= newRef
.getQualifierExpression();
592 assert qualifierExpression
!= null;
593 qualifierExpression
.replace(factory
.createReferenceExpression(aClass
));
599 private class StaticReferencesCollector
extends ClassMemberReferencesVisitor
{
600 ArrayList
<PsiJavaCodeReferenceElement
> myReferences
;
601 ArrayList
<PsiElement
> myReferees
;
602 ArrayList
<PsiClass
> myRefereeClasses
;
603 private final Set
<PsiMember
> myMovedMembers
;
605 private StaticReferencesCollector(Set
<PsiMember
> movedMembers
) {
606 super(mySourceClass
);
607 myMovedMembers
= movedMembers
;
608 myReferees
= new ArrayList
<PsiElement
>();
609 myRefereeClasses
= new ArrayList
<PsiClass
>();
610 myReferences
= new ArrayList
<PsiJavaCodeReferenceElement
>();
613 public ArrayList
<PsiElement
> getReferees() {
617 public ArrayList
<PsiClass
> getRefereeClasses() {
618 return myRefereeClasses
;
621 public ArrayList
<PsiJavaCodeReferenceElement
> getReferences() {
625 protected void visitClassMemberReferenceElement(PsiMember classMember
, PsiJavaCodeReferenceElement classMemberReference
) {
626 if (classMember
instanceof PsiClass
) return;
627 if (classMember
.hasModifierProperty(PsiModifier
.STATIC
)) {
628 if (!myMovedMembers
.contains(classMember
) &&
629 RefactoringHierarchyUtil
.isMemberBetween(myTargetSuperClass
, mySourceClass
, classMember
)) {
630 myReferences
.add(classMemberReference
);
631 myReferees
.add(classMember
);
632 myRefereeClasses
.add(classMember
.getContainingClass());
634 else if ((myMovedMembers
.contains(classMember
) || myMembersAfterMove
.contains(classMember
)) && classMemberReference
.isQualified()) {
635 myReferences
.add(classMemberReference
);
636 myReferees
.add(classMember
);
637 myRefereeClasses
.add(myTargetSuperClass
);
643 private class QualifiedThisSuperAdjuster
extends JavaRecursiveElementVisitor
{
644 @Override public void visitThisExpression(PsiThisExpression expression
) {
645 super.visitThisExpression(expression
);
646 final PsiJavaCodeReferenceElement qualifier
= expression
.getQualifier();
647 if (qualifier
!= null && qualifier
.isReferenceTo(mySourceClass
)) {
649 qualifier
.bindToElement(myTargetSuperClass
);
651 catch (IncorrectOperationException e
) {
657 @Override public void visitSuperExpression(PsiSuperExpression expression
) {
658 super.visitSuperExpression(expression
);
659 final PsiJavaCodeReferenceElement qualifier
= expression
.getQualifier();
660 if (qualifier
!= null && qualifier
.isReferenceTo(mySourceClass
)) {
662 expression
.replace(JavaPsiFacade
.getInstance(myManager
.getProject()).getElementFactory().createExpressionFromText(myTargetSuperClass
.getName() + ".this", null));
664 catch (IncorrectOperationException e
) {
671 private class ExplicitSuperDeleter
extends JavaRecursiveElementWalkingVisitor
{
672 private final ArrayList
<PsiExpression
> mySupersToDelete
= new ArrayList
<PsiExpression
>();
673 private final ArrayList
<PsiSuperExpression
> mySupersToChangeToThis
= new ArrayList
<PsiSuperExpression
>();
675 @Override public void visitReferenceExpression(PsiReferenceExpression expression
) {
676 if(expression
.getQualifierExpression() instanceof PsiSuperExpression
) {
677 PsiElement resolved
= expression
.resolve();
678 if (resolved
== null || resolved
instanceof PsiMethod
&& shouldFixSuper((PsiMethod
) resolved
)) {
679 mySupersToDelete
.add(expression
.getQualifierExpression());
684 @Override public void visitSuperExpression(PsiSuperExpression expression
) {
685 mySupersToChangeToThis
.add(expression
);
688 @Override public void visitClass(PsiClass aClass
) {
692 private boolean shouldFixSuper(PsiMethod method
) {
693 for (PsiMember element
: myMembersAfterMove
) {
694 if (element
instanceof PsiMethod
) {
695 PsiMethod member
= (PsiMethod
)element
;
696 // if there is such member among moved members, super qualifier
697 // should not be removed
698 final PsiManager manager
= method
.getManager();
699 if (manager
.areElementsEquivalent(member
.getContainingClass(), method
.getContainingClass()) &&
700 MethodSignatureUtil
.areSignaturesEqual(member
, method
)) {
706 final PsiMethod methodFromSuper
= myTargetSuperClass
.findMethodBySignature(method
, false);
707 return methodFromSuper
== null;
710 public void fixSupers() throws IncorrectOperationException
{
711 final PsiElementFactory factory
= JavaPsiFacade
.getInstance(myManager
.getProject()).getElementFactory();
712 PsiThisExpression thisExpression
= (PsiThisExpression
) factory
.createExpressionFromText("this", null);
713 for (PsiExpression psiExpression
: mySupersToDelete
) {
714 psiExpression
.delete();
717 for (PsiSuperExpression psiSuperExpression
: mySupersToChangeToThis
) {
718 psiSuperExpression
.replace(thisExpression
);
723 private static boolean willBeUsedInSubclass(PsiElement member
, Set
<PsiMember
> movedMembers
, PsiClass superclass
, PsiClass subclass
) {
724 for (PsiReference ref
: ReferencesSearch
.search(member
, new LocalSearchScope(subclass
), false)) {
725 PsiElement element
= ref
.getElement();
726 if (!RefactoringHierarchyUtil
.willBeInTargetClass(element
, movedMembers
, superclass
, false)) {
733 public static boolean checkedInterfacesContain(Collection
<MemberInfo
> memberInfos
, PsiMethod psiMethod
) {
734 for (MemberInfo memberInfo
: memberInfos
) {
735 if (memberInfo
.isChecked() &&
736 memberInfo
.getMember() instanceof PsiClass
&&
737 Boolean
.FALSE
.equals(memberInfo
.getOverrides())) {
738 if (((PsiClass
)memberInfo
.getMember()).findMethodBySignature(psiMethod
, true) != null) {