boolean (@NotNull final DirectClassInheritorsSearch.SearchParameters parameters, @NotNull final Processor<? super PsiClass> processor) { if (!parameters.shouldSearchInLanguage(JavaLanguage.INSTANCE)) { return true; } PsiClass baseClass = getClassToSearch(parameters); assert parameters.isCheckInheritance(); SearchScope scope = parameters.getScope(); final Project project = PsiUtilCore.getProjectInReadAction(baseClass); if (JavaClassInheritorsSearcher.isJavaLangObject(baseClass)) { SearchScope useScope = ReadAction.compute(baseClass::getUseScope); SearchScope actualScope = useScope.intersectWith(scope); return AllClassesSearch.search(actualScope, project).allowParallelProcessing().forEach(psiClass -> { ProgressManager.checkCanceled(); if (shortCircuitCandidate(psiClass)) return true; return processor.process(psiClass); }); } PsiClass[] cache = getOrCalculateDirectSubClasses(project, baseClass, parameters); if (cache.length == 0) { return true; } VirtualFile baseClassJarFile = null; // iterate by same-FQN groups. For each group process only same-jar subclasses, or all of them if they are all outside the jarFile. int groupStart = 0; boolean sameJarClassFound = false; String currentFQN = null; boolean[] isOutOfScope = new boolean[cache.length]; // here we cache results of isInScope(scope, subClass) to avoid calculating it twice for (int i = 0; i < cache.length; i++) { ProgressManager.checkCanceled(); PsiClass subClass = cache[i]; if (subClass instanceof PsiAnonymousClass) { // we reached anonymous classes tail, process them all and exit if (!parameters.includeAnonymous()) { return flushCurrentGroup(cache, isOutOfScope, sameJarClassFound, groupStart, i, processor); } } if (!isInScope(scope, subClass)) { isOutOfScope[i] = true; continue; } String fqn = ReadAction.compute(subClass::getQualifiedName); if (currentFQN != null && Objects.equals(fqn, currentFQN)) { VirtualFile currentJarFile = getJarFile(subClass); if (baseClassJarFile == null) { baseClassJarFile = getJarFile(baseClass); } boolean fromSameJar = Comparing.equal(currentJarFile, baseClassJarFile); if (fromSameJar) { if (!processor.process(subClass)) return false; sameJarClassFound = true; } } else { currentFQN = fqn; // the end of the same-FQN group. Process only same-jar classes in subClasses[groupStart..i-1] group or the whole group if there were none. if (!flushCurrentGroup(cache, isOutOfScope, sameJarClassFound, groupStart, i, processor)) return false; groupStart = i; sameJarClassFound = false; } } return flushCurrentGroup(cache, isOutOfScope, sameJarClassFound, groupStart, cache.length, processor); }