extract superclass: do not extract class type parameter if method one is used

This commit is contained in:
anna
2010-10-14 21:51:02 +04:00
parent cf33a0cd86
commit 4e82c12b54
6 changed files with 42 additions and 8 deletions

View File

@@ -18,6 +18,7 @@ package com.intellij.refactoring.extractSuperclass;
import com.intellij.codeInsight.generation.OverrideImplementUtil;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Condition;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.util.MethodSignature;
@@ -30,6 +31,7 @@ import com.intellij.refactoring.util.classMembers.MemberInfo;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.HashMap;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.Nullable;
import java.util.*;
@@ -162,27 +164,34 @@ public class ExtractSuperClassUtil {
for (final MemberInfo info : selectedMembers) {
movedElements.add(info.getMember());
}
final PsiTypeParameterList typeParameterList = RefactoringUtil.createTypeParameterListWithUsedTypeParameters(
movedElements.toArray(new PsiElement[movedElements.size()]));
final PsiTypeParameterList typeParameterList = RefactoringUtil.createTypeParameterListWithUsedTypeParameters(null, new Condition<PsiTypeParameter>() {
@Override
public boolean value(PsiTypeParameter parameter) {
return findTypeParameterInDerived(derivedClass, parameter.getName()) != null;
}
}, movedElements.toArray(new PsiElement[movedElements.size()]));
final PsiTypeParameterList originalTypeParameterList = superClass.getTypeParameterList();
assert originalTypeParameterList != null;
final PsiTypeParameterList newList = typeParameterList != null ? (PsiTypeParameterList)originalTypeParameterList.replace(typeParameterList) : originalTypeParameterList;
final PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory();
Map<PsiTypeParameter, PsiType> substitutionMap = new HashMap<PsiTypeParameter, PsiType>();
for (final PsiTypeParameter parameter : newList.getTypeParameters()) {
substitutionMap.put(parameter, factory.createType(findTypeParameterInDerived(derivedClass, parameter.getName())));
final PsiTypeParameter parameterInDerived = findTypeParameterInDerived(derivedClass, parameter.getName());
if (parameterInDerived != null) {
substitutionMap.put(parameter, factory.createType(parameterInDerived));
}
}
final PsiClassType type = factory.createType(superClass, factory.createSubstitutor(substitutionMap));
return factory.createReferenceElementByType(type);
}
@Nullable
public static PsiTypeParameter findTypeParameterInDerived(final PsiClass aClass, final String name) {
for (PsiTypeParameter typeParameter : PsiUtil.typeParametersIterable(aClass)) {
if (name.equals(typeParameter.getName())) return typeParameter;
}
LOG.error("Cannot find type parameter");
return null;
}
}

View File

@@ -1196,12 +1196,20 @@ public class RefactoringUtil {
}
@Nullable
public static PsiTypeParameterList createTypeParameterListWithUsedTypeParameters(final PsiTypeParameterList fromList, @NotNull final PsiElement... elements) {
public static PsiTypeParameterList createTypeParameterListWithUsedTypeParameters(final PsiTypeParameterList fromList,
@NotNull final PsiElement... elements) {
return createTypeParameterListWithUsedTypeParameters(fromList, Condition.TRUE, elements);
}
@Nullable
public static PsiTypeParameterList createTypeParameterListWithUsedTypeParameters(final PsiTypeParameterList fromList,
Condition<PsiTypeParameter> filter,
@NotNull final PsiElement... elements) {
if (elements.length == 0) return null;
final Set<PsiTypeParameter> used = new HashSet<PsiTypeParameter>();
for (final PsiElement element : elements) {
if (element == null) continue;
collectTypeParameters(used, element); //pull up extends cls class with type params
collectTypeParameters(used, element, filter); //pull up extends cls class with type params
}
@@ -1235,6 +1243,10 @@ public class RefactoringUtil {
}
public static void collectTypeParameters(final Set<PsiTypeParameter> used, final PsiElement element) {
collectTypeParameters(used, element, Condition.TRUE);
}
public static void collectTypeParameters(final Set<PsiTypeParameter> used, final PsiElement element,
final Condition<PsiTypeParameter> filter) {
element.accept(new JavaRecursiveElementVisitor() {
@Override public void visitReferenceElement(PsiJavaCodeReferenceElement reference) {
super.visitReferenceElement(reference);
@@ -1242,7 +1254,7 @@ public class RefactoringUtil {
final PsiElement resolved = reference.resolve();
if (resolved instanceof PsiTypeParameter) {
final PsiTypeParameter typeParameter = (PsiTypeParameter)resolved;
if (PsiTreeUtil.isAncestor(typeParameter.getOwner(), element, false)) {
if (PsiTreeUtil.isAncestor(typeParameter.getOwner(), element, false) && filter.value(typeParameter)) {
used.add(typeParameter);
}
}
@@ -1254,7 +1266,8 @@ public class RefactoringUtil {
super.visitExpression(expression);
final PsiType type = expression.getType();
final PsiClass resolved = PsiUtil.resolveClassInType(type);
if (resolved instanceof PsiTypeParameter && PsiTreeUtil.isAncestor(((PsiTypeParameter)resolved).getOwner(), element, false)){
if (resolved instanceof PsiTypeParameter && PsiTreeUtil.isAncestor(((PsiTypeParameter)resolved).getOwner(), element, false) && filter.value(
(PsiTypeParameter)resolved)){
used.add((PsiTypeParameter)resolved);
}
}

View File

@@ -0,0 +1,3 @@
public class Test {
public <T> T m(){return null;}
}

View File

@@ -0,0 +1,2 @@
public class TestSubclass extends Test {
}

View File

@@ -0,0 +1,3 @@
public class Test {
public <T> T m(){return null;}
}

View File

@@ -41,6 +41,10 @@ public class ExtractSuperClassTest extends CodeInsightTestCase {
doTest("Test", "TestSubclass", new RefactoringTestUtil.MemberDescriptor("x", PsiField.class));
}
public void testMethodTypeParameter() throws Exception {
doTest("Test", "TestSubclass", new RefactoringTestUtil.MemberDescriptor("m", PsiMethod.class));
}
public void testConflictUsingPrivateMethod() throws Exception {
doTest("Test", "TestSubclass",
new String[] {"Method <b><code>Test.foo()</code></b> is private and will not be accessible from method <b><code>x()</code></b>."},