update copyright
[fedora-idea.git] / java / java-impl / src / com / intellij / refactoring / move / moveMembers / MoveJavaMemberHandler.java
blobb3e99edc2b9306c1060f5feea5f33b29faaa6d04
1 /*
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;
32 import java.util.*;
34 /**
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
54 else {
55 if (qualifier instanceof PsiReferenceExpression &&
56 ((PsiReferenceExpression)qualifier).isReferenceTo(member.getContainingClass())) {
57 return new MoveMembersProcessor.MoveMembersUsageInfo(member, refExpr, null, qualifier, psiReference); // change qualifier
61 else {
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
66 else {
67 return new MoveMembersProcessor.MoveMembersUsageInfo(member, refExpr, targetClass, qualifier, psiReference); // change qualifier
71 return null;
74 private boolean isInMovedElement(PsiElement element, Set<PsiMember> membersToMove) {
75 for (PsiMember member : membersToMove) {
76 if (PsiTreeUtil.isAncestor(member, element, false)) return true;
78 return false;
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);
91 else {
92 refExpr.setQualifierExpression(null);
95 else { // no qualifier
96 if (usage.qualifierClass != null) {
97 changeQualifier(refExpr, usage.qualifierClass);
100 return true;
102 return false;
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());
120 else {
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();
125 assert list != null;
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()));
131 member.delete();
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);
143 else {
144 PsiElementFactory factory = JavaPsiFacade.getInstance(refExpr.getProject()).getElementFactory();
145 refExpr.setQualifierExpression(factory.createReferenceExpression(aClass));
149 @Nullable
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() {
156 @Override
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();
193 return null;