@NotNull
  private TIntHashSet calcForwardRefs(
      @NotNull final VirtualFile virtualFile, @NotNull final ProgressIndicator indicator)
      throws IndexNotReadyException, ApplicationUtil.CannotRunReadActionException {

    final TIntHashSet forward = new TIntHashSet();

    final PsiFile psiFile =
        ApplicationUtil.tryRunReadAction(
            () -> {
              if (myProject.isDisposed()) throw new ProcessCanceledException();
              if (fileCount.incrementAndGet() % 100 == 0) {
                PsiManager.getInstance(myProject).dropResolveCaches();
                try {
                  storage.flush();
                  log.flush();
                } catch (IOException e) {
                  LOG.error(e);
                }
              }

              return PsiManager.getInstance(myProject).findFile(virtualFile);
            });
    final int fileId = getAbsId(virtualFile);
    if (psiFile != null) {
      bytesSize.addAndGet(virtualFile.getLength());
      final Set<PsiElement> resolved = new THashSet<PsiElement>();
      ApplicationUtil.tryRunReadAction(
          new Runnable() {
            @Override
            public void run() {
              indicator.checkCanceled();

              if (psiFile instanceof PsiJavaFile) {
                psiFile.accept(
                    new JavaRecursiveElementWalkingVisitor() {
                      @Override
                      public void visitReferenceElement(PsiJavaCodeReferenceElement reference) {
                        indicator.checkCanceled();
                        resolveReference(reference, resolved);

                        super.visitReferenceElement(reference);
                      }
                    });
              } else {
                psiFile.accept(
                    new PsiRecursiveElementWalkingVisitor() {
                      @Override
                      public void visitElement(PsiElement element) {
                        for (PsiReference reference : element.getReferences()) {
                          indicator.checkCanceled();
                          resolveReference(reference, resolved);
                        }
                        super.visitElement(element);
                      }
                    });
              }

              indicator.checkCanceled();
              for (PsiElement element : resolved) {
                PsiFile file = element.getContainingFile();
                addIdAndSuperClasses(file, forward);
              }
            }
          });
    }

    forward.remove(fileId);
    return forward;
  }
  private void initListeners(@NotNull MessageBus messageBus, @NotNull PsiManager psiManager) {
    messageBus
        .connect()
        .subscribe(
            VirtualFileManager.VFS_CHANGES,
            new BulkFileListener.Adapter() {
              @Override
              public void after(@NotNull List<? extends VFileEvent> events) {
                fileCount.set(0);
                List<VirtualFile> files =
                    ContainerUtil.mapNotNull(
                        events,
                        new Function<VFileEvent, VirtualFile>() {
                          @Override
                          public VirtualFile fun(VFileEvent event) {
                            return event.getFile();
                          }
                        });
                queue(files, "VFS events " + events.size());
              }
            });
    psiManager.addPsiTreeChangeListener(
        new PsiTreeChangeAdapter() {
          @Override
          public void childrenChanged(@NotNull PsiTreeChangeEvent event) {
            PsiFile file = event.getFile();
            VirtualFile virtualFile = PsiUtilCore.getVirtualFile(file);
            if (virtualFile != null) {
              queue(Collections.singletonList(virtualFile), event);
            }
          }

          @Override
          public void propertyChanged(@NotNull PsiTreeChangeEvent event) {
            childrenChanged(event);
          }
        });

    messageBus
        .connect()
        .subscribe(
            DumbService.DUMB_MODE,
            new DumbService.DumbModeListener() {
              @Override
              public void enteredDumbMode() {
                disable();
              }

              @Override
              public void exitDumbMode() {
                enable();
              }
            });
    messageBus
        .connect()
        .subscribe(
            PowerSaveMode.TOPIC,
            new PowerSaveMode.Listener() {
              @Override
              public void powerSaveStateChanged() {
                if (PowerSaveMode.isEnabled()) {
                  enable();
                } else {
                  disable();
                }
              }
            });
    myApplication.addApplicationListener(
        new ApplicationAdapter() {
          @Override
          public void beforeWriteActionStart(@NotNull Object action) {
            disable();
          }

          @Override
          public void writeActionFinished(@NotNull Object action) {
            enable();
          }

          @Override
          public void applicationExiting() {
            disable();
          }
        },
        this);
    VirtualFileManager.getInstance()
        .addVirtualFileManagerListener(
            new VirtualFileManagerListener() {
              @Override
              public void beforeRefreshStart(boolean asynchronous) {
                disable();
              }

              @Override
              public void afterRefreshFinish(boolean asynchronous) {
                enable();
              }
            },
            this);
    HeavyProcessLatch.INSTANCE.addListener(
        new HeavyProcessLatch.HeavyProcessListener() {
          @Override
          public void processStarted() {}

          @Override
          public void processFinished() {
            wakeUp();
          }
        },
        this);
  }