From 0750185befafa5c178ba57cbbe849f48ced4d10d Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Wed, 9 Dec 2015 19:28:45 +0300 Subject: [PATCH] type migration: allow to migrate elements with type parameters if root contains these type parameters (IDEA-147944) --- .../typeMigration/TypeMigrationLabeler.java | 24 +++++++++----- .../TypeMigrationStatementProcessor.java | 2 +- .../refactoring/TypeMigrationTest.java | 31 +++++++++++++++++-- .../after/Test.items | 9 ++++++ .../after/test.java | 6 ++++ .../before/test.java | 5 +++ 6 files changed, 66 insertions(+), 11 deletions(-) create mode 100644 java/typeMigration/testData/refactoring/typeMigration/methodReturnTypeWithTypeParameter/after/Test.items create mode 100644 java/typeMigration/testData/refactoring/typeMigration/methodReturnTypeWithTypeParameter/after/test.java create mode 100644 java/typeMigration/testData/refactoring/typeMigration/methodReturnTypeWithTypeParameter/before/test.java diff --git a/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationLabeler.java b/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationLabeler.java index e4cce35c88f4..1161f68490be 100644 --- a/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationLabeler.java +++ b/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationLabeler.java @@ -25,6 +25,7 @@ import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.impl.PsiImplUtil; +import com.intellij.psi.impl.source.PsiClassReferenceType; import com.intellij.psi.impl.source.PsiImmediateClassType; import com.intellij.psi.javadoc.PsiDocTagValue; import com.intellij.psi.search.PsiSearchScopeUtil; @@ -37,11 +38,9 @@ import com.intellij.psi.util.TypeConversionUtil; import com.intellij.refactoring.typeMigration.usageInfo.OverridenUsageInfo; import com.intellij.refactoring.typeMigration.usageInfo.OverriderUsageInfo; import com.intellij.refactoring.typeMigration.usageInfo.TypeMigrationUsageInfo; +import com.intellij.refactoring.util.RefactoringUtil; import com.intellij.usageView.UsageInfo; -import com.intellij.util.Consumer; -import com.intellij.util.Function; -import com.intellij.util.IncorrectOperationException; -import com.intellij.util.Query; +import com.intellij.util.*; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.graph.DFSTBuilder; import com.intellij.util.graph.GraphGenerator; @@ -468,7 +467,15 @@ public class TypeMigrationLabeler { type = userDefinedType ? type : TypeEvaluator.substituteType(type, originalType, isContraVariantPosition); if (!userDefinedType) { - if (typeContainsTypeParameters(originalType)) return false; + final Set collector; + if (originalType instanceof PsiClassReferenceType) { + collector = new HashSet(); + final PsiJavaCodeReferenceElement reference = ((PsiClassReferenceType)originalType).getReference(); + RefactoringUtil.collectTypeParameters(collector, reference); + } else { + collector = Collections.emptySet(); + } + if (typeContainsTypeParameters(originalType, collector)) return false; } if (type instanceof PsiCapturedWildcardType) { @@ -571,14 +578,17 @@ public class TypeMigrationLabeler { } } - static boolean typeContainsTypeParameters(PsiType originalType) { + static boolean typeContainsTypeParameters(@Nullable PsiType originalType, @NotNull Set excluded) { if (originalType instanceof PsiClassType) { final PsiClassType psiClassType = (PsiClassType)originalType; if (psiClassType.resolve() instanceof PsiTypeParameter) { return true; } for (PsiType paramType : psiClassType.getParameters()) { - if (paramType instanceof PsiClassType && ((PsiClassType)paramType).resolve() instanceof PsiTypeParameter) return true; + if (paramType instanceof PsiClassType) { + final PsiClass resolved = ((PsiClassType)paramType).resolve(); + if (resolved instanceof PsiTypeParameter && !excluded.contains(resolved)) return true; + } } } return false; diff --git a/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationStatementProcessor.java b/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationStatementProcessor.java index bd89a643a121..26d1e2750c21 100644 --- a/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationStatementProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/typeMigration/TypeMigrationStatementProcessor.java @@ -191,7 +191,7 @@ class TypeMigrationStatementProcessor extends JavaRecursiveElementVisitor { final PsiType valueType = myTypeEvaluator.evaluateType(value); if (returnType != null && valueType != null) { if (!myLabeler.addMigrationRoot(method, valueType, myStatement, TypeConversionUtil.isAssignable(returnType, valueType) && !isGetter(value, method), true, true) - && TypeMigrationLabeler.typeContainsTypeParameters(returnType)) { + && TypeMigrationLabeler.typeContainsTypeParameters(returnType, Collections.emptySet())) { value.accept(this); } } diff --git a/java/typeMigration/test/com/intellij/refactoring/TypeMigrationTest.java b/java/typeMigration/test/com/intellij/refactoring/TypeMigrationTest.java index c738822114c5..708a08b070d7 100644 --- a/java/typeMigration/test/com/intellij/refactoring/TypeMigrationTest.java +++ b/java/typeMigration/test/com/intellij/refactoring/TypeMigrationTest.java @@ -862,8 +862,8 @@ public class TypeMigrationTest extends TypeMigrationTestBase { } public void testT139() { - doTestForeachParameter(myFactory.createTypeFromText("java.lang.String", null), - myFactory.createTypeFromText("java.lang.Integer", null)); + doTestForeachParameter( + myFactory.createTypeFromText("java.lang.Integer", null)); } public void testT140() { @@ -914,7 +914,32 @@ public class TypeMigrationTest extends TypeMigrationTestBase { doTestFieldType("foo", "Test", PsiType.INT, PsiType.LONG); } - private void doTestForeachParameter(final PsiType rootType, final PsiType migrationType) { + public void testMethodReturnTypeWithTypeParameter() { + doTestReturnType("meth", myFactory.createTypeFromText("java.util.List", null)); + } + + private void doTestReturnType(final String methodName, final PsiType migrationType) { + start(new RulesProvider() { + @Override + public TypeMigrationRules provide() throws Exception { + final TypeMigrationRules rules = new TypeMigrationRules(); + rules.setMigrationRootType(migrationType); + return rules; + } + + @Override + public PsiElement victims(PsiClass aClass) { + for (PsiMethod method : PsiTreeUtil.findChildrenOfType(aClass, PsiMethod.class)) { + if (methodName.equals(method.getName())) { + return method; + } + } + throw new AssertionError(); + } + }); + } + + private void doTestForeachParameter(final PsiType migrationType) { start(new RulesProvider() { @Override public TypeMigrationRules provide() { diff --git a/java/typeMigration/testData/refactoring/typeMigration/methodReturnTypeWithTypeParameter/after/Test.items b/java/typeMigration/testData/refactoring/typeMigration/methodReturnTypeWithTypeParameter/after/Test.items new file mode 100644 index 000000000000..ce4fb7c8cd05 --- /dev/null +++ b/java/typeMigration/testData/refactoring/typeMigration/methodReturnTypeWithTypeParameter/after/Test.items @@ -0,0 +1,9 @@ +Types: +PsiMethod:meth : java.util.List +PsiParameter:p : java.util.List +PsiReferenceExpression:p : java.util.List + +Conversions: + +New expression type changes: +Fails: diff --git a/java/typeMigration/testData/refactoring/typeMigration/methodReturnTypeWithTypeParameter/after/test.java b/java/typeMigration/testData/refactoring/typeMigration/methodReturnTypeWithTypeParameter/after/test.java new file mode 100644 index 000000000000..73b07bd75e42 --- /dev/null +++ b/java/typeMigration/testData/refactoring/typeMigration/methodReturnTypeWithTypeParameter/after/test.java @@ -0,0 +1,6 @@ +import java.util.List; +import java.util.Set; + +public class Test { + public List meth(List p) { return p; } +} \ No newline at end of file diff --git a/java/typeMigration/testData/refactoring/typeMigration/methodReturnTypeWithTypeParameter/before/test.java b/java/typeMigration/testData/refactoring/typeMigration/methodReturnTypeWithTypeParameter/before/test.java new file mode 100644 index 000000000000..6b9858892c6f --- /dev/null +++ b/java/typeMigration/testData/refactoring/typeMigration/methodReturnTypeWithTypeParameter/before/test.java @@ -0,0 +1,5 @@ +import java.util.Set; + +public class Test { + public Set meth(Set p) { return p; } +} \ No newline at end of file