diff --git a/java/java-impl/src/com/intellij/codeInsight/JavaTargetElementEvaluator.java b/java/java-impl/src/com/intellij/codeInsight/JavaTargetElementEvaluator.java index 9f0356289781..763d69031c36 100644 --- a/java/java-impl/src/com/intellij/codeInsight/JavaTargetElementEvaluator.java +++ b/java/java-impl/src/com/intellij/codeInsight/JavaTargetElementEvaluator.java @@ -292,7 +292,8 @@ public class JavaTargetElementEvaluator extends TargetElementEvaluatorEx2 implem } else if (expression != null) { psiClass = PsiUtil.resolveClassInType(expression.getType()); - } else { + } + else { if (element instanceof PsiClass) { psiClass = (PsiClass)element; final PsiElement resolve = ((PsiReferenceExpression)reference).advancedResolve(true).getElement(); @@ -306,15 +307,31 @@ public class JavaTargetElementEvaluator extends TargetElementEvaluatorEx2 implem if (containingClass == null && psiClass == null) return PsiClass.EMPTY_ARRAY; if (containingClass != null) { - PsiElementFindProcessor processor1 = new PsiElementFindProcessor<>(containingClass); - while (psiClass != null) { - if (!processor1.process(psiClass) || - !ClassInheritorsSearch.search(containingClass).forEach(new PsiElementFindProcessor<>(psiClass)) || - !ClassInheritorsSearch.search(psiClass).forEach(processor1)) { - return new PsiClass[] {psiClass}; + if (psiClass instanceof PsiTypeParameter) { + List result = new ArrayList<>(); + for (PsiClassType classType : psiClass.getExtendsListTypes()) { + ContainerUtil.addIfNotNull(result, getInheritor(containingClass, classType.resolve())); } - psiClass = psiClass.getContainingClass(); + return result.isEmpty() ? null : result.toArray(PsiClass.EMPTY_ARRAY); } + else { + PsiClass aClass = getInheritor(containingClass, psiClass); + if (aClass != null) return new PsiClass[] {aClass}; + } + + } + return null; + } + + private PsiClass getInheritor(PsiClass containingClass, PsiClass psiClass) { + PsiElementFindProcessor processor1 = new PsiElementFindProcessor<>(containingClass); + while (psiClass != null) { + if (!processor1.process(psiClass) || + !ClassInheritorsSearch.search(containingClass).forEach(new PsiElementFindProcessor<>(psiClass)) || + !ClassInheritorsSearch.search(psiClass).forEach(processor1)) { + return psiClass; + } + psiClass = psiClass.getContainingClass(); } return null; } diff --git a/java/java-tests/testSrc/com/intellij/navigation/GotoImplementationHandlerTest.java b/java/java-tests/testSrc/com/intellij/navigation/GotoImplementationHandlerTest.java index ba1257d4d8e0..962054b5c22f 100644 --- a/java/java-tests/testSrc/com/intellij/navigation/GotoImplementationHandlerTest.java +++ b/java/java-tests/testSrc/com/intellij/navigation/GotoImplementationHandlerTest.java @@ -249,6 +249,27 @@ public class GotoImplementationHandlerTest extends JavaCodeInsightFixtureTestCas assertEquals("A", aClass.getName()); } + public void testMethodImplementationsOnTypeVariable() throws Exception { + PsiFile file = myFixture.addFileToProject("Foo.java", "interface I {}\n" + + "interface Im {\n" + + " void m();\n" + + "}\n" + + "class Im1 implements Im {\n" + + " public void m() {}\n" + + "}\n" + + "class Im2 implements Im {\n" + + " public void m() {}\n" + + "}\n" + + "class JavaClass {\n" + + " void a(T t){\n" + + " t.m();\n" + + " }\n" + + "}"); + myFixture.configureFromExistingVirtualFile(file.getVirtualFile()); + PsiElement[] targets = getTargets(file); + assertSize(2, targets); + } + public void testStaticMethodReference() { PsiFile file = myFixture.addFileToProject("Foo.java", "class C {\n" +