pull up: erasure type parameters or try to substitute (IDEA-53490)

This commit is contained in:
anna
2010-04-14 14:08:31 +04:00
parent a03abdc55a
commit d95d359eeb
10 changed files with 90 additions and 22 deletions

View File

@@ -36,10 +36,7 @@ import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import com.intellij.psi.search.LocalSearchScope;
import com.intellij.psi.search.searches.OverridingMethodsSearch;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.MethodSignatureUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.*;
import com.intellij.refactoring.BaseRefactoringProcessor;
import com.intellij.refactoring.RefactoringBundle;
import com.intellij.refactoring.listeners.JavaRefactoringListenerManager;
@@ -109,6 +106,9 @@ 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());
@@ -235,6 +235,23 @@ public class PullUpHelper extends BaseRefactoringProcessor{
}
}
private PsiSubstitutor upDownSuperClassSubstitutor() {
PsiSubstitutor substitutor = PsiSubstitutor.EMPTY;
for (PsiTypeParameter parameter : PsiUtil.typeParametersIterable(mySourceClass)) {
substitutor = substitutor.put(parameter, null);
}
final Map<PsiTypeParameter, PsiType> substitutionMap =
TypeConversionUtil.getSuperClassSubstitutor(myTargetSuperClass, mySourceClass, PsiSubstitutor.EMPTY).getSubstitutionMap();
for (PsiTypeParameter parameter : substitutionMap.keySet()) {
final PsiType type = substitutionMap.get(parameter);
final PsiClass resolvedClass = PsiUtil.resolveClassInType(type);
if (resolvedClass instanceof PsiTypeParameter) {
substitutor = substitutor.put((PsiTypeParameter)resolvedClass, JavaPsiFacade.getElementFactory(myProject).createType(parameter));
}
}
return substitutor;
}
private static void deleteOverrideAnnotationIfFound(PsiMethod oMethod) {
final PsiAnnotation annotation = AnnotationUtil.findAnnotation(oMethod, Override.class.getName());
if (annotation != null) {

View File

@@ -327,24 +327,7 @@ 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);
for (PsiTypeParameter parameter : PsiUtil.typeParametersIterable(myClass)) {
for (PsiReference reference : ReferencesSearch.search(parameter)) {
final PsiElement element = reference.getElement();
final PsiMember member = PsiTreeUtil.getParentOfType(element, PsiMember.class);
if (member != null) {
for (MemberInfo memberInfo : myMemberInfos) {
if (PsiTreeUtil.isAncestor(memberInfo.getMember(), member, false)) {
PsiType substitutedType = substitutor.substitute(parameter);
if (substitutedType == null) {
substitutedType = TypeConversionUtil.erasure(factory.createType(parameter));
}
element.getParent().replace(factory.createTypeElement(substitutedType));
break;
}
}
}
}
}
RefactoringUtil.replaceMovedMemberTypeParameters(myMemberInfos, PsiUtil.typeParametersIterable(myClass), substitutor, factory);
for (MemberInfo memberInfo : myMemberInfos) {
final PsiMember member = memberInfo.getMember();
final List<PsiReference> refsToRebind = new ArrayList<PsiReference>();

View File

@@ -48,9 +48,11 @@ import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
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;
@@ -855,6 +857,27 @@ public class RefactoringUtil {
return null;
}
public static void replaceMovedMemberTypeParameters(final MemberInfo[] memberInfos,
final Iterable<PsiTypeParameter> parametersIterable,
final PsiSubstitutor substitutor,
final PsiElementFactory factory) {
for (PsiTypeParameter parameter : parametersIterable) {
for (PsiReference reference : ReferencesSearch.search(parameter)) {
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;
}
}
}
}
}
public static interface ImplicitConstructorUsageVisitor {
void visitConstructor(PsiMethod constructor, PsiMethod baseConstructor);

View File

@@ -0,0 +1,5 @@
public class Parent<S> {}
class Child extends Parent<String> {
String <caret>f;
}

View File

@@ -0,0 +1,6 @@
public class Parent<S> {
String f;
}
class Child extends Parent<String> {
}

View File

@@ -0,0 +1,5 @@
public class Parent {}
class Child<T> extends Parent {
T <caret>f;
}

View File

@@ -0,0 +1,6 @@
public class Parent {
Object f;
}
class Child<T> extends Parent {
}

View File

@@ -0,0 +1,5 @@
public class Parent<S> {}
class Child<T> extends Parent<T> {
T <caret>f;
}

View File

@@ -0,0 +1,6 @@
public class Parent<S> {
S f;
}
class Child<T> extends Parent<T> {
}

View File

@@ -67,6 +67,18 @@ public class PullUpTest extends LightCodeInsightTestCase {
doTest(new MemberDescriptor ("get", PsiMethod.class));
}
public void testTypeParamErasure() throws Exception {
doTest(new MemberDescriptor("f", PsiField.class));
}
public void testTypeParamSubst() throws Exception {
doTest(new MemberDescriptor("f", PsiField.class));
}
public void testTypeArgument() throws Exception {
doTest(new MemberDescriptor("f", PsiField.class));
}
private void doTest(MemberDescriptor... membersToFind) throws Exception {
configureByFile(BASE_PATH + getTestName(false) + ".java");
PsiElement elementAt = getFile().findElementAt(getEditor().getCaretModel().getOffset());