@Nullable
  protected DirCoverageInfo collectFolderCoverage(@NotNull final VirtualFile dir,
                                                  final @NotNull CoverageDataManager dataManager,
                                                  final CoverageAnnotatorRunner annotator,
                                                  final ProjectData projectInfo, boolean trackTestFolders,
                                                  @NotNull final ProjectFileIndex index,
                                                  @NotNull final CoverageEngine coverageEngine,
                                                  Set<? super VirtualFile> visitedDirs,
                                                  @NotNull final Map<String, String> normalizedFiles2Files) {
    if (ReadAction.compute(() -> !index.isInContent(dir) && !index.isInLibrary(dir))) {
      return null;
    }

    if (visitedDirs.contains(dir)) {
      return null;
    }

    if (!shouldCollectCoverageInsideLibraryDirs()) {
      if (ReadAction.compute(() -> index.isInLibrary(dir))) {
        return null;
      }
    }
    visitedDirs.add(dir);

    final String dirPath = normalizeFilePath(dir.getPath());

    final boolean isInTestSrcContent = ReadAction.compute(() -> TestSourcesFilter.isTestSources(dir, getProject()));
    if (isInTestSrcContent) {
      myTestDirectories.add(dirPath);
    }

    // Don't count coverage for tests folders if track test folders is switched off
    if (!trackTestFolders && isInTestSrcContent) {
      return null;
    }

    final VirtualFile[] children = dataManager.doInReadActionIfProjectOpen(dir::getChildren);
    if (children == null) {
      return null;
    }

    final DirCoverageInfo dirCoverageInfo = new DirCoverageInfo();

    for (VirtualFile fileOrDir : children) {
      if (fileOrDir.isDirectory()) {
        final DirCoverageInfo childCoverageInfo =
          collectFolderCoverage(fileOrDir, dataManager, annotator, projectInfo, trackTestFolders, index,
                                coverageEngine, visitedDirs, normalizedFiles2Files);

        if (childCoverageInfo != null) {
          dirCoverageInfo.totalFilesCount += childCoverageInfo.totalFilesCount;
          dirCoverageInfo.coveredFilesCount += childCoverageInfo.coveredFilesCount;
          dirCoverageInfo.totalLineCount += childCoverageInfo.totalLineCount;
          dirCoverageInfo.coveredLineCount += childCoverageInfo.coveredLineCount;
        }
      }
      else if (coverageEngine.coverageProjectViewStatisticsApplicableTo(fileOrDir)) {
        // let's count statistics only for ruby-based files

        final FileCoverageInfo fileInfo =
          collectBaseFileCoverage(fileOrDir, annotator, projectInfo, normalizedFiles2Files);

        if (fileInfo != null) {
          dirCoverageInfo.totalLineCount += fileInfo.totalLineCount;
          dirCoverageInfo.totalFilesCount++;

          if (fileInfo.coveredLineCount > 0) {
            dirCoverageInfo.coveredFilesCount++;
            dirCoverageInfo.coveredLineCount += fileInfo.coveredLineCount;
          }
        }
      }
    }


    //TODO - toplevelFilesCoverage - is unused variable!

    // no sense to include directories without ruby files
    if (dirCoverageInfo.totalFilesCount == 0) {
      return null;
    }

    if (isInTestSrcContent) {
      annotator.annotateTestDirectory(dirPath, dirCoverageInfo);
    }
    else {
      annotator.annotateSourceDirectory(dirPath, dirCoverageInfo);
    }

    return dirCoverageInfo;
  }
@Nullable
  protected DirCoverageInfo collectFolderCoverage(@NotNull final VirtualFile dir,
                                                  final @NotNull CoverageDataManager dataManager,
                                                  final CoverageAnnotatorRunner annotator,
                                                  final ProjectData projectInfo, boolean trackTestFolders,
                                                  @NotNull final ProjectFileIndex index,
                                                  @NotNull final CoverageEngine coverageEngine,
                                                  Set<? super VirtualFile> visitedDirs,
                                                  @NotNull final Map<String, String> normalizedFiles2Files)