@NotNull
 private static Set<VirtualFile> getLocalScopeFiles(@NotNull LocalSearchScope scope) {
   Set<VirtualFile> files = new LinkedHashSet<VirtualFile>();
   for (PsiElement element : scope.getScope()) {
     PsiFile file = element.getContainingFile();
     if (file != null) {
       ContainerUtil.addIfNotNull(files, file.getVirtualFile());
     }
   }
   return files;
 }
  private static int addToUsages(
      @NotNull Document document,
      @NotNull Processor<UsageInfo> consumer,
      @NotNull FindModel findModel,
      @NotNull final PsiFile psiFile,
      @NotNull int[] offsetRef,
      int maxUsages) {
    int count = 0;
    CharSequence text = document.getCharsSequence();
    int textLength = document.getTextLength();
    int offset = offsetRef[0];

    Project project = psiFile.getProject();

    FindManager findManager = FindManager.getInstance(project);
    while (offset < textLength) {
      FindResult result = findManager.findString(text, offset, findModel, psiFile.getVirtualFile());
      if (!result.isStringFound()) break;

      final SearchScope customScope = findModel.getCustomScope();
      if (customScope instanceof LocalSearchScope) {
        final TextRange range = new TextRange(result.getStartOffset(), result.getEndOffset());
        if (!((LocalSearchScope) customScope).containsRange(psiFile, range)) break;
      }
      UsageInfo info = new FindResultUsageInfo(findManager, psiFile, offset, findModel, result);
      if (!consumer.process(info)) {
        throw new ProcessCanceledException();
      }
      count++;

      final int prevOffset = offset;
      offset = result.getEndOffset();

      if (prevOffset == offset) {
        // for regular expr the size of the match could be zero -> could be infinite loop in finding
        // usages!
        ++offset;
      }
      if (maxUsages > 0 && count >= maxUsages) {
        break;
      }
    }
    offsetRef[0] = offset;
    return count;
  }
 // returns number of hits
 static int processUsagesInFile(
     @NotNull final PsiFile psiFile,
     @NotNull final FindModel findModel,
     @NotNull final Processor<UsageInfo> consumer) {
   if (findModel.getStringToFind().isEmpty()) {
     if (!ApplicationManager.getApplication()
         .runReadAction((Computable<Boolean>) () -> consumer.process(new UsageInfo(psiFile)))) {
       throw new ProcessCanceledException();
     }
     return 1;
   }
   final VirtualFile virtualFile = psiFile.getVirtualFile();
   if (virtualFile == null) return 0;
   if (virtualFile.getFileType().isBinary()) return 0; // do not decompile .class files
   final Document document =
       ApplicationManager.getApplication()
           .runReadAction(
               (Computable<Document>)
                   () ->
                       virtualFile.isValid()
                           ? FileDocumentManager.getInstance().getDocument(virtualFile)
                           : null);
   if (document == null) return 0;
   final int[] offset = {0};
   int count = 0;
   int found;
   ProgressIndicator indicator =
       ProgressWrapper.unwrap(ProgressManager.getInstance().getProgressIndicator());
   TooManyUsagesStatus tooManyUsagesStatus = TooManyUsagesStatus.getFrom(indicator);
   do {
     tooManyUsagesStatus.pauseProcessingIfTooManyUsages(); // wait for user out of read action
     found =
         ApplicationManager.getApplication()
             .runReadAction(
                 (Computable<Integer>)
                     () -> {
                       if (!psiFile.isValid()) return 0;
                       return addToUsages(
                           document, consumer, findModel, psiFile, offset, USAGES_PER_READ_ACTION);
                     });
     count += found;
   } while (found != 0);
   return count;
 }
  @NotNull
  private Set<PsiFile> getFilesForFastWordSearch() {
    String stringToFind = myFindModel.getStringToFind();
    if (stringToFind.isEmpty() || DumbService.getInstance(myProject).isDumb()) {
      return Collections.emptySet();
    }

    SearchScope customScope = myFindModel.getCustomScope();
    GlobalSearchScope scope =
        myPsiDirectory != null
            ? GlobalSearchScopesCore.directoryScope(myPsiDirectory, true)
            : myModule != null
                ? myModule.getModuleContentScope()
                : customScope instanceof GlobalSearchScope
                    ? (GlobalSearchScope) customScope
                    : toGlobal(customScope);
    if (scope == null) {
      scope = ProjectScope.getContentScope(myProject);
    }

    final Set<PsiFile> resultFiles = new LinkedHashSet<PsiFile>();

    if (TrigramIndex.ENABLED) {
      final Set<Integer> keys = ContainerUtil.newTroveSet();
      TrigramBuilder.processTrigrams(
          stringToFind,
          new TrigramBuilder.TrigramProcessor() {
            @Override
            public boolean execute(int value) {
              keys.add(value);
              return true;
            }
          });

      if (!keys.isEmpty()) {
        final List<VirtualFile> hits = new ArrayList<VirtualFile>();
        final GlobalSearchScope finalScope = scope;
        ApplicationManager.getApplication()
            .runReadAction(
                new Runnable() {
                  @Override
                  public void run() {
                    FileBasedIndex.getInstance()
                        .getFilesWithKey(
                            TrigramIndex.INDEX_ID,
                            keys,
                            new CommonProcessors.CollectProcessor<VirtualFile>(hits),
                            finalScope);
                  }
                });

        for (VirtualFile hit : hits) {
          if (myFileMask.value(hit)) {
            PsiFile file = findFile(hit);
            if (file != null) {
              resultFiles.add(file);
            }
          }
        }

        return resultFiles;
      }
    }

    PsiSearchHelperImpl helper =
        (PsiSearchHelperImpl) PsiSearchHelper.SERVICE.getInstance(myProject);
    helper.processFilesWithText(
        scope,
        UsageSearchContext.ANY,
        myFindModel.isCaseSensitive(),
        stringToFind,
        new Processor<VirtualFile>() {
          @Override
          public boolean process(VirtualFile file) {
            if (myFileMask.value(file)) {
              ContainerUtil.addIfNotNull(resultFiles, findFile(file));
            }
            return true;
          }
        });

    // in case our word splitting is incorrect
    CacheManager cacheManager = CacheManager.SERVICE.getInstance(myProject);
    PsiFile[] filesWithWord =
        cacheManager.getFilesWithWord(
            stringToFind, UsageSearchContext.ANY, scope, myFindModel.isCaseSensitive());
    for (PsiFile file : filesWithWord) {
      if (myFileMask.value(file.getVirtualFile())) {
        resultFiles.add(file);
      }
    }

    return resultFiles;
  }
  private void searchInFiles(
      @NotNull Collection<PsiFile> psiFiles,
      @NotNull FindUsagesProcessPresentation processPresentation,
      @NotNull final Processor<UsageInfo> consumer) {
    int i = 0;
    long totalFilesSize = 0;
    int count = 0;

    for (final PsiFile psiFile : psiFiles) {
      final VirtualFile virtualFile = psiFile.getVirtualFile();
      final int index = i++;
      if (virtualFile == null) continue;

      long fileLength = UsageViewManagerImpl.getFileLength(virtualFile);
      if (fileLength == -1) continue; // Binary or invalid

      final boolean skipProjectFile =
          ProjectCoreUtil.isProjectOrWorkspaceFile(virtualFile)
              && !myFindModel.isSearchInProjectFiles();
      if (skipProjectFile && !Registry.is("find.search.in.project.files")) continue;

      if (fileLength > SINGLE_FILE_SIZE_LIMIT) {
        myLargeFiles.add(psiFile);
        continue;
      }

      myProgress.checkCanceled();
      myProgress.setFraction((double) index / psiFiles.size());
      String text =
          FindBundle.message(
              "find.searching.for.string.in.file.progress",
              myFindModel.getStringToFind(),
              virtualFile.getPresentableUrl());
      myProgress.setText(text);
      myProgress.setText2(
          FindBundle.message("find.searching.for.string.in.file.occurrences.progress", count));

      int countInFile =
          FindInProjectUtil.processUsagesInFile(
              psiFile,
              myFindModel,
              new Processor<UsageInfo>() {
                @Override
                public boolean process(UsageInfo info) {
                  return skipProjectFile || consumer.process(info);
                }
              });

      if (countInFile > 0 && skipProjectFile) {
        processPresentation.projectFileUsagesFound(
            new Runnable() {
              @Override
              public void run() {
                FindModel model = myFindModel.clone();
                model.setSearchInProjectFiles(true);
                FindInProjectManager.getInstance(myProject).startFindInProject(model);
              }
            });
        continue;
      }

      count += countInFile;
      if (countInFile > 0) {
        totalFilesSize += fileLength;
        if (totalFilesSize > FILES_SIZE_LIMIT && !myWarningShown) {
          myWarningShown = true;
          String message =
              FindBundle.message(
                  "find.excessive.total.size.prompt",
                  UsageViewManagerImpl.presentableSize(totalFilesSize),
                  ApplicationNamesInfo.getInstance().getProductName());
          UsageLimitUtil.showAndCancelIfAborted(
              myProject, message, processPresentation.getUsageViewPresentation());
        }
      }
    }
  }