API to create graph traversal utilities for various typical applications

GitOrigin-RevId: 1c8cf47934b8e456068be1fa3b1ab8132229f8b0
This commit is contained in:
Eugene Zhuravlev
2024-04-26 11:06:33 +02:00
committed by intellij-monorepo-bot
parent 79178982d9
commit 1ba6fd1a16

View File

@@ -16,31 +16,59 @@ import java.util.function.Supplier;
import static org.jetbrains.jps.javac.Iterators.*;
/**
* This class provides commonly used graph traversal methods.
*/
public final class Utils {
private final @NotNull DifferentiateContext myContext;
private final @NotNull Graph myGraph;
private final @Nullable Graph myDelta;
private final @NotNull Predicate<? super NodeSource> mySourcesFilter;
private final @NotNull Predicate<? super ReferenceID> myIsNodeDeleted;
private final @NotNull BackDependencyIndex myDirectSubclasses;
private final @Nullable BackDependencyIndex myDeltaDirectSubclasses;
/**
* Use this constructor for traversal during differentiate operation
* @param context differentiate context
* @param isDelta false, if new nodes in Delta should be taken into account, false otherwise
*/
public Utils(@NotNull DifferentiateContext context, boolean isDelta) {
myContext = context;
myGraph = context.getGraph();
myDelta = isDelta? context.getDelta() : null;
this(context.getGraph(), isDelta? context.getDelta() : null, context.getParams().affectionFilter(), context::isDeleted);
}
/**
* Use this constructor for ordinary graph traversal to explore currently stored dependencies
* @param graph the graph to be explored
* @param sourceFilter NodeSource filter limiting the scope of traversal. Usually this is used to limit the sources set to some scope defined by some external layout, (i.e. a module structure)
*/
public Utils(@NotNull Graph graph, @NotNull Predicate<? super NodeSource> sourceFilter) {
this(graph, null, sourceFilter, id -> false);
}
/**
* The base constructor defining all necessary traversal parameters
* @param graph the graph to be explored
* @param delta the optional delta graph containing new nodes which are not yet integrated into the graph
* @param sourceFilter NodeSource filter limiting the scope of traversal. Usually this is used to limit the sources set to some scope defined by some external layout, (i.e. a module structure)
* @param isNodeDeleted predicate to test if some node currently existing in the graph will be deleted after changes from Delta are applied to the graph
*/
public Utils(@NotNull Graph graph, @Nullable Delta delta, @NotNull Predicate<? super NodeSource> sourceFilter, @NotNull Predicate<? super ReferenceID> isNodeDeleted) {
myGraph = graph;
myDelta = delta;
mySourcesFilter = sourceFilter;
myIsNodeDeleted = isNodeDeleted;
myDirectSubclasses = Objects.requireNonNull(myGraph.getIndex(SubclassesIndex.NAME));
myDeltaDirectSubclasses = myDelta != null? Objects.requireNonNull(myDelta.getIndex(SubclassesIndex.NAME)) : null;
}
public Iterable<NodeSource> getNodeSources(ReferenceID nodeId) {
Predicate<? super NodeSource> srcFilter = myContext.getParams().affectionFilter();
if (myDelta != null) {
Iterable<NodeSource> _src = myDelta.getSources(nodeId);
Iterable<NodeSource> deltaSources = _src instanceof Set? _src : collect(_src, new HashSet<>()) /*ensure Set data structure*/;
return flat(deltaSources, filter(myGraph.getSources(nodeId), src -> !contains(deltaSources, src) && srcFilter.test(src)));
return flat(deltaSources, filter(myGraph.getSources(nodeId), src -> !contains(deltaSources, src) && mySourcesFilter.test(src)));
}
return filter(myGraph.getSources(nodeId), srcFilter::test);
return filter(myGraph.getSources(nodeId), mySourcesFilter::test);
}
public Iterable<JvmClass> getClassesByName(@NotNull String name) {
@@ -111,18 +139,17 @@ public final class Utils {
if (id instanceof JvmNodeReferenceID && "".equals(((JvmNodeReferenceID)id).getNodeName())) {
return Collections.emptyList();
}
Predicate<? super NodeSource> srcFilter = myContext.getParams().affectionFilter();
Iterable<T> allNodes;
if (myDelta != null) {
Iterable<NodeSource> deltaSrc = myDelta.getSources(id);
Iterable<NodeSource> deltaSources = fromDeltaOnly? deltaSrc : deltaSrc instanceof Set? deltaSrc : collect(deltaSrc, new HashSet<>()) /*ensure Set data structure*/;
Iterable<T> deltaNodes = flat(map(deltaSources, src -> myDelta.getNodes(src, selector)));
allNodes = fromDeltaOnly? deltaNodes : flat(
deltaNodes, flat(map(filter(myGraph.getSources(id), src -> !contains(deltaSources, src) && srcFilter.test(src)), src -> myGraph.getNodes(src, selector)))
deltaNodes, flat(map(filter(myGraph.getSources(id), src -> !contains(deltaSources, src) && mySourcesFilter.test(src)), src -> myGraph.getNodes(src, selector)))
);
}
else {
allNodes = fromDeltaOnly? Collections.emptyList() : flat(map(filter(myGraph.getSources(id), srcFilter::test), src -> myGraph.getNodes(src, selector)));
allNodes = fromDeltaOnly? Collections.emptyList() : flat(map(filter(myGraph.getSources(id), mySourcesFilter::test), src -> myGraph.getNodes(src, selector)));
}
return uniqueBy(filter(allNodes, n -> id.equals(n.getReferenceID())), () -> new BooleanFunction<>() {
Set<T> visited;
@@ -166,7 +193,7 @@ public final class Utils {
public Iterable<ReferenceID> directSubclasses(ReferenceID from) {
if (myDeltaDirectSubclasses != null) {
BooleanFunction<ReferenceID> subClassFilter = sub -> {
if (myContext.isDeleted(sub)) {
if (myIsNodeDeleted.test(sub)) {
return false;
}
Iterable<JvmClass> justCompiled = getCompiledNodes(sub, JvmClass.class);