move members: calc anchor before references become invalid (IDEADEV-39996)

This commit is contained in:
Anna Kozlova
2009-09-02 15:51:18 +04:00
parent 80bc5baf5c
commit c6cc0a17bb
8 changed files with 70 additions and 27 deletions
@@ -2,14 +2,15 @@ package com.intellij.refactoring.move.moveMembers;
import com.intellij.codeInsight.ChangeContextUtil;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiUtilBase;
import com.intellij.psi.search.LocalSearchScope;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtilBase;
import com.intellij.refactoring.util.EnumConstantsUtil;
import com.intellij.refactoring.util.RefactoringUtil;
import com.intellij.util.VisibilityUtil;
import com.intellij.refactoring.util.RefactoringHierarchyUtil;
import com.intellij.refactoring.util.RefactoringUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.VisibilityUtil;
import org.jetbrains.annotations.Nullable;
import java.util.*;
@@ -85,16 +86,14 @@ public class MoveJavaMemberHandler implements MoveMemberHandler {
return false;
}
public PsiMember doMove(MoveMembersOptions options, PsiMember member, ArrayList<MoveMembersProcessor.MoveMembersUsageInfo> otherUsages) {
public PsiMember doMove(MoveMembersOptions options, PsiMember member, PsiElement anchor, PsiClass targetClass) {
if (member instanceof PsiVariable) {
((PsiVariable)member).normalizeDeclaration();
}
PsiClass targetClass = JavaPsiFacade.getInstance(member.getManager().getProject())
.findClass(options.getTargetClassName(), GlobalSearchScope.projectScope(member.getProject()));
ChangeContextUtil.encodeContextInfo(member, true);
if (targetClass == null) return null;
PsiElement anchor = getAnchor(member, targetClass);
final PsiMember memberCopy;
if (options.makeEnumConstant() &&
@@ -132,9 +131,9 @@ public class MoveJavaMemberHandler implements MoveMemberHandler {
}
@Nullable
private static PsiElement getAnchor(final PsiMember member, final PsiClass targetClass) {
public PsiElement getAnchor(final PsiMember member, final PsiClass targetClass) {
if (member instanceof PsiField && member.hasModifierProperty(PsiModifier.STATIC)) {
final List<PsiField> referencedFields = new ArrayList<PsiField>();
final List<PsiField> afterFields = new ArrayList<PsiField>();
final PsiExpression psiExpression = ((PsiField)member).getInitializer();
if (psiExpression != null) {
psiExpression.accept(new JavaRecursiveElementWalkingVisitor() {
@@ -144,20 +143,35 @@ public class MoveJavaMemberHandler implements MoveMemberHandler {
final PsiElement psiElement = expression.resolve();
if (psiElement instanceof PsiField) {
final PsiField psiField = (PsiField)psiElement;
if (psiField.getContainingClass() == targetClass && !referencedFields.contains(psiField)) {
referencedFields.add(psiField);
if (psiField.getContainingClass() == targetClass && !afterFields.contains(psiField)) {
afterFields.add(psiField);
}
}
}
});
}
if (!referencedFields.isEmpty()) {
Collections.sort(referencedFields, new Comparator<PsiField>() {
public int compare(final PsiField o1, final PsiField o2) {
return -PsiUtilBase.compareElementsByPosition(o1, o2);
}
});
return referencedFields.get(0);
final Comparator<PsiField> fieldComparator = new Comparator<PsiField>() {
public int compare(final PsiField o1, final PsiField o2) {
return -PsiUtilBase.compareElementsByPosition(o1, o2);
}
};
if (!afterFields.isEmpty()) {
Collections.sort(afterFields, fieldComparator);
return afterFields.get(0);
}
final List<PsiField> beforeFields = new ArrayList<PsiField>();
for (PsiReference psiReference : ReferencesSearch.search(member, new LocalSearchScope(targetClass))) {
final PsiField fieldWithReference = PsiTreeUtil.getParentOfType(psiReference.getElement(), PsiField.class);
if (fieldWithReference != null && !afterFields.contains(fieldWithReference)) {
beforeFields.add(fieldWithReference);
}
}
Collections.sort(beforeFields, fieldComparator);
if (!beforeFields.isEmpty()) {
return beforeFields.get(0).getPrevSibling();
}
}
return null;
@@ -1,13 +1,14 @@
package com.intellij.refactoring.move.moveMembers;
import com.intellij.lang.LanguageExtension;
import com.intellij.psi.*;
import java.util.ArrayList;
import java.util.Set;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiMember;
import com.intellij.psi.PsiReference;
import org.jetbrains.annotations.Nullable;
import java.util.Set;
/**
* @author Maxim.Medvedev
*/
@@ -21,7 +22,10 @@ public interface MoveMemberHandler {
boolean changeExternalUsage(MoveMembersOptions options, MoveMembersProcessor.MoveMembersUsageInfo usage);
PsiMember doMove(MoveMembersOptions options, PsiMember member, ArrayList<MoveMembersProcessor.MoveMembersUsageInfo> otherUsages);
PsiMember doMove(MoveMembersOptions options, PsiMember member, PsiElement anchor, PsiClass targetClass);
void decodeContextInfo(PsiElement scope);
@Nullable
PsiElement getAnchor(PsiMember member, PsiClass targetClass);
}
@@ -139,7 +139,13 @@ public class MoveMembersProcessor extends BaseRefactoringProcessor {
try {
// correct references to moved members from the outside
LanguageExtension<MoveMemberHandler> extension=new LanguageExtension<MoveMemberHandler>("com.intellij.refactoring.moveMemberHandler");
PsiClass targetClass = JavaPsiFacade.getInstance(myProject)
.findClass(myOptions.getTargetClassName(), GlobalSearchScope.projectScope(myProject));
if (targetClass == null) return;
final Map<PsiMember, PsiElement> anchors = new HashMap<PsiMember, PsiElement>();
for (PsiMember member : myMembersToMove) {
anchors.put(member, extension.forLanguage(member.getLanguage()).getAnchor(member, targetClass));
}
ArrayList<MoveMembersUsageInfo> otherUsages = new ArrayList<MoveMembersUsageInfo>();
for (UsageInfo usageInfo : usages) {
MoveMembersUsageInfo usage = (MoveMembersUsageInfo)usageInfo;
@@ -166,7 +172,7 @@ public class MoveMembersProcessor extends BaseRefactoringProcessor {
}
final RefactoringElementListener elementListener = getTransaction().getElementListener(member);
final MoveMemberHandler handler = extension.forLanguage(member.getLanguage());
PsiMember newMember=handler.doMove(myOptions, member, otherUsages);
PsiMember newMember=handler.doMove(myOptions, member, anchors.get(member), targetClass);
elementListener.elementMoved(newMember);
fixVisibility(newMember, usages);
@@ -74,6 +74,10 @@ public class MoveMembersTest extends MultiFileTestCase {
doTest("B", "A", 0);
}
public void testDependantFields() throws Exception {
doTest("B", "A", 0);
}
protected String getTestRoot() {
return "/refactoring/moveMembers/";
}
@@ -0,0 +1,6 @@
public class A {
void foo(){}
public static final String ONE = "";
public static final String TWO = ONE + "";
}
@@ -0,0 +1,2 @@
public class B {
}
@@ -0,0 +1,4 @@
public class A {
void foo(){}
public static final String TWO = B.ONE + "";
}
@@ -0,0 +1,3 @@
public class B {
public static final String ONE = "";
}