diff --git a/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaClassInheritorsSearcher.java b/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaClassInheritorsSearcher.java index 2c2f254ece1e..7846f74651e2 100644 --- a/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaClassInheritorsSearcher.java +++ b/java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaClassInheritorsSearcher.java @@ -17,12 +17,12 @@ package com.intellij.psi.impl.search; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.QueryExecutorBase; +import com.intellij.openapi.application.ReadActionProcessor; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressIndicatorProvider; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Computable; -import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Ref; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; @@ -32,14 +32,11 @@ import com.intellij.psi.search.searches.AllClassesSearch; import com.intellij.psi.search.searches.ClassInheritorsSearch; import com.intellij.psi.search.searches.DirectClassInheritorsSearch; import com.intellij.psi.util.PsiUtilCore; -import com.intellij.reference.SoftReference; import com.intellij.util.Processor; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.Stack; -import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import java.lang.ref.Reference; import java.util.Set; public class JavaClassInheritorsSearcher extends QueryExecutorBase { @@ -79,113 +76,85 @@ public class JavaClassInheritorsSearcher extends QueryExecutorBase() { - @Override - public String compute() { - return baseClass.getQualifiedName(); - } - }); - if (CommonClassNames.JAVA_LANG_OBJECT.equals(qname)) { - Project project = PsiUtilCore.getProjectInReadAction(baseClass); + Project project = PsiUtilCore.getProjectInReadAction(baseClass); + if (isJavaLangObject(baseClass)) { AllClassesSearch.search(searchScope, project, parameters.getNameCondition()).forEach(new Processor() { @Override public boolean process(final PsiClass aClass) { ProgressIndicatorProvider.checkCanceled(); - final String qname1 = ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - @Nullable - public String compute() { - return aClass.getQualifiedName(); - } - }); - return CommonClassNames.JAVA_LANG_OBJECT.equals(qname1) || consumer.process(aClass); + return isJavaLangObject(aClass) || consumer.process(aClass); } }); return; } final Ref currentBase = Ref.create(null); - final Stack, String>> stack = new Stack, String>>(); - // there are two sets for memory optimization: it's cheaper to hold FQN than PsiClass - final Set processedFqns = new THashSet(); // FQN of processed classes if the class has one - final Set processed = new THashSet(); // processed classes without FQN (e.g. anonymous) + final Stack stack = new Stack(); + final Set processed = ContainerUtil.newTroveSet(); - final Processor processor = new Processor() { + final Processor processor = new ReadActionProcessor() { @Override - public boolean process(final PsiClass candidate) { + public boolean processInReadAction(PsiClass candidate) { ProgressIndicatorProvider.checkCanceled(); - final Ref result = new Ref(); - final String[] fqn = new String[1]; - ApplicationManager.getApplication().runReadAction(new Runnable() { - @Override - public void run() { - fqn[0] = candidate.getQualifiedName(); - if (parameters.isCheckInheritance() || parameters.isCheckDeep() && !(candidate instanceof PsiAnonymousClass)) { - if (!candidate.isInheritor(currentBase.get(), false)) { - result.set(true); - return; - } - } - - if (PsiSearchScopeUtil.isInScope(searchScope, candidate)) { - if (candidate instanceof PsiAnonymousClass) { - result.set(consumer.process(candidate)); - } - else { - final String name = candidate.getName(); - if (name != null && parameters.getNameCondition().value(name) && !consumer.process(candidate)) result.set(false); - } - } + if (parameters.isCheckInheritance() || parameters.isCheckDeep() && !(candidate instanceof PsiAnonymousClass)) { + if (!candidate.isInheritor(currentBase.get(), false)) { + return true; } - }); - if (!result.isNull()) return result.get().booleanValue(); - - if (parameters.isCheckDeep() && !(candidate instanceof PsiAnonymousClass) && !isFinal(candidate)) { - Reference ref = fqn[0] == null ? createHardReference(candidate) : new SoftReference(candidate); - stack.push(Pair.create(ref, fqn[0])); } + if (PsiSearchScopeUtil.isInScope(searchScope, candidate)) { + if (candidate instanceof PsiAnonymousClass) { + return consumer.process(candidate); + } + + final String name = candidate.getName(); + if (name != null && parameters.getNameCondition().value(name) && !consumer.process(candidate)) { + return false; + } + } + + if (parameters.isCheckDeep() && !(candidate instanceof PsiAnonymousClass) && !isFinal(candidate)) { + stack.push(PsiAnchor.create(candidate)); + } return true; } }; - stack.push(Pair.create(createHardReference(baseClass), qname)); - final GlobalSearchScope projectScope = GlobalSearchScope.allScope(PsiUtilCore.getProjectInReadAction(baseClass)); - final JavaPsiFacade facade = JavaPsiFacade.getInstance(projectScope.getProject()); + + ApplicationManager.getApplication().runReadAction(new Runnable() { + @Override + public void run() { + stack.push(PsiAnchor.create(baseClass)); + } + }); + final GlobalSearchScope projectScope = GlobalSearchScope.allScope(project); + while (!stack.isEmpty()) { ProgressIndicatorProvider.checkCanceled(); - Pair, String> pair = stack.pop(); - PsiClass psiClass = pair.getFirst().get(); - final String fqn = pair.getSecond(); - if (psiClass == null) { - psiClass = ApplicationManager.getApplication().runReadAction(new Computable() { + final PsiAnchor anchor = stack.pop(); + if (!processed.add(anchor)) continue; + + PsiClass psiClass = ApplicationManager.getApplication().runReadAction(new Computable() { @Override public PsiClass compute() { - return facade.findClass(fqn, projectScope); + return (PsiClass)anchor.retrieve(); } }); - if (psiClass == null) continue; - } - if (fqn == null) { - if (!processed.add(psiClass)) continue; - } - else { - if (!processedFqns.add(fqn)) continue; - } + if (psiClass == null) continue; currentBase.set(psiClass); if (!DirectClassInheritorsSearch.search(psiClass, projectScope, parameters.isIncludeAnonymous(), false).forEach(processor)) return; } } - private static Reference createHardReference(final PsiClass candidate) { - return new SoftReference(candidate){ + private static boolean isJavaLangObject(@NotNull final PsiClass baseClass) { + return ApplicationManager.getApplication().runReadAction(new Computable() { @Override - public PsiClass get() { - return candidate; + public Boolean compute() { + return baseClass.isValid() && CommonClassNames.JAVA_LANG_OBJECT.equals(baseClass.getQualifiedName()); } - }; + }); } private static boolean isFinal(@NotNull final PsiClass baseClass) {