Fix Pull Up refactoring after removal of MethodElement#copyElement override

In some scenarios Pull Up worked correctly only by chance, thanks to incorrect resolve on copied method. However there are more scenarios, presented in new tests ReferencedStaticGenericClassFromOuterClass and ReferencedStaticMethodFromOuterClass, which did not work correctly even before. The fix addresses these cases.

GitOrigin-RevId: bd56ed851dd8bbf546dba2847535a98de1eea295
This commit is contained in:
Tagir Valeev
2019-11-12 04:40:55 +00:00
committed by intellij-monorepo-bot
parent f3f3e9eecb
commit 77517a3a3a
6 changed files with 84 additions and 14 deletions
@@ -100,16 +100,23 @@ public class JavaPullUpHelper implements PullUpHelper<MemberInfo> {
member.accept(new JavaRecursiveElementWalkingVisitor() {
@Override
public void visitReferenceExpression(PsiReferenceExpression expression) {
final PsiExpression qualifierExpression = expression.getQualifierExpression();
public void visitReferenceElement(PsiJavaCodeReferenceElement reference) {
final PsiElement qualifierExpression = reference.getQualifier();
if (qualifierExpression != null) {
final Boolean preserveQualifier = qualifierExpression.getCopyableUserData(PRESERVE_QUALIFIER);
if (preserveQualifier != null && !preserveQualifier) {
qualifierExpression.delete();
return;
PsiElement target = reference.resolve();
if (target != null) {
PsiJavaCodeReferenceElement copy = (PsiJavaCodeReferenceElement)reference.copy();
Objects.requireNonNull(copy.getQualifier()).delete();
if (copy.resolve() == target) {
qualifierExpression.delete();
return;
}
}
}
}
super.visitReferenceExpression(expression);
super.visitReferenceElement(reference);
}
});
@@ -686,15 +693,16 @@ public class JavaPullUpHelper implements PullUpHelper<MemberInfo> {
PsiClass aClass = classes.get(i);
if (namedElement instanceof PsiNamedElement) {
PsiReferenceExpression newRef =
(PsiReferenceExpression) factory.createExpressionFromText
("a." + ((PsiNamedElement) namedElement).getName(),
null);
PsiExpression qualifierExpression = newRef.getQualifierExpression();
assert qualifierExpression != null;
qualifierExpression = (PsiExpression)qualifierExpression.replace(factory.createReferenceExpression(aClass));
qualifierExpression.putCopyableUserData(PRESERVE_QUALIFIER, ref.isQualified());
ref.replace(newRef);
PsiElement oldQualifier = ref.getQualifier();
if (oldQualifier != null) {
oldQualifier.delete();
}
String template = aClass.getQualifiedName() + "." + ref.getText();
PsiJavaCodeReferenceElement newRef = ref instanceof PsiReferenceExpression ?
(PsiReferenceExpression)factory.createExpressionFromText(template, null) :
factory.createReferenceFromText(template, null);
ref = (PsiJavaCodeReferenceElement)ref.replace(newRef);
Objects.requireNonNull(ref.getQualifier()).putCopyableUserData(PRESERVE_QUALIFIER, oldQualifier != null);
}
}
}
@@ -0,0 +1,13 @@
class A extends C {
void <caret>foo() {
A.D<String> d = new A.D<>();
}
static class D<T> {
}
}
class C {
}
@@ -0,0 +1,14 @@
class A extends C {
}
class C {
void foo() {
C.D<String> d = new C.D<>();
}
static class D<T> {
}
}
@@ -0,0 +1,13 @@
class A {
static class B extends C {
void <caret>foo() {
bar();
}
}
static void bar() {}
}
class C {
}
@@ -0,0 +1,13 @@
class A {
static class B extends C {
}
static void bar() {}
}
class C {
void foo() {
A.bar();
}
}
@@ -160,6 +160,15 @@ public class PullUpTest extends LightRefactoringTestCase {
public void testTypeParamsConflictingNames() {
doTest(false, new RefactoringTestUtil.MemberDescriptor("foo", PsiMethod.class, true));
}
public void testReferencedStaticMethodFromOuterClass() {
doTest(false, new RefactoringTestUtil.MemberDescriptor("foo", PsiMethod.class, false));
}
public void testReferencedStaticGenericClassFromOuterClass() {
doTest(false, new RefactoringTestUtil.MemberDescriptor("foo", PsiMethod.class),
new RefactoringTestUtil.MemberDescriptor("D", PsiClass.class));
}
public void testConflictOnNewAbstractMethod() {
doTest(false, "Concrete 'class <b><code>C</code></b>' would inherit a new abstract method", new RefactoringTestUtil.MemberDescriptor("foo", PsiMethod.class));