diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/MethodReturnTypeFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/MethodReturnTypeFix.java index f3a0efad220f..243cbde2e4b3 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/MethodReturnTypeFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/MethodReturnTypeFix.java @@ -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 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 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) { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/methodReturn/afterGenericVar.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/methodReturn/afterGenericVar.java new file mode 100644 index 000000000000..c4baf6d52338 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/methodReturn/afterGenericVar.java @@ -0,0 +1,14 @@ +// "Make 'method' return 'java.util.List'" "true" +import java.util.*; + +public class Test { + class Inner { + List method() { + return null; + } + + void test() { + List t = method(); + } + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/methodReturn/beforeGenericVar.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/methodReturn/beforeGenericVar.java new file mode 100644 index 000000000000..96025ba66059 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/methodReturn/beforeGenericVar.java @@ -0,0 +1,12 @@ +// "Make 'method' return 'java.util.List'" "true" +import java.util.*; + +public class Test { + class Inner { + void method() {} + + void test() { + List t = method(); + } + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/methodReturn/beforeGenericVarOutOfScope.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/methodReturn/beforeGenericVarOutOfScope.java new file mode 100644 index 000000000000..a4ed099686fe --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/methodReturn/beforeGenericVarOutOfScope.java @@ -0,0 +1,13 @@ +// "Make 'method' return 'java.util.List'" "false" +import java.util.*; + +public class Test { + void method() {} + + class Inner { + + void test() { + List t = method(); + } + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/methodReturn/beforeGenericVarStatic.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/methodReturn/beforeGenericVarStatic.java new file mode 100644 index 000000000000..cd2f6f4b36bf --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/methodReturn/beforeGenericVarStatic.java @@ -0,0 +1,12 @@ +// "Make 'method' return 'java.util.List'" "false" +import java.util.*; + +public class Test { + static class Inner { + static void method() {} + + void test() { + List t = method(); + } + } +}