mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-08 15:09:39 +07:00
JPS mappings for incremental compilation refactoring: mark hierarchy-induced dependencies on initial stage before compilation starts
GitOrigin-RevId: 2d4543e13729ee6a8d1df393565e6d128f59645f
This commit is contained in:
committed by
intellij-monorepo-bot
parent
fb25fbd19e
commit
f8674d9894
@@ -2783,6 +2783,7 @@ f:org.jetbrains.jps.dependency.AffectionScopeMetaUsage
|
||||
- hashCode():I
|
||||
- write(org.jetbrains.jps.dependency.GraphDataOutput):V
|
||||
org.jetbrains.jps.dependency.BackDependencyIndex
|
||||
- s:createEmpty(java.lang.String):org.jetbrains.jps.dependency.BackDependencyIndex
|
||||
- a:getDependencies(org.jetbrains.jps.dependency.ReferenceID):java.lang.Iterable
|
||||
- a:getKeys():java.lang.Iterable
|
||||
- a:getName():java.lang.String
|
||||
@@ -2808,10 +2809,11 @@ org.jetbrains.jps.dependency.Delta
|
||||
- a:associate(org.jetbrains.jps.dependency.Node,java.lang.Iterable):V
|
||||
- a:getBaseSources():java.util.Set
|
||||
- a:getDeletedSources():java.util.Set
|
||||
- a:isSourceOnly():Z
|
||||
org.jetbrains.jps.dependency.DependencyGraph
|
||||
- java.io.Closeable
|
||||
- org.jetbrains.jps.dependency.Graph
|
||||
- a:createDelta(java.lang.Iterable,java.lang.Iterable):org.jetbrains.jps.dependency.Delta
|
||||
- a:createDelta(java.lang.Iterable,java.lang.Iterable,Z):org.jetbrains.jps.dependency.Delta
|
||||
- a:differentiate(org.jetbrains.jps.dependency.Delta,org.jetbrains.jps.dependency.DifferentiateParameters):org.jetbrains.jps.dependency.DifferentiateResult
|
||||
- a:integrate(org.jetbrains.jps.dependency.DifferentiateResult):V
|
||||
org.jetbrains.jps.dependency.DifferentiateContext
|
||||
|
||||
@@ -131,12 +131,8 @@ public final class JavaBuilderUtil {
|
||||
|
||||
NodeSourcePathMapper pathMapper = graphConfig.getPathMapper();
|
||||
Set<File> inputFiles = getFilesContainer(context, FILES_TO_COMPILE_KEY);
|
||||
Set<File> compiledWithErrors = getFilesContainer(context, COMPILED_WITH_ERRORS_KEY);
|
||||
List<Pair<Node<?, ?>, Iterable<NodeSource>>> compiledNodes;
|
||||
|
||||
if (callback != null) {
|
||||
compiledNodes = callback.getNodes();
|
||||
|
||||
// Important: in case of errors some sources sent to recompilation might not have corresponding output classes either because a source has compilation errors
|
||||
// or because compiler stopped compilation and has not managed to compile some sources.
|
||||
// In this case use empty set of delta's "base sources" for dependency calculation, so that only actually recompiled sources will take part in dependency analysis and affected files calculation.
|
||||
@@ -145,9 +141,10 @@ public final class JavaBuilderUtil {
|
||||
Set<File> deltaBaseSources = Utils.errorsDetected(context)? Collections.emptySet() : inputFiles;
|
||||
delta = graphConfig.getGraph().createDelta(
|
||||
Iterators.map(deltaBaseSources, pathMapper::toNodeSource),
|
||||
Iterators.map(getRemovedPaths(chunk, dirtyFilesHolder), pathMapper::toNodeSource)
|
||||
Iterators.map(getRemovedPaths(chunk, dirtyFilesHolder), pathMapper::toNodeSource),
|
||||
false
|
||||
);
|
||||
for (var nodeData : compiledNodes) {
|
||||
for (var nodeData : callback.getNodes()) {
|
||||
delta.associate(nodeData.getFirst(), nodeData.getSecond());
|
||||
}
|
||||
// todo: consider using delta for marking additional sources for compilation
|
||||
@@ -157,32 +154,11 @@ public final class JavaBuilderUtil {
|
||||
// }
|
||||
//}
|
||||
}
|
||||
else {
|
||||
compiledNodes = Collections.emptyList();
|
||||
}
|
||||
|
||||
boolean additionalPassRequired = false;
|
||||
|
||||
if (Utils.errorsDetected(context) || !inputFiles.isEmpty() && compiledNodes.isEmpty()) {
|
||||
// In case of compilation errors additionally mark files referenced from "error"-files.
|
||||
// So next time compilation is invoked, the compilation scope will be broader: directly used dependencies will be compiled as well.
|
||||
DependencyGraph graph = graphConfig.getGraph();
|
||||
Set<File> errFiles = !compiledWithErrors.isEmpty()? compiledWithErrors : inputFiles;
|
||||
Iterable<Node<?, ?>> nodesWithErrors = Iterators.flat(Iterators.map(Iterators.map(errFiles, pathMapper::toNodeSource), graph::getNodes));
|
||||
Iterable<ReferenceID> usedDependencies = Iterators.unique(Iterators.map(Iterators.flat(Iterators.map(nodesWithErrors, Node::getUsages)), Usage::getElementOwner));
|
||||
for (File src : Iterators.filter(Iterators.map(Iterators.unique(Iterators.flat(Iterators.map(usedDependencies, graph::getSources))), ns -> pathMapper.toPath(ns).toFile()), f -> !inputFiles.contains(f))) {
|
||||
additionalPassRequired = true;
|
||||
FSOperations.markDirtyIfNotDeleted(context, CompilationRound.NEXT, src);
|
||||
}
|
||||
}
|
||||
|
||||
for (Key<?> key : List.of(GRAPH_DELTA_CALLBACK_KEY, FILES_TO_COMPILE_KEY, COMPILED_WITH_ERRORS_KEY, SUCCESSFULLY_COMPILED_FILES_KEY)) {
|
||||
key.set(context, null);
|
||||
}
|
||||
if (delta != null && updateDependencyGraph(context, delta, chunk, CompilationRound.NEXT, createOrFilter(SKIP_MARKING_DIRTY_FILTERS_KEY.get(context)))) {
|
||||
additionalPassRequired = true;
|
||||
}
|
||||
return additionalPassRequired;
|
||||
return delta != null && updateDependencyGraph(context, delta, chunk, CompilationRound.NEXT, createOrFilter(SKIP_MARKING_DIRTY_FILTERS_KEY.get(context)));
|
||||
}
|
||||
|
||||
Mappings delta = null;
|
||||
@@ -226,20 +202,25 @@ public final class JavaBuilderUtil {
|
||||
}
|
||||
|
||||
public static void markDirtyDependenciesForInitialRound(CompileContext context, DirtyFilesHolder<JavaSourceRootDescriptor, ModuleBuildTarget> dfh, ModuleChunk chunk) throws IOException {
|
||||
if (hasRemovedPaths(chunk, dfh)) {
|
||||
BuildDataManager dataManager = context.getProjectDescriptor().dataManager;
|
||||
GraphConfiguration graphConfig = dataManager.getDependencyGraph();
|
||||
if (isDepGraphEnabled() && graphConfig != null) {
|
||||
NodeSourcePathMapper mapper = graphConfig.getPathMapper();
|
||||
BuildDataManager dataManager = context.getProjectDescriptor().dataManager;
|
||||
GraphConfiguration graphConfig = dataManager.getDependencyGraph();
|
||||
if (isDepGraphEnabled() && graphConfig != null) {
|
||||
NodeSourcePathMapper mapper = graphConfig.getPathMapper();
|
||||
Set<NodeSource> toCompile = new HashSet<>();
|
||||
dfh.processDirtyFiles((target, file, root) -> toCompile.add(mapper.toNodeSource(file)));
|
||||
if (!toCompile.isEmpty() || hasRemovedPaths(chunk, dfh)) {
|
||||
Delta delta = graphConfig.getGraph().createDelta(
|
||||
Collections.emptyList(), Iterators.map(getRemovedPaths(chunk, dfh), mapper::toNodeSource)
|
||||
toCompile, Iterators.map(getRemovedPaths(chunk, dfh), mapper::toNodeSource), true
|
||||
);
|
||||
updateDependencyGraph(context, delta, chunk, CompilationRound.CURRENT, null);
|
||||
return;
|
||||
}
|
||||
final Mappings delta = dataManager.getMappings().createDelta();
|
||||
final Set<File> empty = Collections.emptySet();
|
||||
updateMappings(context, delta, dfh, chunk, empty, empty, CompilationRound.CURRENT, null);
|
||||
}
|
||||
else {
|
||||
if (hasRemovedPaths(chunk, dfh)) {
|
||||
final Mappings delta = dataManager.getMappings().createDelta();
|
||||
final Set<File> empty = Collections.emptySet();
|
||||
updateMappings(context, delta, dfh, chunk, empty, empty, CompilationRound.CURRENT, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.jps.dependency;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
public interface BackDependencyIndex {
|
||||
@NotNull String getName();
|
||||
|
||||
@@ -13,4 +15,33 @@ public interface BackDependencyIndex {
|
||||
void indexNode(@NotNull Node<?, ?> node);
|
||||
|
||||
void integrate(Iterable<Node<?, ?>> deletedNodes, Iterable<Node<?, ?>> updatedNodes, BackDependencyIndex deltaIndex);
|
||||
|
||||
static BackDependencyIndex createEmpty(String name) {
|
||||
return new BackDependencyIndex() {
|
||||
@Override
|
||||
public @NotNull String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<ReferenceID> getKeys() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<ReferenceID> getDependencies(@NotNull ReferenceID id) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void indexNode(@NotNull Node<?, ?> node) {
|
||||
// nothing here
|
||||
}
|
||||
|
||||
@Override
|
||||
public void integrate(Iterable<Node<?, ?>> deletedNodes, Iterable<Node<?, ?>> updatedNodes, BackDependencyIndex deltaIndex) {
|
||||
// nothing here
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.jps.dependency;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -10,6 +10,12 @@ import java.util.Set;
|
||||
*/
|
||||
public interface Delta extends Graph {
|
||||
|
||||
/**
|
||||
* @return true, if this Delta describes only changes in sources and no Nodes were generated, because compiler has not been run.
|
||||
* Value false means the Delta object contains changes in sources and possibly in Nodes, because compiler has been run and new set of Nodes corresponding to the new content of sources has been generated
|
||||
*/
|
||||
boolean isSourceOnly();
|
||||
|
||||
/**
|
||||
* @param node node reflecting compilation unit built by a compiler
|
||||
* @param sources sources, that were used to build the node
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.jps.dependency;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -11,7 +11,7 @@ import java.io.IOException;
|
||||
*/
|
||||
public interface DependencyGraph extends Graph, Closeable {
|
||||
|
||||
Delta createDelta(Iterable<NodeSource> sourcesToProcess, Iterable<NodeSource> deletedSources) throws IOException;
|
||||
Delta createDelta(Iterable<NodeSource> sourcesToProcess, Iterable<NodeSource> deletedSources, boolean isSourceOnly) throws IOException;
|
||||
|
||||
DifferentiateResult differentiate(Delta delta, DifferentiateParameters params);
|
||||
|
||||
|
||||
@@ -26,11 +26,16 @@ public final class DeltaImpl extends GraphImpl implements Delta {
|
||||
private final Set<NodeSource> myBaseSources;
|
||||
private final Set<NodeSource> myDeletedSources;
|
||||
|
||||
public DeltaImpl(Set<NodeSource> baseSources, Iterable<NodeSource> deletedSources) throws IOException {
|
||||
DeltaImpl(Iterable<NodeSource> baseSources, Iterable<NodeSource> deletedSources) throws IOException {
|
||||
super(Containers.MEMORY_CONTAINER_FACTORY);
|
||||
addIndex(new SubclassesIndex(Containers.MEMORY_CONTAINER_FACTORY));
|
||||
myBaseSources = Collections.unmodifiableSet(baseSources);
|
||||
myDeletedSources = Collections.unmodifiableSet(Iterators.collect(deletedSources, new HashSet<>()));
|
||||
myBaseSources = Collections.unmodifiableSet(baseSources instanceof Set? (Set<? extends NodeSource>)baseSources : Iterators.collect(baseSources, new HashSet<>()));
|
||||
myDeletedSources = Collections.unmodifiableSet(deletedSources instanceof Set? (Set<? extends NodeSource>)deletedSources : Iterators.collect(deletedSources, new HashSet<>()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSourceOnly() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -28,8 +28,8 @@ public final class DependencyGraphImpl extends GraphImpl implements DependencyGr
|
||||
}
|
||||
|
||||
@Override
|
||||
public Delta createDelta(Iterable<NodeSource> compiledSources, Iterable<NodeSource> deletedSources) throws IOException {
|
||||
DeltaImpl delta = new DeltaImpl(completeSourceSet(compiledSources, deletedSources), deletedSources);
|
||||
public Delta createDelta(Iterable<NodeSource> compiledSources, Iterable<NodeSource> deletedSources, boolean isSourceOnly) throws IOException {
|
||||
Delta delta = isSourceOnly? new SourceOnlyDelta(myRegisteredIndices, compiledSources, deletedSources) : new DeltaImpl(compiledSources, deletedSources);
|
||||
|
||||
Set<String> deltaIndices = collect(map(delta.getIndices(), index -> index.getName()), new HashSet<>());
|
||||
if (!myRegisteredIndices.equals(deltaIndices)) {
|
||||
@@ -44,9 +44,9 @@ public final class DependencyGraphImpl extends GraphImpl implements DependencyGr
|
||||
|
||||
String sessionName = params.getSessionName();
|
||||
Iterable<NodeSource> deltaSources = delta.getSources();
|
||||
Set<NodeSource> allProcessedSources = collect(flat(Arrays.asList(delta.getBaseSources(), deltaSources, delta.getDeletedSources())), new HashSet<>());
|
||||
Set<NodeSource> allProcessedSources = delta.isSourceOnly()? delta.getDeletedSources() : collect(flat(Arrays.asList(delta.getBaseSources(), deltaSources, delta.getDeletedSources())), new HashSet<>());
|
||||
Set<Node<?, ?>> nodesBefore = collect(flat(map(allProcessedSources, this::getNodes)), Containers.createCustomPolicySet(DiffCapable::isSame, DiffCapable::diffHashCode));
|
||||
Set<Node<?, ?>> nodesAfter = collect(flat(map(deltaSources, delta::getNodes)), Containers.createCustomPolicySet(DiffCapable::isSame, DiffCapable::diffHashCode));
|
||||
Set<Node<?, ?>> nodesAfter = delta.isSourceOnly()? Collections.emptySet() : collect(flat(map(deltaSources, delta::getNodes)), Containers.createCustomPolicySet(DiffCapable::isSame, DiffCapable::diffHashCode));
|
||||
|
||||
// do not process 'removed' per-source file. This works when a class comes from exactly one source, but might not work, if a class can be associated with several sources
|
||||
// better make a node-diff over all compiled sources => the sets of removed, added, deleted _nodes_ will be more accurate and reflecting reality
|
||||
@@ -209,6 +209,26 @@ public final class DependencyGraphImpl extends GraphImpl implements DependencyGr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (delta.isSourceOnly()) {
|
||||
// Some nodes may be associated with multiple sources. In this case ensure that all these sources are sent to compilation
|
||||
Set<NodeSource> inputSources = delta.getBaseSources();
|
||||
Set<NodeSource> deleted = delta.getDeletedSources();
|
||||
Predicate<? super NodeSource> srcFilter = diffContext.getParams().belongsToCurrentCompilationChunk().and(s -> !deleted.contains(s));
|
||||
for (var node : flat(map(flat(inputSources, deleted), this::getNodes))) {
|
||||
Iterable<NodeSource> nodeSources = getSources(node.getReferenceID());
|
||||
if (count(nodeSources) > 1) {
|
||||
List<NodeSource> filteredNodeSources = collect(filter(nodeSources, srcFilter::test), new SmartList<>());
|
||||
// all sources associated with the node should be either marked 'dirty' or deleted
|
||||
if (find(filteredNodeSources, s -> !inputSources.contains(s)) != null) {
|
||||
for (NodeSource s : filteredNodeSources) {
|
||||
diffContext.affectNodeSource(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// do not include sources that were already compiled
|
||||
affectedSources.removeAll(allProcessedSources);
|
||||
// ensure sources explicitly marked by strategies are affected, even if these sources were compiled initially
|
||||
@@ -303,27 +323,6 @@ public final class DependencyGraphImpl extends GraphImpl implements DependencyGr
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a complete set of node sources based on the input set of node sources.
|
||||
* Some nodes may be associated with multiple sources. If a source from the input set is associated with such a node,
|
||||
* the method makes sure the output set contains the rest of the sources, the node is associated with
|
||||
*
|
||||
* @param sources set of node sources to be completed.
|
||||
* @param deletedSources registered deleted sources
|
||||
* @return complete set of node sources, containing all sources associated with nodes affected by the sources from the input set.
|
||||
*/
|
||||
private Set<NodeSource> completeSourceSet(Iterable<NodeSource> sources, Iterable<NodeSource> deletedSources) {
|
||||
// ensure initial sources are in the result
|
||||
Set<NodeSource> result = collect(sources, new HashSet<>()); // todo: check if a special hashing-policy set is required here
|
||||
Set<NodeSource> deleted = collect(deletedSources, new HashSet<>());
|
||||
|
||||
Set<Node<?, ?>> affectedNodes = collect(flat(map(flat(result, deleted), s -> getNodes(s))), new HashSet<>());
|
||||
for (var node : affectedNodes) {
|
||||
collect(filter(getSources(node.getReferenceID()), s -> !result.contains(s) && !deleted.contains(s) && filter(getNodes(s).iterator(), affectedNodes::contains).hasNext()), result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static final class DiffChangeAdapter implements Difference.Change<Node<?, ?>, Difference> {
|
||||
|
||||
private final Difference.Change<Node, ?> myDelegate;
|
||||
|
||||
@@ -30,8 +30,8 @@ public final class LoggingDependencyGraph extends LoggingGraph implements Depend
|
||||
}
|
||||
|
||||
@Override
|
||||
public Delta createDelta(Iterable<NodeSource> sourcesToProcess, Iterable<NodeSource> deletedSources) throws IOException {
|
||||
return getDelegate().createDelta(sourcesToProcess, deletedSources);
|
||||
public Delta createDelta(Iterable<NodeSource> sourcesToProcess, Iterable<NodeSource> deletedSources, boolean isSourceOnly) throws IOException {
|
||||
return getDelegate().createDelta(sourcesToProcess, deletedSources, isSourceOnly);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.jps.dependency.impl;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.dependency.*;
|
||||
import org.jetbrains.jps.javac.Iterators;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
final class SourceOnlyDelta implements Delta {
|
||||
private final Set<NodeSource> myBaseSources;
|
||||
private final Set<NodeSource> myDeletedSources;
|
||||
private final Map<String, BackDependencyIndex> myIndices = new HashMap<>();
|
||||
|
||||
SourceOnlyDelta(Iterable<String> indexNames, Iterable<NodeSource> baseSources, Iterable<NodeSource> deletedSources) {
|
||||
myBaseSources = Collections.unmodifiableSet(baseSources instanceof Set? (Set<? extends NodeSource>)baseSources : Iterators.collect(baseSources, new HashSet<>()));
|
||||
myDeletedSources = Collections.unmodifiableSet(deletedSources instanceof Set? (Set<? extends NodeSource>)deletedSources : Iterators.collect(deletedSources, new HashSet<>()));
|
||||
for (String name : indexNames) {
|
||||
myIndices.put(name, BackDependencyIndex.createEmpty(name));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSourceOnly() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<NodeSource> getBaseSources() {
|
||||
return myBaseSources;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<NodeSource> getDeletedSources() {
|
||||
return myDeletedSources;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void associate(@NotNull Node<?, ?> node, @NotNull Iterable<NodeSource> sources) {
|
||||
// nothing here todo: throw exception?
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<BackDependencyIndex> getIndices() {
|
||||
return myIndices.values();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable BackDependencyIndex getIndex(String name) {
|
||||
return myIndices.get(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Iterable<ReferenceID> getDependingNodes(@NotNull ReferenceID id) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<NodeSource> getSources(@NotNull ReferenceID id) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<ReferenceID> getRegisteredNodes() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<NodeSource> getSources() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Node<?, ?>> getNodes(@NotNull NodeSource source) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,21 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.jps.dependency.java;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.util.SmartList;
|
||||
import org.jetbrains.jps.dependency.DifferentiateContext;
|
||||
import org.jetbrains.jps.dependency.DifferentiateStrategy;
|
||||
import org.jetbrains.jps.dependency.Graph;
|
||||
import org.jetbrains.jps.dependency.Node;
|
||||
import org.jetbrains.jps.dependency.*;
|
||||
import org.jetbrains.jps.dependency.diff.Difference;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import static org.jetbrains.jps.javac.Iterators.collect;
|
||||
import static org.jetbrains.jps.javac.Iterators.*;
|
||||
|
||||
public final class GeneralJvmDifferentiateStrategy implements DifferentiateStrategy {
|
||||
|
||||
private static final Logger LOG = Logger.getInstance("#org.jetbrains.jps.dependency.java.GeneralJvmDifferentiateStrategy");
|
||||
|
||||
private static final Iterable<JvmDifferentiateStrategy> ourExtensions = collect(
|
||||
ServiceLoader.load(JvmDifferentiateStrategy.class, GeneralJvmDifferentiateStrategy.class.getClassLoader()),
|
||||
new SmartList<>()
|
||||
@@ -30,10 +32,52 @@ public final class GeneralJvmDifferentiateStrategy implements DifferentiateStrat
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean differentiate(DifferentiateContext context, Iterable<Node<?, ?>> nodesBefore, Iterable<Node<?, ?>> nodesAfter) {
|
||||
public boolean
|
||||
differentiate(DifferentiateContext context, Iterable<Node<?, ?>> nodesBefore, Iterable<Node<?, ?>> nodesAfter) {
|
||||
Utils future = new Utils(context, true);
|
||||
Utils present = new Utils(context, false);
|
||||
|
||||
Delta delta = context.getDelta();
|
||||
if (delta.isSourceOnly()) {
|
||||
new Object() {
|
||||
private final Predicate<? super NodeSource> inCurrentChunk = context.getParams().belongsToCurrentCompilationChunk();
|
||||
private final Set<NodeSource> baseSources = delta.getBaseSources();
|
||||
|
||||
private boolean isMarked(NodeSource src) {
|
||||
return isMarked(Collections.singleton(src));
|
||||
}
|
||||
|
||||
private boolean isMarked(Iterable<NodeSource> sources) {
|
||||
return find(sources, baseSources::contains) != null;
|
||||
}
|
||||
|
||||
boolean traverse(JvmClass cl, boolean isRoot) {
|
||||
boolean parentsMarked = false;
|
||||
for (JvmClass superCl : present.allDirectSupertypes(cl)) {
|
||||
parentsMarked |= traverse(superCl, false);
|
||||
}
|
||||
if (isRoot) {
|
||||
return true;
|
||||
}
|
||||
Iterable<NodeSource> nodeSources = present.getNodeSources(cl.getReferenceID());
|
||||
if (parentsMarked) {
|
||||
for (NodeSource source : filter(nodeSources, s -> !isMarked(s) && inCurrentChunk.test(s))) {
|
||||
LOG.debug("Intermediate class in a class hierarchy is not marked for compilation, while one of its subclasses and superclasses are going to be recompiled. Affecting " + source.toString());
|
||||
context.affectNodeSource(source);
|
||||
}
|
||||
}
|
||||
return parentsMarked || isMarked(nodeSources);
|
||||
}
|
||||
|
||||
void markSources() {
|
||||
Graph graph = context.getGraph();
|
||||
for (JvmClass cls : flat(map(baseSources, s -> graph.getNodes(s, JvmClass.class)))) {
|
||||
traverse(cls, true);
|
||||
}
|
||||
}
|
||||
}.markSources();
|
||||
}
|
||||
|
||||
Difference.Specifier<JvmClass, JvmClass.Diff> classesDiff = Difference.deepDiff(
|
||||
Graph.getNodesOfType(nodesBefore, JvmClass.class), Graph.getNodesOfType(nodesAfter, JvmClass.class)
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.jps.incremental.storage;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
@@ -521,10 +521,10 @@ public final class BuildDataManager {
|
||||
private final ReadWriteLock lock = new ReentrantReadWriteLock();
|
||||
|
||||
@Override
|
||||
public Delta createDelta(Iterable<NodeSource> sourcesToProcess, Iterable<NodeSource> deletedSources) throws IOException {
|
||||
public Delta createDelta(Iterable<NodeSource> sourcesToProcess, Iterable<NodeSource> deletedSources, boolean isSourceOnly) throws IOException {
|
||||
lock.readLock().lock();
|
||||
try {
|
||||
return delegate.createDelta(sourcesToProcess, deletedSources);
|
||||
return delegate.createDelta(sourcesToProcess, deletedSources, isSourceOnly);
|
||||
}
|
||||
finally {
|
||||
lock.readLock().unlock();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.jps.dependency;
|
||||
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
@@ -26,7 +26,7 @@ public class NodeGraphPersistentTest extends BasePlatformTestCase {
|
||||
NodeSource bSrc = createNodeSource("B");
|
||||
|
||||
// This should be executed before compiler run
|
||||
Delta delta = graph.createDelta(Arrays.asList(aSrc, bSrc), null);
|
||||
Delta delta = graph.createDelta(Arrays.asList(aSrc, bSrc), null, false);
|
||||
JvmClass jvmClassNode = JvmClassTestUtil.createJvmClassNode();
|
||||
|
||||
// Analyze after compiler
|
||||
@@ -58,7 +58,7 @@ public class NodeGraphPersistentTest extends BasePlatformTestCase {
|
||||
NodeSource aSrc = createNodeSource("A");
|
||||
NodeSource bSrc = createNodeSource("B");
|
||||
|
||||
Delta initialDelta = graph.createDelta(Arrays.asList(aSrc, bSrc), null);
|
||||
Delta initialDelta = graph.createDelta(Arrays.asList(aSrc, bSrc), null, false);
|
||||
JvmClass clsNodeA = new JvmClass(JVMFlags.EMPTY, "", "com.ppp.aClass", "out/modA/cls", "", "", Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), null, Collections.emptyList(), Collections.emptyList());
|
||||
initialDelta.associate(clsNodeA, List.of(aSrc));
|
||||
JvmClass clsNodeB = new JvmClass(JVMFlags.EMPTY, "", "com.ppp.aClass", "out/modB/cls", "", "", Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), null, Collections.emptyList(), Collections.emptyList());
|
||||
@@ -82,7 +82,7 @@ public class NodeGraphPersistentTest extends BasePlatformTestCase {
|
||||
assertEquals(new HashSet<>(List.of(aSrc, bSrc)), associatedSources);
|
||||
|
||||
// emulate contents of aSrc changed and now a node with different changeID is associated with this source
|
||||
Delta delta = graph.createDelta(Arrays.asList(aSrc), null);
|
||||
Delta delta = graph.createDelta(Arrays.asList(aSrc), null, false);
|
||||
JvmClass clsNodeAChanged = new JvmClass(JVMFlags.EMPTY, "", "com.ppp.aChangedClass", "out/modA/cls", "", "", Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), null, Collections.emptyList(), Collections.emptyList());
|
||||
delta.associate(clsNodeAChanged, List.of(aSrc));
|
||||
DifferentiateResult changes = graph.differentiate(delta, DifferentiateParametersBuilder.create().calculateAffected(false).get());
|
||||
|
||||
@@ -4,8 +4,10 @@ Cleaning output files:
|
||||
out/production/module/META-INF/module.kotlin_module
|
||||
out/production/module/foo/DirectBase.class
|
||||
out/production/module/foo/DirectChild.class
|
||||
out/production/module/foo/DirectInter.class
|
||||
End of files
|
||||
Compiling files:
|
||||
src/DirectInter.kt
|
||||
src/direct.kt
|
||||
End of files
|
||||
Exit code: OK
|
||||
@@ -17,8 +19,10 @@ Cleaning output files:
|
||||
out/production/module/META-INF/module.kotlin_module
|
||||
out/production/module/foo/ReverseBase.class
|
||||
out/production/module/foo/ReverseChild.class
|
||||
out/production/module/foo/ReverseInter.class
|
||||
End of files
|
||||
Compiling files:
|
||||
src/ReverseInter.kt
|
||||
src/reverse.kt
|
||||
End of files
|
||||
Exit code: OK
|
||||
|
||||
Reference in New Issue
Block a user