pull up/push down: type parameters substitution should modify member copy (IDEA-53496)

This commit is contained in:
anna
2010-04-14 18:32:38 +04:00
parent 1d7db34dac
commit 04fdd69cc1
14 changed files with 86 additions and 20 deletions
@@ -106,9 +106,6 @@ public class PullUpHelper extends BaseRefactoringProcessor{
final HashSet<PsiMember> movedMembers = new HashSet<PsiMember>();
myMembersAfterMove = new HashSet<PsiMember>();
RefactoringUtil.replaceMovedMemberTypeParameters(myMembersToMove, PsiUtil.typeParametersIterable(mySourceClass),
upDownSuperClassSubstitutor(),
JavaPsiFacade.getElementFactory(myProject));
// build aux sets
for (MemberInfo info : myMembersToMove) {
movedMembers.add(info.getMember());
@@ -129,6 +126,9 @@ public class PullUpHelper extends BaseRefactoringProcessor{
ChangeContextUtil.encodeContextInfo(info.getMember(), true);
}
final PsiSubstitutor substitutor = upDownSuperClassSubstitutor();
final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(myProject);
// do actual move
for (MemberInfo info : myMembersToMove) {
if (info.getMember() instanceof PsiMethod) {
@@ -138,7 +138,7 @@ public class PullUpHelper extends BaseRefactoringProcessor{
PsiMethod methodCopy = (PsiMethod)method.copy();
ChangeContextUtil.clearContextInfo(method);
RefactoringUtil.abstractizeMethod(myTargetSuperClass, methodCopy);
RefactoringUtil.replaceMovedMemberTypeParameters(methodCopy, PsiUtil.typeParametersIterable(mySourceClass), substitutor, elementFactory);
if (method.findDeepestSuperMethods().length == 0 || (myTargetSuperClass.isInterface() && !PsiUtil.isLanguageLevel6OrHigher(mySourceClass))) {
deleteOverrideAnnotationIfFound(methodCopy);
}
@@ -169,6 +169,7 @@ public class PullUpHelper extends BaseRefactoringProcessor{
if (isOriginalMethodAbstract) {
PsiUtil.setModifierProperty(myTargetSuperClass, PsiModifier.ABSTRACT, true);
}
RefactoringUtil.replaceMovedMemberTypeParameters(method, PsiUtil.typeParametersIterable(mySourceClass), substitutor, elementFactory);
fixReferencesToStatic(method, movedMembers);
final PsiMethod superClassMethod = myTargetSuperClass.findMethodBySignature(method, false);
if (superClassMethod != null && superClassMethod.hasModifierProperty(PsiModifier.ABSTRACT)) {
@@ -184,6 +185,7 @@ public class PullUpHelper extends BaseRefactoringProcessor{
else if (info.getMember() instanceof PsiField) {
PsiField field = (PsiField)info.getMember();
field.normalizeDeclaration();
RefactoringUtil.replaceMovedMemberTypeParameters(field, PsiUtil.typeParametersIterable(mySourceClass), substitutor, elementFactory);
fixReferencesToStatic(field, movedMembers);
if (myIsTargetInterface) {
PsiUtil.setModifierProperty(field, PsiModifier.PUBLIC, true);
@@ -201,6 +203,7 @@ public class PullUpHelper extends BaseRefactoringProcessor{
RefactoringUtil.removeFromReferenceList(sourceReferenceList, aClass) :
RefactoringUtil.findReferenceToClass(sourceReferenceList, aClass);
if (ref != null) {
RefactoringUtil.replaceMovedMemberTypeParameters(ref, PsiUtil.typeParametersIterable(mySourceClass), substitutor, elementFactory);
final PsiReferenceList referenceList =
myTargetSuperClass.isInterface() ? myTargetSuperClass.getExtendsList() : myTargetSuperClass.getImplementsList();
assert referenceList != null;
@@ -208,6 +211,7 @@ public class PullUpHelper extends BaseRefactoringProcessor{
}
}
else {
RefactoringUtil.replaceMovedMemberTypeParameters(aClass, PsiUtil.typeParametersIterable(mySourceClass), substitutor, elementFactory);
fixReferencesToStatic(aClass, movedMembers);
final PsiMember movedElement = (PsiMember)myTargetSuperClass.add(aClass);
myMembersAfterMove.add(movedElement);
@@ -327,9 +327,8 @@ public class PushDownProcessor extends BaseRefactoringProcessor {
private void pushDownToClass(PsiClass targetClass) throws IncorrectOperationException {
final PsiElementFactory factory = JavaPsiFacade.getInstance(myClass.getProject()).getElementFactory();
final PsiSubstitutor substitutor = TypeConversionUtil.getSuperClassSubstitutor(myClass, targetClass, PsiSubstitutor.EMPTY);
RefactoringUtil.replaceMovedMemberTypeParameters(myMemberInfos, PsiUtil.typeParametersIterable(myClass), substitutor, factory);
for (MemberInfo memberInfo : myMemberInfos) {
final PsiMember member = memberInfo.getMember();
PsiMember member = memberInfo.getMember();
final List<PsiReference> refsToRebind = new ArrayList<PsiReference>();
final PsiModifierList list = member.getModifierList();
LOG.assertTrue(list != null);
@@ -345,7 +344,8 @@ public class PushDownProcessor extends BaseRefactoringProcessor {
refsToRebind.add(reference);
}
}
member = (PsiMember)member.copy();
RefactoringUtil.replaceMovedMemberTypeParameters(member, PsiUtil.typeParametersIterable(myClass), substitutor, factory);
PsiMember newMember = null;
if (member instanceof PsiField) {
((PsiField)member).normalizeDeclaration();
@@ -52,7 +52,6 @@ import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.refactoring.PackageWrapper;
import com.intellij.refactoring.introduceField.ElementToWorkOn;
import com.intellij.refactoring.introduceVariable.IntroduceVariableBase;
import com.intellij.refactoring.util.classMembers.MemberInfo;
import com.intellij.usageView.UsageInfo;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.HashMap;
@@ -857,23 +856,18 @@ public class RefactoringUtil {
return null;
}
public static void replaceMovedMemberTypeParameters(final MemberInfo[] memberInfos,
public static void replaceMovedMemberTypeParameters(final PsiElement member,
final Iterable<PsiTypeParameter> parametersIterable,
final PsiSubstitutor substitutor,
final PsiElementFactory factory) {
for (PsiTypeParameter parameter : parametersIterable) {
for (PsiReference reference : ReferencesSearch.search(parameter)) {
for (PsiReference reference : ReferencesSearch.search(parameter, new LocalSearchScope(member))) {
final PsiElement element = reference.getElement();
for (MemberInfo memberInfo : memberInfos) {
if (PsiTreeUtil.isAncestor(memberInfo.getMember(), element, false)) {
PsiType substitutedType = substitutor.substitute(parameter);
if (substitutedType == null) {
substitutedType = TypeConversionUtil.erasure(factory.createType(parameter));
}
element.getParent().replace(factory.createTypeElement(substitutedType));
break;
}
PsiType substitutedType = substitutor.substitute(parameter);
if (substitutedType == null) {
substitutedType = TypeConversionUtil.erasure(factory.createType(parameter));
}
element.getParent().replace(factory.createTypeElement(substitutedType));
}
}
}
@@ -0,0 +1,3 @@
class Test {
Integer t;
}
@@ -0,0 +1,3 @@
class Test1 {
String t;
}
@@ -0,0 +1,3 @@
class Super<T> {
T t;
}
@@ -0,0 +1,2 @@
class Test extends Super<Integer>{
}
@@ -0,0 +1,2 @@
class Test1 extends Super<String>{
}
@@ -0,0 +1,5 @@
public abstract class Parent<S> {}
class Child<T> extends Parent<T> {
void <caret>method(T t){}
}
@@ -0,0 +1,8 @@
public abstract class Parent<S> {
abstract void method(S t);
}
class Child<T> extends Parent<T> {
@Override
void method(T t){}
}
@@ -0,0 +1,10 @@
public class Parent<S> {}
interface I<IT> {
void method(IT t);
}
class Child<T> extends Parent<T> implements I<T>{
<caret>
public void method(T t){}
}
@@ -0,0 +1,10 @@
public class Parent<S> implements I<S> {}
interface I<IT> {
void method(IT t);
}
class Child<T> extends Parent<T> {
public void method(T t){}
}
@@ -161,6 +161,14 @@ public class InlineSuperClassTest extends MultiFileTestCase {
}
public void testMultipleSubclasses() throws Exception {
doTestMultipleSubclasses();
}
public void testMultipleSubstitutions() throws Exception {
doTestMultipleSubclasses();
}
private void doTestMultipleSubclasses() throws Exception {
doTest(new PerformAction() {
public void performAction(final VirtualFile rootDir, final VirtualFile rootAfter) throws Exception {
PsiClass superClass = myJavaFacade.findClass("Super", GlobalSearchScope.allScope(myProject));
@@ -79,7 +79,19 @@ public class PullUpTest extends LightCodeInsightTestCase {
doTest(new MemberDescriptor("f", PsiField.class));
}
public void testGenericsInAbstractMethod() throws Exception {
doTest(new MemberDescriptor("method", PsiMethod.class, true));
}
public void testGenericsInImplements() throws Exception {
doTest(false, new MemberDescriptor("I", PsiClass.class));
}
private void doTest(MemberDescriptor... membersToFind) throws Exception {
doTest(true, membersToFind);
}
private void doTest(final boolean checkMemebersMovedCount, MemberDescriptor... membersToFind) throws Exception {
configureByFile(BASE_PATH + getTestName(false) + ".java");
PsiElement elementAt = getFile().findElementAt(getEditor().getCaretModel().getOffset());
final PsiClass sourceClass = PsiTreeUtil.getParentOfType(elementAt, PsiClass.class);
@@ -105,7 +117,9 @@ public class PullUpTest extends LightCodeInsightTestCase {
final PullUpHelper helper = new PullUpHelper(sourceClass, targetClass, infos, new DocCommentPolicy(DocCommentPolicy.ASIS));
helper.run();
JavaRefactoringListenerManager.getInstance(getProject()).removeMoveMembersListener(listener);
assertEquals(countMoved[0], membersToFind.length);
if (checkMemebersMovedCount) {
assertEquals(countMoved[0], membersToFind.length);
}
checkResultByFile(BASE_PATH + getTestName(false) + "_after.java");
}