private void runMainPasses(@NotNull List<? extends VirtualFile> files,
                             @NotNull Map<? super Document, ? super List<HighlightInfo>> result,
                             @NotNull ProgressIndicatorEx progress,
                             @Nullable HighlightSeverity minimumSeverity) {
    ApplicationManager.getApplication().assertIsNonDispatchThread();
    ApplicationManager.getApplication().assertReadAccessNotAllowed();
    progress.setIndeterminate(false);
    List<Pair<VirtualFile, DaemonProgressIndicator>> daemonIndicators = Collections.synchronizedList(new ArrayList<>(files.size()));
    progress.addStateDelegate(new AbstractProgressIndicatorExBase() {
      @Override
      public void cancel() {
        super.cancel();
        daemonIndicators.forEach(daemonIndicator -> daemonIndicator.getSecond().cancel());
      }
    });
    while (true) {
      daemonIndicators.clear();
      daemonIndicators.addAll(ContainerUtil.map(files, file -> Pair.create(file, new DaemonProgressIndicator())));
      Disposable disposable = Disposer.newDisposable();
      try {
        SensitiveProgressWrapper wrapper = new SensitiveProgressWrapper(progress);
        ReadAction.run(() -> {
          ApplicationManager.getApplication().addApplicationListener(new ApplicationListener() {
            @Override
            public void beforeWriteActionStart(@NotNull Object action) {
              wrapper.cancel();
              daemonIndicators.forEach(daemonIndicator -> daemonIndicator.getSecond().cancel());
            }
          }, disposable);
          // there is a chance we are racing with the write action, in which case just registered listener might not be called, retry.
          if (ApplicationManagerEx.getApplicationEx().isWriteActionPending()) {
            throw new ProcessCanceledException();
          }
        });

        AtomicInteger filesCompleted = new AtomicInteger();
        JobLauncher.getInstance().invokeConcurrentlyUnderProgress(daemonIndicators, wrapper, pair -> {
          VirtualFile file = pair.getFirst();
          wrapper.setText(ReadAction.compute(() -> ProjectUtil.calcRelativeToProjectPath(file, myProject)));
          DaemonProgressIndicator daemonIndicator = pair.getSecond();
          runMainPasses(file, result, daemonIndicator, minimumSeverity);
          int completed = filesCompleted.incrementAndGet();
          wrapper.setFraction((double)completed / files.size());
          return true;
        });
        break;
      }
      catch (ProcessCanceledException e) {
        if (progress.isCanceled()) {
          throw e;
        }
        //retry if one of the daemonIndicators was canceled by started write action
      }
      finally {
        Disposer.dispose(disposable);
      }
      WriteAction.runAndWait(() -> {}); // wait until the current write action is finished
    }
  }
private void runMainPasses(@NotNull List<? extends VirtualFile> files,
                             @NotNull Map<? super Document, ? super List<HighlightInfo>> result,
                             @NotNull ProgressIndicatorEx progress,
                             @Nullable HighlightSeverity minimumSeverity)