private static <T extends BuildTarget<R>, R extends BuildRootDescriptor> void completeRecompiledSourcesSet(CompileContext context, Collection<T> targets) throws IOException {
    final CompileScope scope = context.getScope();
    for (T target : targets) {
      if (scope.isBuildForced(target)) {
        return; // assuming build is either forced for all targets in a chunk or for none of them
      }
    }

    final ProjectDescriptor pd = context.getProjectDescriptor();
    final Set<String> affectedOutputs = CollectionFactory.createFilePathSet();
    final Set<String> affectedSources = CollectionFactory.createFilePathSet();

    final List<SourceToOutputMapping> mappings = new ArrayList<>();
    for (T target : targets) {
      pd.fsState.processFilesToRecompile(context, target, new FileProcessor<>() {
        private SourceToOutputMapping srcToOut;
        @Override
        public boolean apply(@NotNull T target, @NotNull File file, @NotNull R root) throws IOException {
          final String src = FileUtil.toSystemIndependentName(file.getPath());
          if (affectedSources.add(src)) {
            if (srcToOut == null) { // lazy init
              srcToOut = pd.dataManager.getSourceToOutputMap(target);
              mappings.add(srcToOut);
            }
            final Collection<String> outs = srcToOut.getOutputs(src);
            if (outs != null) {
              // Temporary hack for KTIJ-197
              // Change of only one input of *.kotlin_module files didn't trigger recompilation of all inputs in old behaviour.
              // Now it does. It isn't yet obvious whether it is right or wrong behaviour. Let's leave old behaviour for a
              // while for safety and keeping kotlin incremental JPS tests green
              List<String> filteredOuts =
                ContainerUtil.filter(outs, out -> !"kotlin_module".equals(StringUtil.substringAfterLast(out, ".")));
              affectedOutputs.addAll(filteredOuts);
            }
          }
          return true;
        }
      });
    }

    if (!affectedOutputs.isEmpty()) {
      for (SourceToOutputMapping srcToOut : mappings) {
        for (String src : srcToOut.getSources()) {
          if (!affectedSources.contains(src)) {
            for (Iterator<String> it = srcToOut.getOutputsIterator(src); it.hasNext(); ) {
              if (affectedOutputs.contains(it.next())) {
                FSOperations.markDirtyIfNotDeleted(context, CompilationRound.CURRENT, new File(src));
                break;
              }
            }
          }
        }
      }
    }

  }
private static <T extends BuildTarget<R>, R extends BuildRootDescriptor> void completeRecompiledSourcesSet(CompileContext context, Collection<T> targets)