static void markDirtyFiles(
      CompileContext context,
      BuildTarget<?> target,
      final CompilationRound round,
      Timestamps timestamps,
      boolean forceMarkDirty,
      @Nullable THashSet<File> currentFiles,
      @Nullable FileFilter filter)
      throws IOException {
    if (filter == null && forceMarkDirty) {
      addCompletelyMarkedDirtyTarget(context, target);
    }

    for (BuildRootDescriptor rd :
        context.getProjectDescriptor().getBuildRootIndex().getTargetRoots(target, context)) {
      if (!rd.getRootFile().exists()
          ||
          // temp roots are managed by compilers themselves
          (rd instanceof JavaSourceRootDescriptor && ((JavaSourceRootDescriptor) rd).isTemp)) {
        continue;
      }
      if (filter == null) {
        context.getProjectDescriptor().fsState.clearRecompile(rd);
      }
      final FSCache fsCache =
          rd.canUseFileCache() ? context.getProjectDescriptor().getFSCache() : FSCache.NO_CACHE;
      traverseRecursively(
          context,
          rd,
          round,
          rd.getRootFile(),
          timestamps,
          forceMarkDirty,
          currentFiles,
          filter,
          fsCache);
    }
  }