@Override
  public boolean execute(@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);
  }
@Override
  public boolean execute(@NotNull final DirectClassInheritorsSearch.SearchParameters parameters, @NotNull final Processor<? super PsiClass> processor)