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.
16 package com
.intellij
.refactoring
.move
.moveMembers
;
18 import com
.intellij
.codeInsight
.ChangeContextUtil
;
19 import com
.intellij
.psi
.*;
20 import com
.intellij
.psi
.search
.LocalSearchScope
;
21 import com
.intellij
.psi
.search
.searches
.ReferencesSearch
;
22 import com
.intellij
.psi
.util
.PsiTreeUtil
;
23 import com
.intellij
.psi
.util
.PsiUtilBase
;
24 import com
.intellij
.refactoring
.util
.EnumConstantsUtil
;
25 import com
.intellij
.refactoring
.util
.RefactoringConflictsUtil
;
26 import com
.intellij
.refactoring
.util
.RefactoringHierarchyUtil
;
27 import com
.intellij
.refactoring
.util
.RefactoringUtil
;
28 import com
.intellij
.util
.IncorrectOperationException
;
29 import com
.intellij
.util
.VisibilityUtil
;
30 import org
.jetbrains
.annotations
.Nullable
;
35 * @author Maxim.Medvedev
38 public class MoveJavaMemberHandler
implements MoveMemberHandler
{
39 public MoveMembersProcessor
.MoveMembersUsageInfo
getUsage(PsiMember member
,
40 PsiReference psiReference
,
41 Set
<PsiMember
> membersToMove
,
42 PsiClass targetClass
) {
43 PsiElement ref
= psiReference
.getElement();
44 if (ref
instanceof PsiReferenceExpression
) {
45 PsiReferenceExpression refExpr
= (PsiReferenceExpression
)ref
;
46 PsiExpression qualifier
= refExpr
.getQualifierExpression();
47 if (RefactoringHierarchyUtil
.willBeInTargetClass(refExpr
, membersToMove
, targetClass
, true)) {
48 // both member and the reference to it will be in target class
49 if (!isInMovedElement(refExpr
, membersToMove
)) {
50 if (qualifier
!= null) {
51 return new MoveMembersProcessor
.MoveMembersUsageInfo(member
, refExpr
, null, qualifier
, psiReference
); // remove qualifier
55 if (qualifier
instanceof PsiReferenceExpression
&&
56 ((PsiReferenceExpression
)qualifier
).isReferenceTo(member
.getContainingClass())) {
57 return new MoveMembersProcessor
.MoveMembersUsageInfo(member
, refExpr
, null, qualifier
, psiReference
); // change qualifier
62 // member in target class, the reference will be outside target class
63 if (qualifier
== null) {
64 return new MoveMembersProcessor
.MoveMembersUsageInfo(member
, refExpr
, targetClass
, refExpr
, psiReference
); // add qualifier
67 return new MoveMembersProcessor
.MoveMembersUsageInfo(member
, refExpr
, targetClass
, qualifier
, psiReference
); // change qualifier
74 private boolean isInMovedElement(PsiElement element
, Set
<PsiMember
> membersToMove
) {
75 for (PsiMember member
: membersToMove
) {
76 if (PsiTreeUtil
.isAncestor(member
, element
, false)) return true;
81 public boolean changeExternalUsage(MoveMembersOptions options
, MoveMembersProcessor
.MoveMembersUsageInfo usage
) {
82 if (!usage
.getElement().isValid()) return true;
84 if (usage
.reference
instanceof PsiReferenceExpression
) {
85 PsiReferenceExpression refExpr
= (PsiReferenceExpression
)usage
.reference
;
86 PsiExpression qualifier
= refExpr
.getQualifierExpression();
87 if (qualifier
!= null) {
88 if (usage
.qualifierClass
!= null) {
89 changeQualifier(refExpr
, usage
.qualifierClass
);
92 refExpr
.setQualifierExpression(null);
95 else { // no qualifier
96 if (usage
.qualifierClass
!= null) {
97 changeQualifier(refExpr
, usage
.qualifierClass
);
105 public PsiMember
doMove(MoveMembersOptions options
, PsiMember member
, PsiElement anchor
, PsiClass targetClass
) {
106 if (member
instanceof PsiVariable
) {
107 ((PsiVariable
)member
).normalizeDeclaration();
110 ChangeContextUtil
.encodeContextInfo(member
, true);
111 if (targetClass
== null) return null;
114 final PsiMember memberCopy
;
115 if (options
.makeEnumConstant() &&
116 member
instanceof PsiVariable
&&
117 EnumConstantsUtil
.isSuitableForEnumConstant(((PsiVariable
)member
).getType(), targetClass
)) {
118 memberCopy
= EnumConstantsUtil
.createEnumConstant(targetClass
, member
.getName(), ((PsiVariable
)member
).getInitializer());
121 memberCopy
= (PsiMember
)member
.copy();
122 if (member
.getContainingClass().isInterface() && !targetClass
.isInterface()) {
123 //might need to make modifiers explicit, see IDEADEV-11416
124 final PsiModifierList list
= memberCopy
.getModifierList();
126 list
.setModifierProperty(PsiModifier
.STATIC
, member
.hasModifierProperty(PsiModifier
.STATIC
));
127 list
.setModifierProperty(PsiModifier
.FINAL
, member
.hasModifierProperty(PsiModifier
.FINAL
));
128 RefactoringConflictsUtil
.setVisibility(list
, VisibilityUtil
.getVisibilityModifier(member
.getModifierList()));
132 return anchor
!= null ?
(PsiMember
)targetClass
.addAfter(memberCopy
, anchor
) : (PsiMember
)targetClass
.add(memberCopy
);
135 public void decodeContextInfo(PsiElement scope
) {
136 ChangeContextUtil
.decodeContextInfo(scope
, null, null);
139 private void changeQualifier(PsiReferenceExpression refExpr
, PsiClass aClass
) throws IncorrectOperationException
{
140 if (RefactoringUtil
.hasOnDemandStaticImport(refExpr
, aClass
)) {
141 refExpr
.setQualifierExpression(null);
144 PsiElementFactory factory
= JavaPsiFacade
.getInstance(refExpr
.getProject()).getElementFactory();
145 refExpr
.setQualifierExpression(factory
.createReferenceExpression(aClass
));
150 public PsiElement
getAnchor(final PsiMember member
, final PsiClass targetClass
) {
151 if (member
instanceof PsiField
&& member
.hasModifierProperty(PsiModifier
.STATIC
)) {
152 final List
<PsiField
> afterFields
= new ArrayList
<PsiField
>();
153 final PsiExpression psiExpression
= ((PsiField
)member
).getInitializer();
154 if (psiExpression
!= null) {
155 psiExpression
.accept(new JavaRecursiveElementWalkingVisitor() {
157 public void visitReferenceExpression(final PsiReferenceExpression expression
) {
158 super.visitReferenceExpression(expression
);
159 final PsiElement psiElement
= expression
.resolve();
160 if (psiElement
instanceof PsiField
) {
161 final PsiField psiField
= (PsiField
)psiElement
;
162 if (psiField
.getContainingClass() == targetClass
&& !afterFields
.contains(psiField
)) {
163 afterFields
.add(psiField
);
170 final Comparator
<PsiField
> fieldComparator
= new Comparator
<PsiField
>() {
171 public int compare(final PsiField o1
, final PsiField o2
) {
172 return -PsiUtilBase
.compareElementsByPosition(o1
, o2
);
176 if (!afterFields
.isEmpty()) {
177 Collections
.sort(afterFields
, fieldComparator
);
178 return afterFields
.get(0);
181 final List
<PsiField
> beforeFields
= new ArrayList
<PsiField
>();
182 for (PsiReference psiReference
: ReferencesSearch
.search(member
, new LocalSearchScope(targetClass
))) {
183 final PsiField fieldWithReference
= PsiTreeUtil
.getParentOfType(psiReference
.getElement(), PsiField
.class);
184 if (fieldWithReference
!= null && !afterFields
.contains(fieldWithReference
)) {
185 beforeFields
.add(fieldWithReference
);
188 Collections
.sort(beforeFields
, fieldComparator
);
189 if (!beforeFields
.isEmpty()) {
190 return beforeFields
.get(0).getPrevSibling();