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;
}