<T extends WordRequestInfo> boolean processGlobalRequests(@NotNull Map<TextIndexQuery, Collection<T>> singles,
                                                            @NotNull ProgressIndicator progress,
                                                            @NotNull Map<T, Processor<CandidateFileInfo>> localProcessors) {
    progress.pushState();
    progress.setText(IndexingBundle.message("psi.scanning.files.progress"));
    boolean result;

    try {
      // files which are target of the search
      Map<VirtualFile, Collection<T>> targetFiles = new HashMap<>();
      // directories in which target files are contained
      Map<VirtualFile, Collection<T>> nearDirectoryFiles = new HashMap<>();
      // intersectionCandidateFiles holds files containing words from all requests in `singles` and words in corresponding container names
      Map<VirtualFile, Collection<T>> intersectionCandidateFiles = new HashMap<>();
      // restCandidateFiles holds files containing words from all requests in `singles` but EXCLUDING words in corresponding container names
      Map<VirtualFile, Collection<T>> restCandidateFiles = new HashMap<>();
      int totalSize = collectFiles(singles, targetFiles, nearDirectoryFiles, intersectionCandidateFiles, restCandidateFiles);

      if (totalSize == 0) {
        return true;
      }

      Set<String> allWords = new TreeSet<>();
      for (WordRequestInfo singleRequest : localProcessors.keySet()) {
        ProgressManager.checkCanceled();
        allWords.add(singleRequest.getWord());
      }
      progress.setText(IndexingBundle.message("psi.search.for.word.progress", concat(allWords), totalSize));

      int alreadyProcessedFiles = 0;
      if (!targetFiles.isEmpty()) {
        result = processCandidates(localProcessors, targetFiles, progress, totalSize, alreadyProcessedFiles);
        if (!result) return false;
        alreadyProcessedFiles += targetFiles.size();
      }
      if (!nearDirectoryFiles.isEmpty()) {
        result = processCandidates(localProcessors, nearDirectoryFiles, progress, totalSize, alreadyProcessedFiles);
        if (!result) return false;
        alreadyProcessedFiles += nearDirectoryFiles.size();
      }
      if (!intersectionCandidateFiles.isEmpty()) {
        result = processCandidates(localProcessors, intersectionCandidateFiles, progress, totalSize, alreadyProcessedFiles);
        if (!result) return false;
        alreadyProcessedFiles += intersectionCandidateFiles.size();
      }
      result = processCandidates(localProcessors, restCandidateFiles, progress, totalSize, alreadyProcessedFiles);
    }
    finally {
      progress.popState();
    }

    return result;
  }
<T extends WordRequestInfo> boolean processGlobalRequests(@NotNull Map<TextIndexQuery, Collection<T>> singles,
                                                            @NotNull ProgressIndicator progress,
                                                            @NotNull Map<T, Processor<CandidateFileInfo>> localProcessors)