diff --git a/java/java-impl/src/com/intellij/refactoring/wrapreturnvalue/WrapReturnValueDialog.java b/java/java-impl/src/com/intellij/refactoring/wrapreturnvalue/WrapReturnValueDialog.java index e7918134afe5..6c0eb5c41f53 100644 --- a/java/java-impl/src/com/intellij/refactoring/wrapreturnvalue/WrapReturnValueDialog.java +++ b/java/java-impl/src/com/intellij/refactoring/wrapreturnvalue/WrapReturnValueDialog.java @@ -15,6 +15,7 @@ */ package com.intellij.refactoring.wrapreturnvalue; +import com.intellij.psi.util.PsiUtil; import com.intellij.ui.ListCellRendererWrapper; import com.intellij.ide.util.TreeClassChooser; import com.intellij.ide.util.TreeClassChooserFactory; @@ -215,12 +216,18 @@ class WrapReturnValueDialog extends RefactoringDialog { final PsiClass currentClass = facade.findClass(existingClassField.getText(), GlobalSearchScope.allScope(myProject)); if (currentClass != null) { model.removeAllElements(); + final PsiType returnType = sourceMethod.getReturnType(); + assert returnType != null; for (PsiField field : currentClass.getFields()) { - final PsiType returnType = sourceMethod.getReturnType(); - assert returnType != null; - if (TypeConversionUtil.isAssignable(field.getType(), returnType)) { + final PsiType fieldType = field.getType(); + if (TypeConversionUtil.isAssignable(fieldType, returnType)) { model.addElement(field); } + else { + if (WrapReturnValueProcessor.getInferredType(fieldType, returnType, currentClass, sourceMethod) != null) { + model.addElement(field); + } + } } } } diff --git a/java/java-impl/src/com/intellij/refactoring/wrapreturnvalue/WrapReturnValueProcessor.java b/java/java-impl/src/com/intellij/refactoring/wrapreturnvalue/WrapReturnValueProcessor.java index d410252f5528..6d7ed2ffd939 100644 --- a/java/java-impl/src/com/intellij/refactoring/wrapreturnvalue/WrapReturnValueProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/wrapreturnvalue/WrapReturnValueProcessor.java @@ -31,6 +31,7 @@ import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.searches.OverridingMethodsSearch; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.util.PropertyUtil; +import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.TypeConversionUtil; import com.intellij.refactoring.MoveDestination; import com.intellij.refactoring.RefactorJBundle; @@ -157,9 +158,32 @@ public class WrapReturnValueProcessor extends FixableUsagesRefactoringProcessor }, ",")); returnTypeBuffer.append('>'); } + else if (myDelegateField != null) { + final PsiType type = myDelegateField.getType(); + final PsiType returnType = myMethod.getReturnType(); + final PsiClass containingClass = myDelegateField.getContainingClass(); + final PsiType inferredType = getInferredType(type, returnType, containingClass, myMethod); + if (inferredType != null) { + returnTypeBuffer.append("<").append(inferredType.getCanonicalText()).append(">"); + } + } return returnTypeBuffer.toString(); } + protected static PsiType getInferredType(PsiType type, PsiType returnType, PsiClass containingClass, PsiMethod method) { + if (containingClass != null && containingClass.getTypeParameters().length == 1) { + final PsiSubstitutor substitutor = PsiResolveHelper.SERVICE.getInstance(method.getProject()) + .inferTypeArguments(containingClass.getTypeParameters(), new PsiType[]{type}, new PsiType[]{returnType}, PsiUtil.getLanguageLevel( + method)); + final PsiTypeParameter typeParameter = containingClass.getTypeParameters()[0]; + final PsiType substituted = substitutor.substitute(typeParameter); + if (substituted != null && !typeParameter.equals(PsiUtil.resolveClassInClassTypeOnly(substituted))) { + return substituted; + } + } + return null; + } + @Override protected boolean preprocessUsages(final Ref refUsages) { MultiMap conflicts = new MultiMap(); @@ -198,7 +222,7 @@ public class WrapReturnValueProcessor extends FixableUsagesRefactoringProcessor final PsiParameter parameter = parameters[0]; final PsiType parameterType = parameter.getType(); for (PsiType returnType : returnTypes) { - if (!TypeConversionUtil.isAssignable(parameterType, returnType)) { + if (getInferredType(parameterType, returnType, existingClass, myMethod) == null && !TypeConversionUtil.isAssignable(parameterType, returnType)) { continue constr; } } diff --git a/java/java-tests/testData/refactoring/wrapReturnValue/inferFieldType/after/Test.java b/java/java-tests/testData/refactoring/wrapReturnValue/inferFieldType/after/Test.java new file mode 100644 index 000000000000..af4bb0191954 --- /dev/null +++ b/java/java-tests/testData/refactoring/wrapReturnValue/inferFieldType/after/Test.java @@ -0,0 +1,10 @@ +class Test { + Wrapper foo() { + return new Wrapper(""); + } + + void bar() { + String s = foo().getMyField(); + } + +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/wrapReturnValue/inferFieldType/after/Wrapper.java b/java/java-tests/testData/refactoring/wrapReturnValue/inferFieldType/after/Wrapper.java new file mode 100644 index 000000000000..4562e93899f4 --- /dev/null +++ b/java/java-tests/testData/refactoring/wrapReturnValue/inferFieldType/after/Wrapper.java @@ -0,0 +1,10 @@ +class Wrapper { + T myField; + Wrapper(T s) { + myField = s; + } + + String getMyField() { + return myField; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/wrapReturnValue/inferFieldType/before/Test.java b/java/java-tests/testData/refactoring/wrapReturnValue/inferFieldType/before/Test.java new file mode 100644 index 000000000000..df1a8dfc9115 --- /dev/null +++ b/java/java-tests/testData/refactoring/wrapReturnValue/inferFieldType/before/Test.java @@ -0,0 +1,10 @@ +class Test { + String foo() { + return ""; + } + + void bar() { + String s = foo(); + } + +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/wrapReturnValue/inferFieldType/before/Wrapper.java b/java/java-tests/testData/refactoring/wrapReturnValue/inferFieldType/before/Wrapper.java new file mode 100644 index 000000000000..4562e93899f4 --- /dev/null +++ b/java/java-tests/testData/refactoring/wrapReturnValue/inferFieldType/before/Wrapper.java @@ -0,0 +1,10 @@ +class Wrapper { + T myField; + Wrapper(T s) { + myField = s; + } + + String getMyField() { + return myField; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/wrapReturnValue/inferFieldTypeArg/after/Test.java b/java/java-tests/testData/refactoring/wrapReturnValue/inferFieldTypeArg/after/Test.java new file mode 100644 index 000000000000..249a8bc66deb --- /dev/null +++ b/java/java-tests/testData/refactoring/wrapReturnValue/inferFieldTypeArg/after/Test.java @@ -0,0 +1,12 @@ +import java.util.List; + +class Test { + Wrapper foo() { + return new Wrapper(null); + } + + void bar() { + List s = foo().getMyField(); + } + +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/wrapReturnValue/inferFieldTypeArg/after/Wrapper.java b/java/java-tests/testData/refactoring/wrapReturnValue/inferFieldTypeArg/after/Wrapper.java new file mode 100644 index 000000000000..46a4678d8d0a --- /dev/null +++ b/java/java-tests/testData/refactoring/wrapReturnValue/inferFieldTypeArg/after/Wrapper.java @@ -0,0 +1,11 @@ +import java.util.List; +class Wrapper { + List myField; + Wrapper(List s) { + myField = s; + } + + List getMyField() { + return myField; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/wrapReturnValue/inferFieldTypeArg/before/Test.java b/java/java-tests/testData/refactoring/wrapReturnValue/inferFieldTypeArg/before/Test.java new file mode 100644 index 000000000000..0ecc3827e600 --- /dev/null +++ b/java/java-tests/testData/refactoring/wrapReturnValue/inferFieldTypeArg/before/Test.java @@ -0,0 +1,12 @@ +import java.util.List; + +class Test { + List foo() { + return null; + } + + void bar() { + List s = foo(); + } + +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/wrapReturnValue/inferFieldTypeArg/before/Wrapper.java b/java/java-tests/testData/refactoring/wrapReturnValue/inferFieldTypeArg/before/Wrapper.java new file mode 100644 index 000000000000..46a4678d8d0a --- /dev/null +++ b/java/java-tests/testData/refactoring/wrapReturnValue/inferFieldTypeArg/before/Wrapper.java @@ -0,0 +1,11 @@ +import java.util.List; +class Wrapper { + List myField; + Wrapper(List s) { + myField = s; + } + + List getMyField() { + return myField; + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/refactoring/WrapReturnValueTest.java b/java/java-tests/testSrc/com/intellij/refactoring/WrapReturnValueTest.java index b1efc20c4523..a6e362073bb9 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/WrapReturnValueTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/WrapReturnValueTest.java @@ -51,6 +51,8 @@ public class WrapReturnValueTest extends MultiFileTestCase { public void testHierarchy() { doTest(false, null, true); } public void testAnonymous() { doTest(true, null, false); } public void testWrongFieldAssignment() { doTest(true, "Existing class does not have appropriate constructor", false); } + public void testInferFieldType() { doTest(true, null, false); } + public void testInferFieldTypeArg() { doTest(true, null, false); } public void testWrongFieldType() { doTest(true, "Existing class does not have appropriate constructor", false); } public void testStaticMethodInnerClass() { doTest(false, null, true); } public void testRawReturnType() { doTest(true, "Existing class does not have appropriate constructor"); }