don't build hierarchy for all class methods just to check that one of them has a super (IDEA-85127)

This commit is contained in:
peter
2013-07-01 14:21:32 +02:00
parent 79750cad59
commit 58b111fc88
2 changed files with 55 additions and 35 deletions
@@ -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<PsiMember> result = new ArrayList<PsiMember>();
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<PsiMember> members) {
ListIterator<PsiMember> 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<PsiMethod> list = new ArrayList<PsiMethod>(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<PsiModifierListOwner>{
@@ -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<Object> getPopupElements(ChooseByNameModel model, String text) {
return getPopupElements(createPopup(model), text)
}