private void processDirtyFiles(DirtyFilesHolder<ArtifactRootDescriptor, ArtifactBuildTarget> holder) throws ProjectBuildException, IOException {
      context.checkCanceled();

      if (!holder.hasRemovedFiles() && !holder.hasDirtyFiles()) {
        return;
      }

      final Collection<String> deletedFiles = holder.getRemovedFiles(target);

      final SourceToOutputMapping srcOutMapping = pd.dataManager.getSourceToOutputMap(target);

      final MultiMap<String, String> filesToDelete = new MultiMap<>();
      final Set<String> deletedOutputPaths = CollectionFactory.createFilePathSet();
      for (String sourcePath : deletedFiles) {
        final Collection<String> outputPaths = srcOutMapping.getOutputs(sourcePath);
        if (outputPaths != null) {
          for (String outputPath : outputPaths) {
            if (deletedOutputPaths.add(outputPath)) {
              collectSourcesCorrespondingToOutput(outputPath, sourcePath, deletedFiles, outSrcMapping, filesToDelete);
            }
          }
        }
      }

      final Set<String> changedOutputPaths = CollectionFactory.createFilePathSet();
      holder.processDirtyFiles(new FileProcessor<>() {
        @Override
        public boolean apply(@NotNull ArtifactBuildTarget target, @NotNull File file, @NotNull ArtifactRootDescriptor root) throws IOException {
          int rootIndex = root.getRootIndex();
          String sourcePath = FileUtil.toSystemIndependentName(file.getPath());
          addFileToProcess(rootIndex, sourcePath, deletedFiles);
          final Collection<String> outputPaths = srcOutMapping.getOutputs(sourcePath);
          if (outputPaths != null) {
            for (String outputPath : outputPaths) {
              if (changedOutputPaths.add(outputPath)) {
                collectSourcesCorrespondingToOutput(outputPath, sourcePath, deletedFiles, outSrcMapping, filesToDelete);
              }
            }
          }
          return true;
        }
      });

      BuildOperations.cleanOutputsCorrespondingToChangedFiles(context, holder);
      for (String outputPath : changedOutputPaths) {
        outSrcMapping.remove(outputPath);
      }

      deleteOutdatedFiles(filesToDelete, srcOutMapping, outSrcMapping);
    }
private void processDirtyFiles(DirtyFilesHolder<ArtifactRootDescriptor, ArtifactBuildTarget> holder)