From ed360ef370b4eb6f8f9a99a3d2904f76ec24da5b Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Wed, 12 Jan 2022 16:07:43 +0100 Subject: [PATCH] caller hierarchy: in case of bound generics do not filter out bounds-related usages to fix another case in IDEA-275145 result of call hierarchy is not correct GitOrigin-RevId: c713a96efd775a301439c4e6d5502d3827477fcb --- .../call/CallerMethodsTreeStructure.java | 19 +++++++++++++++++-- .../ide/hierarchy/call/Wildcards/A.java | 15 +++++++++++++++ .../hierarchy/call/Wildcards/verification.xml | 3 +++ .../ide/hierarchy/JavaCallHierarchyTest.java | 3 +++ 4 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 java/java-tests/testData/ide/hierarchy/call/Wildcards/A.java create mode 100644 java/java-tests/testData/ide/hierarchy/call/Wildcards/verification.xml diff --git a/java/java-impl/src/com/intellij/ide/hierarchy/call/CallerMethodsTreeStructure.java b/java/java-impl/src/com/intellij/ide/hierarchy/call/CallerMethodsTreeStructure.java index ef3f343ab807..e06f4c8f6925 100644 --- a/java/java-impl/src/com/intellij/ide/hierarchy/call/CallerMethodsTreeStructure.java +++ b/java/java-impl/src/com/intellij/ide/hierarchy/call/CallerMethodsTreeStructure.java @@ -105,8 +105,7 @@ public final class CallerMethodsTreeStructure extends HierarchyTreeStructure { if (receiverClass != null && expectedQualifierClass != null - && !InheritanceUtil.isInheritorOrSelf(expectedQualifierClass, receiverClass, true) - && !InheritanceUtil.isInheritorOrSelf(receiverClass, expectedQualifierClass, true) + && !areClassesRelated(expectedQualifierClass, receiverClass) ) { // ignore impossible candidates. E.g. when A < B,A < C and we invoked call hierarchy for method in C we should filter out methods in B because B and C are assignment-incompatible return true; @@ -130,6 +129,22 @@ public final class CallerMethodsTreeStructure extends HierarchyTreeStructure { .map(e -> new CallHierarchyNodeDescriptor(myProject, nodeDescriptor, e, false, false)).toArray(); } + private static boolean areClassesRelated(@NotNull PsiClass expectedQualifierClass, @NotNull PsiClass receiverClass) { + if (InheritanceUtil.isInheritorOrSelf(expectedQualifierClass, receiverClass, true) + || InheritanceUtil.isInheritorOrSelf(receiverClass, expectedQualifierClass, true)) { + return true; + } + if (receiverClass instanceof PsiTypeParameter) { + // in case of "T extends S", it should be related to SImpl, even though T is not superclass of SImpl + for (PsiClass receiverExtends : receiverClass.getSupers()) { + if (areClassesRelated(expectedQualifierClass, receiverExtends)) { + return true; + } + } + } + return false; + } + private static boolean isLocalOrAnonymousClass(PsiMember enclosingElement) { return enclosingElement instanceof PsiClass && ((PsiClass)enclosingElement).getQualifiedName() == null; } diff --git a/java/java-tests/testData/ide/hierarchy/call/Wildcards/A.java b/java/java-tests/testData/ide/hierarchy/call/Wildcards/A.java new file mode 100644 index 000000000000..eeaa313cda2d --- /dev/null +++ b/java/java-tests/testData/ide/hierarchy/call/Wildcards/A.java @@ -0,0 +1,15 @@ +package p; + +interface Board { + int getCount(); +} +class BoardImpl implements Board { + @Override + public int getCount() {return 0;} +} +class King { + B board; + boolean isLast() { + return board.getCount() == 1; + } +} diff --git a/java/java-tests/testData/ide/hierarchy/call/Wildcards/verification.xml b/java/java-tests/testData/ide/hierarchy/call/Wildcards/verification.xml new file mode 100644 index 000000000000..a7d65544b182 --- /dev/null +++ b/java/java-tests/testData/ide/hierarchy/call/Wildcards/verification.xml @@ -0,0 +1,3 @@ + + + diff --git a/java/java-tests/testSrc/com/intellij/java/ide/hierarchy/JavaCallHierarchyTest.java b/java/java-tests/testSrc/com/intellij/java/ide/hierarchy/JavaCallHierarchyTest.java index d1baaab15ef1..f8d135b17e66 100644 --- a/java/java-tests/testSrc/com/intellij/java/ide/hierarchy/JavaCallHierarchyTest.java +++ b/java/java-tests/testSrc/com/intellij/java/ide/hierarchy/JavaCallHierarchyTest.java @@ -144,4 +144,7 @@ public class JavaCallHierarchyTest extends HierarchyViewTestBase { public void testThroughAnonymousCalledByOther() throws Exception { doJavaCallerTypeHierarchyTest("x.AcmClientImpl", "returnSomething", "X.java"); } + public void testWildcards() throws Exception { + doJavaCallerTypeHierarchyTest("p.BoardImpl", "getCount", "A.java"); + } }