diff --git a/java/java-impl/src/com/intellij/slicer/SliceUtil.java b/java/java-impl/src/com/intellij/slicer/SliceUtil.java index 5500e95542fa..19dc18baaaf5 100644 --- a/java/java-impl/src/com/intellij/slicer/SliceUtil.java +++ b/java/java-impl/src/com/intellij/slicer/SliceUtil.java @@ -35,6 +35,7 @@ import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.MethodSignatureUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.TypeConversionUtil; +import com.intellij.refactoring.util.RefactoringChangeUtil; import com.intellij.util.ArrayUtilRt; import com.intellij.util.Processor; import gnu.trove.THashMap; @@ -244,7 +245,10 @@ class SliceUtil { @NotNull final Processor processor, @NotNull final JavaSliceUsage parent, @NotNull final PsiSubstitutor parentSubstitutor) { - final JavaResolveResult resolved = methodCallExpr.resolveMethodGenerics(); + // if the call looks like 'otherClassObject.methodFromInterface()' + // we can narrow down the overridden methods scan to inheritors of OtherClass only + PsiClass qualifierClass = resolveQualifier(methodCallExpr); + JavaResolveResult resolved = methodCallExpr.resolveMethodGenerics(); PsiElement r = resolved.getElement(); if (r instanceof PsiCompiledElement) { r = r.getNavigationElement(); @@ -257,8 +261,15 @@ class SliceUtil { final PsiType parentType = parentSubstitutor.substitute(methodCallExpr.getType()); final PsiSubstitutor substitutor = resolved.getSubstitutor().putAll(parentSubstitutor); - Collection overrides = - new THashSet<>(OverridingMethodsSearch.search(methodCalled, parent.getScope().toSearchScope(), true).findAll()); + Collection overrides = new THashSet<>(); + OverridingMethodsSearch.search(methodCalled, parent.getScope().toSearchScope(), true).forEach((PsiMethod override) -> { + PsiClass containingClass = override.getContainingClass(); + if (containingClass == null) return true; + if (qualifierClass == null || containingClass.isInheritor(qualifierClass, true)) { + overrides.add(override); + } + return true; + }); overrides.add(methodCalled); final boolean[] result = {true}; @@ -300,6 +311,31 @@ class SliceUtil { return result[0]; } + private static PsiClass resolveQualifier(@NotNull PsiMethodCallExpression expr) { + PsiExpression qualifier = expr.getMethodExpression().getQualifierExpression(); + if (qualifier == null) { + PsiMethodCallExpression copy = (PsiMethodCallExpression)expr.copy(); + PsiReferenceExpression methodExpression = copy.getMethodExpression(); + + PsiThisExpression thisExpression = RefactoringChangeUtil.createThisExpression(expr.getManager(), null); + methodExpression.setQualifierExpression(thisExpression); + qualifier = methodExpression.getQualifierExpression(); + } + if (qualifier != null) { + if (qualifier instanceof PsiReferenceExpression) { + PsiElement resolved = ((PsiReferenceExpression)qualifier).resolve(); + if (resolved instanceof PsiClass) return (PsiClass)resolved; + } + else if (qualifier instanceof PsiThisExpression || qualifier instanceof PsiSuperExpression) { + PsiType type = qualifier.getType(); + if (type instanceof PsiClassType) { + return ((PsiClassType)type).resolve(); + } + } + } + return null; + } + private static boolean processFieldUsages(@NotNull final PsiField field, @NotNull final JavaSliceUsage parent, @NotNull final PsiSubstitutor parentSubstitutor, diff --git a/java/java-tests/testData/codeInsight/slice/backward/SearchOverriddenMethodsInThisClassHierarchy.java b/java/java-tests/testData/codeInsight/slice/backward/SearchOverriddenMethodsInThisClassHierarchy.java new file mode 100644 index 000000000000..d8b783560dff --- /dev/null +++ b/java/java-tests/testData/codeInsight/slice/backward/SearchOverriddenMethodsInThisClassHierarchy.java @@ -0,0 +1,21 @@ +interface I { + String getValue(); +} + +abstract class X implements I { + void foo() { + String s = getValue(); + } +} + +class Y implements I { + public String getValue() { + return "Y"; + } +} + +class Impl extends X { + public String getValue() { + return "Impl"; + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/slicer/SliceBackwardTest.java b/java/java-tests/testSrc/com/intellij/slicer/SliceBackwardTest.java index 485d4ed87f5c..7321d5e7bd74 100644 --- a/java/java-tests/testSrc/com/intellij/slicer/SliceBackwardTest.java +++ b/java/java-tests/testSrc/com/intellij/slicer/SliceBackwardTest.java @@ -83,4 +83,5 @@ public class SliceBackwardTest extends SliceTestCase { public void testTryCatchFinally() throws Exception { doTest();} public void testFinalVarAssignedBeforePassingToAnonymous() throws Exception { doTest();} public void testLocalVarDeclarationAndAssignment() throws Exception { doTest();} + public void testSearchOverriddenMethodsInThisClassHierarchy() throws Exception { doTest();} }