mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
move members: calc anchor before references become invalid (IDEADEV-39996)
This commit is contained in:
+33
-19
@@ -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;
|
||||
|
||||
+10
-6
@@ -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);
|
||||
}
|
||||
|
||||
+8
-2
@@ -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 = "";
|
||||
}
|
||||
Reference in New Issue
Block a user