private NodeSourceSnapshotDelta updateDependencyGraph()

in sources/java-incremental-compilation/jvm-inc-builder/src/com/intellij/tools/build/bazel/jvmIncBuilder/GraphUpdater.java [34:113]


  private NodeSourceSnapshotDelta updateDependencyGraph(DependencyGraph depGraph, NodeSourceSnapshotDelta snapshotDelta, Delta delta, boolean errorsDetected, List<Graph> extParts, boolean isAfterCompilation) {
    if (snapshotDelta.isRecompileAll()) {
      if (isAfterCompilation) {
        if (errorsDetected) {
          // do nothing
          return new SnapshotDeltaImpl(snapshotDelta.getBaseSnapshot());
        }
      }
      else {
        if (delta.isSourceOnly()) {
          return snapshotDelta;
        }
      }
    }

    NodeSourceSnapshot baseSnapshot = snapshotDelta.getBaseSnapshot();
    Predicate<NodeSource> currentChunkScopeFilter = s -> contains(baseSnapshot.getElements(), s);
    DifferentiateParameters params = DifferentiateParametersBuilder.create(myTargetName)
      .compiledWithErrors(errorsDetected)
      .calculateAffected(!snapshotDelta.isRecompileAll())
      .processConstantsIncrementally(true)
      .withAffectionFilter(currentChunkScopeFilter)
      .withChunkStructureFilter(currentChunkScopeFilter).get();

    DifferentiateResult diffResult = depGraph.differentiate(delta, params, extParts);

    if (snapshotDelta.isRecompileAll() && isAfterCompilation) {
      depGraph.integrate(diffResult); // save full graph state
      return new SnapshotDeltaImpl(snapshotDelta.getBaseSnapshot());
    }

    NodeSourceSnapshotDelta nextSnapshotDelta;
    if (isAfterCompilation) {
      nextSnapshotDelta = new SnapshotDeltaImpl(snapshotDelta.getBaseSnapshot());
    }
    else {
      // the delta does not correspond to real compilation session,
      // mark files for recompilation in the existing delta and keep information about deleted files or already modified files
      nextSnapshotDelta = snapshotDelta;
    }

    if (!diffResult.isIncremental()) {
      // recompile whole target, no integrate necessary
      nextSnapshotDelta.markRecompileAll();
      return nextSnapshotDelta;
    }

    if (!errorsDetected && params.isCalculateAffected()) {
      // some compilers (and compiler plugins) may produce different outputs for the same set of inputs.
      // This might cause corresponding graph Nodes to be considered as always 'changed'. In some scenarios this may lead to endless build loops
      // This fallback logic detects such loops and recompiles the whole module chunk instead.
      Set<NodeSource> affectedForChunk = Iterators.collect(Iterators.filter(diffResult.getAffectedSources(), params.belongsToCurrentCompilationChunk()::test), new HashSet<>());
      if (!affectedForChunk.isEmpty() && !myAllAffectedSources.addAll(affectedForChunk)) {
        // all affected files in this round have already been affected in previous rounds. This might indicate a build cycle => recompiling whole chunk
        // todo: diagnostic
        //LOG.info("Build cycle detected for " + chunk.getName() + "; recompiling whole module chunk");
        // turn on non-incremental mode for the current target  => next time the whole target is recompiled and affected files won't be calculated anymore
        nextSnapshotDelta.markRecompileAll();
        return nextSnapshotDelta;
      }
    }

    for (NodeSource src : diffResult.getAffectedSources()) {

      if (isJavaModuleInfo(src)) {
        // recompile whole target, no integrate necessary
        nextSnapshotDelta.markRecompileAll();
        return nextSnapshotDelta;
      }

      nextSnapshotDelta.markRecompile(src);
    }

    if (!errorsDetected && isAfterCompilation) {
      // do not integrate delta, if compilation has not happened, to keep information about deleted paths
      depGraph.integrate(diffResult);
    }

    return nextSnapshotDelta;
  }