wrap return value: teach inference (IDEA-135027)

This commit is contained in:
Anna Kozlova
2015-01-08 19:54:18 +01:00
parent eef903064a
commit 51971c4a7a
11 changed files with 123 additions and 4 deletions
@@ -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);
}
}
}
}
}
@@ -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<UsageInfo[]> refUsages) {
MultiMap<PsiElement, String> conflicts = new MultiMap<PsiElement, String>();
@@ -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;
}
}
@@ -0,0 +1,10 @@
class Test {
Wrapper<String> foo() {
return new Wrapper<String>("");
}
void bar() {
String s = foo().getMyField();
}
}
@@ -0,0 +1,10 @@
class Wrapper<T> {
T myField;
Wrapper(T s) {
myField = s;
}
String getMyField() {
return myField;
}
}
@@ -0,0 +1,10 @@
class Test {
String foo() {
return "";
}
void bar() {
String s = foo();
}
}
@@ -0,0 +1,10 @@
class Wrapper<T> {
T myField;
Wrapper(T s) {
myField = s;
}
String getMyField() {
return myField;
}
}
@@ -0,0 +1,12 @@
import java.util.List;
class Test {
Wrapper<String> foo() {
return new Wrapper<String>(null);
}
void bar() {
List<String> s = foo().getMyField();
}
}
@@ -0,0 +1,11 @@
import java.util.List;
class Wrapper<T> {
List<T> myField;
Wrapper(List<T> s) {
myField = s;
}
List<T> getMyField() {
return myField;
}
}
@@ -0,0 +1,12 @@
import java.util.List;
class Test {
List<String> foo() {
return null;
}
void bar() {
List<String> s = foo();
}
}
@@ -0,0 +1,11 @@
import java.util.List;
class Wrapper<T> {
List<T> myField;
Wrapper(List<T> s) {
myField = s;
}
List<T> getMyField() {
return myField;
}
}
@@ -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"); }