MethodReturnTypeFix: do not suggest when type refers to type parameter not available at method declaration

This commit is contained in:
Tagir Valeev
2017-10-09 09:27:16 +07:00
parent 55330b22fb
commit 9a91789f27
5 changed files with 77 additions and 11 deletions
@@ -22,10 +22,7 @@ import com.intellij.psi.controlFlow.AnalysisCanceledException;
import com.intellij.psi.controlFlow.ControlFlow;
import com.intellij.psi.controlFlow.ControlFlowUtil;
import com.intellij.psi.search.LocalSearchScope;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.PsiTypesUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.psi.util.*;
import com.intellij.refactoring.changeSignature.ChangeSignatureProcessor;
import com.intellij.refactoring.changeSignature.OverriderUsageInfo;
import com.intellij.refactoring.changeSignature.ParameterInfoImpl;
@@ -36,7 +33,10 @@ import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
public class MethodReturnTypeFix extends LocalQuickFixAndIntentionActionOnPsiElement implements HighPriorityAction {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.daemon.impl.quickfix.MethodReturnBooleanFix");
@@ -81,7 +81,26 @@ public class MethodReturnTypeFix extends LocalQuickFixAndIntentionActionOnPsiEle
myReturnType.isValid() &&
!TypeConversionUtil.isNullType(myReturnType)) {
final PsiType returnType = myMethod.getReturnType();
if (returnType != null && returnType.isValid() && !Comparing.equal(myReturnType, returnType)) return true;
if (returnType != null && returnType.isValid() && !Comparing.equal(myReturnType, returnType)) {
return allTypeParametersResolved(myMethod, myReturnType);
}
}
return false;
}
private static boolean allTypeParametersResolved(PsiMethod myMethod, PsiType myReturnType) {
PsiTypesUtil.TypeParameterSearcher searcher = new PsiTypesUtil.TypeParameterSearcher();
myReturnType.accept(searcher);
Set<PsiTypeParameter> parameters = searcher.getTypeParameters();
return parameters.stream().allMatch(parameter -> isAccessibleAt(parameter, myMethod));
}
private static boolean isAccessibleAt(PsiTypeParameter parameter, PsiMethod method) {
PsiTypeParameterListOwner owner = parameter.getOwner();
if(owner == method) return true;
if(owner instanceof PsiClass) {
return PsiTreeUtil.isAncestor(owner, method, true) &&
InheritanceUtil.hasEnclosingInstanceInScope((PsiClass)owner, method, false, false);
}
return false;
}
@@ -188,7 +207,7 @@ public class MethodReturnTypeFix extends LocalQuickFixAndIntentionActionOnPsiEle
return editor;
}
@Nullable
@NotNull
private PsiMethod[] getChangeRoots(final PsiMethod method, @NotNull PsiType returnType) {
if (!myFixWholeHierarchy) return new PsiMethod[]{method};
@@ -209,10 +228,6 @@ public class MethodReturnTypeFix extends LocalQuickFixAndIntentionActionOnPsiEle
@NotNull
private List<PsiMethod> changeReturnType(final PsiMethod method, @NotNull final PsiType returnType) {
final PsiMethod[] methods = getChangeRoots(method, returnType);
if (methods == null) {
// canceled
return Collections.emptyList();
}
final MethodSignatureChangeVisitor methodSignatureChangeVisitor = new MethodSignatureChangeVisitor();
for (PsiMethod targetMethod : methods) {
@@ -0,0 +1,14 @@
// "Make 'method' return 'java.util.List<T>'" "true"
import java.util.*;
public class Test {
class Inner<T> {
List<T> method() {
return null;
}
void test() {
List<T> t = method();
}
}
}
@@ -0,0 +1,12 @@
// "Make 'method' return 'java.util.List<T>'" "true"
import java.util.*;
public class Test {
class Inner<T> {
void method() {}
void test() {
List<T> t = met<caret>hod();
}
}
}
@@ -0,0 +1,13 @@
// "Make 'method' return 'java.util.List<T>'" "false"
import java.util.*;
public class Test {
void method() {}
class Inner<T> {
void test() {
List<T> t = met<caret>hod();
}
}
}
@@ -0,0 +1,12 @@
// "Make 'method' return 'java.util.List<T>'" "false"
import java.util.*;
public class Test {
static class Inner<T> {
static void method() {}
void test() {
List<T> t = met<caret>hod();
}
}
}