diff --git a/java/java-impl/src/com/intellij/ide/util/gotoByName/DefaultSymbolNavigationContributor.java b/java/java-impl/src/com/intellij/ide/util/gotoByName/DefaultSymbolNavigationContributor.java index e42aff93b76e..402e7f54e0dc 100644 --- a/java/java-impl/src/com/intellij/ide/util/gotoByName/DefaultSymbolNavigationContributor.java +++ b/java/java-impl/src/com/intellij/ide/util/gotoByName/DefaultSymbolNavigationContributor.java @@ -19,18 +19,20 @@ import com.intellij.ide.util.DefaultPsiElementCellRenderer; import com.intellij.navigation.ChooseByNameContributor; import com.intellij.navigation.NavigationItem; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; import com.intellij.psi.*; +import com.intellij.psi.impl.PsiSuperMethodImplUtil; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.PsiShortNamesCache; import com.intellij.psi.util.PsiUtil; import com.intellij.util.ArrayUtil; -import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.HashSet; import org.jetbrains.annotations.NotNull; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; public class DefaultSymbolNavigationContributor implements ChooseByNameContributor { private static final Logger LOG = Logger.getInstance("#com.intellij.ide.util.gotoByName.DefaultSymbolNavigationContributor"); @@ -52,45 +54,41 @@ public class DefaultSymbolNavigationContributor implements ChooseByNameContribut GlobalSearchScope scope = includeNonProjectItems ? GlobalSearchScope.allScope(project) : GlobalSearchScope.projectScope(project); PsiShortNamesCache cache = PsiShortNamesCache.getInstance(project); - PsiMethod[] methods = cache.getMethodsByName(name, scope); - methods = filterInheritedMethods(methods); - PsiField[] fields = cache.getFieldsByName(name, scope); - PsiClass[] classes = cache.getClassesByName(name, scope); - List result = new ArrayList(); - ContainerUtil.addAll(result, methods); - ContainerUtil.addAll(result, fields); - ContainerUtil.addAll(result, classes); - filterOutNonOpenable(result); + for (PsiMethod method : cache.getMethodsByName(name, scope)) { + if (!method.isConstructor() && isOpenable(method) && !hasSuperMethod(method)) { + result.add(method); + } + } + for (PsiField field : cache.getFieldsByName(name, scope)) { + if (isOpenable(field)) { + result.add(field); + } + } + for (PsiClass aClass : cache.getClassesByName(name, scope)) { + if (isOpenable(aClass)) { + result.add(aClass); + } + } PsiMember[] array = result.toArray(new PsiMember[result.size()]); Arrays.sort(array, MyComparator.INSTANCE); return array; } - private static void filterOutNonOpenable(List members) { - ListIterator it = members.listIterator(); - while (it.hasNext()) { - PsiMember member = it.next(); - if (isNonOpenable(member)) { - it.remove(); + private static boolean isOpenable(PsiMember member) { + return member.getContainingFile().getVirtualFile() != null; + } + + private static boolean hasSuperMethod(PsiMethod method) { + PsiClass containingClass = method.getContainingClass(); + if (containingClass == null) return false; + + for (PsiMethod candidate : containingClass.findMethodsByName(method.getName(), true)) { + if (candidate.getContainingClass() != containingClass && PsiSuperMethodImplUtil.isSuperMethodSmart(method, candidate)) { + return true; } } - } - - private static boolean isNonOpenable(PsiMember member) { - return member.getContainingFile().getVirtualFile() == null; - } - - private static PsiMethod[] filterInheritedMethods(PsiMethod[] methods) { - ArrayList list = new ArrayList(methods.length); - for (PsiMethod method : methods) { - ProgressManager.checkCanceled(); - if (method.isConstructor()) continue; - PsiMethod[] supers = method.findSuperMethods(); - if (supers.length > 0) continue; - list.add(method); - } - return list.toArray(new PsiMethod[list.size()]); + return false; } private static class MyComparator implements Comparator{ diff --git a/java/java-tests/testSrc/com/intellij/navigation/ChooseByNameTest.groovy b/java/java-tests/testSrc/com/intellij/navigation/ChooseByNameTest.groovy index 0a5cc1516c24..89a61bc565ab 100644 --- a/java/java-tests/testSrc/com/intellij/navigation/ChooseByNameTest.groovy +++ b/java/java-tests/testSrc/com/intellij/navigation/ChooseByNameTest.groovy @@ -1,9 +1,9 @@ package com.intellij.navigation - import com.intellij.ide.util.gotoByName.ChooseByNameBase import com.intellij.ide.util.gotoByName.ChooseByNameModel import com.intellij.ide.util.gotoByName.ChooseByNamePopup import com.intellij.ide.util.gotoByName.GotoClassModel2 +import com.intellij.ide.util.gotoByName.GotoSymbolModel2 import com.intellij.openapi.Disposable import com.intellij.openapi.application.ModalityState import com.intellij.openapi.util.Disposer @@ -43,6 +43,28 @@ class ChooseByNameTest extends LightCodeInsightFixtureTestCase { assert getPopupElements(new GotoClassModel2(project), "@") == [] } + public void "test filter overridden methods from goto symbol"() { + def intf = myFixture.addClass(""" +class Intf { + void xxx1() {} + void xxx2() {} +}""") + def impl = myFixture.addClass(""" +class Impl extends Intf { + void xxx1() {} + void xxx3() {} +} +""") + + def elements = getPopupElements(new GotoSymbolModel2(project), "xxx") + + assert intf.findMethodsByName('xxx1', false)[0] in elements + assert intf.findMethodsByName('xxx2', false)[0] in elements + + assert impl.findMethodsByName('xxx3', false)[0] in elements + assert !(impl.findMethodsByName('xxx1', false)[0] in elements) + } + private List getPopupElements(ChooseByNameModel model, String text) { return getPopupElements(createPopup(model), text) }