mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-08 15:09:39 +07:00
JPS mappings for incremental compilation refactoring: fixes in persistence; update back-deps indexes correctly; added class short name index; rules for added classes
GitOrigin-RevId: da6760219c22d1043ce1b9ac542a59bfee151780
This commit is contained in:
committed by
intellij-monorepo-bot
parent
0d94a90f56
commit
893bdd3eec
@@ -1,15 +1,16 @@
|
||||
// Copyright 2000-2023 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.Pair;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public interface BackDependencyIndex {
|
||||
@NotNull String getName();
|
||||
|
||||
Iterable<ReferenceID> getKeys();
|
||||
|
||||
Iterable<ReferenceID> getDependencies(@NotNull ReferenceID id);
|
||||
|
||||
void indexNode(@NotNull Node<?, ?> node);
|
||||
|
||||
void integrate(Iterable<Node<?, ?>> deletedNodes, Iterable<Node<?, ?>> updatedNodes, Iterable<Pair<ReferenceID, Iterable<ReferenceID>>> delta);
|
||||
void integrate(Iterable<Node<?, ?>> deletedNodes, Iterable<Node<?, ?>> updatedNodes, BackDependencyIndex deltaIndex);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright 2000-2023 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 com.intellij.openapi.util.Pair;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jps.dependency.*;
|
||||
import org.jetbrains.jps.javac.Iterators;
|
||||
@@ -28,6 +27,11 @@ public abstract class BackDependencyIndexImpl implements BackDependencyIndex {
|
||||
return myName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<ReferenceID> getKeys() {
|
||||
return myMap.getKeys();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Iterable<ReferenceID> getDependencies(@NotNull ReferenceID id) {
|
||||
Iterable<ReferenceID> nodes = myMap.get(id);
|
||||
@@ -43,28 +47,30 @@ public abstract class BackDependencyIndexImpl implements BackDependencyIndex {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void integrate(Iterable<Node<?, ?>> deletedNodes, Iterable<Node<?, ?>> updatedNodes, Iterable<Pair<ReferenceID, Iterable<ReferenceID>>> indexDelta) {
|
||||
public void integrate(Iterable<Node<?, ?>> deletedNodes, Iterable<Node<?, ?>> updatedNodes, BackDependencyIndex deltaIndex) {
|
||||
Map<ReferenceID, Set<ReferenceID>> depsToRemove = new HashMap<>();
|
||||
|
||||
for (var node : deletedNodes) {
|
||||
cleanupDependencies(node, depsToRemove);
|
||||
myMap.remove(node.getReferenceID());
|
||||
}
|
||||
|
||||
for (var node : updatedNodes) {
|
||||
cleanupDependencies(node, depsToRemove);
|
||||
}
|
||||
|
||||
for (Pair<ReferenceID, Iterable<ReferenceID>> p : indexDelta) {
|
||||
ReferenceID nodeID = p.getFirst();
|
||||
Set<ReferenceID> deps = Iterators.collect(getDependencies(nodeID), new HashSet<>());
|
||||
Iterable<ReferenceID> toRemove = depsToRemove.get(nodeID);
|
||||
if (toRemove != null) {
|
||||
for (ReferenceID d : toRemove) {
|
||||
deps.remove(d);
|
||||
for (ReferenceID id : Iterators.unique(Iterators.flat(deltaIndex.getKeys(), depsToRemove.keySet()))) {
|
||||
Set<ReferenceID> toRemove = depsToRemove.get(id);
|
||||
if (!Iterators.isEmpty(toRemove)) {
|
||||
Set<ReferenceID> deps = Iterators.collect(getDependencies(id), new HashSet<>());
|
||||
deps.removeAll(toRemove);
|
||||
myMap.put(id, Iterators.collect(deltaIndex.getDependencies(id), deps));
|
||||
}
|
||||
else {
|
||||
Iterable<ReferenceID> toAdd = deltaIndex.getDependencies(id);
|
||||
if (!Iterators.isEmpty(toAdd)) {
|
||||
myMap.appendValues(id, toAdd);
|
||||
}
|
||||
}
|
||||
myMap.put(nodeID, Iterators.collect(p.getSecond(), deps));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package org.jetbrains.jps.dependency.impl;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jps.dependency.*;
|
||||
import org.jetbrains.jps.dependency.java.ClassShortNameIndex;
|
||||
import org.jetbrains.jps.dependency.java.SubclassesIndex;
|
||||
import org.jetbrains.jps.javac.Iterators;
|
||||
|
||||
@@ -28,6 +29,7 @@ public final class DeltaImpl extends GraphImpl implements Delta {
|
||||
public DeltaImpl(Set<NodeSource> baseSources, Iterable<NodeSource> deletedSources) {
|
||||
super(Containers.MEMORY_CONTAINER_FACTORY);
|
||||
addIndex(new SubclassesIndex(Containers.MEMORY_CONTAINER_FACTORY));
|
||||
addIndex(new ClassShortNameIndex(Containers.MEMORY_CONTAINER_FACTORY));
|
||||
myBaseSources = Collections.unmodifiableSet(baseSources);
|
||||
myDeletedSources = Collections.unmodifiableSet(Iterators.collect(deletedSources, new HashSet<>()));
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
// Copyright 2000-2023 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 com.intellij.openapi.util.Pair;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jps.dependency.*;
|
||||
import org.jetbrains.jps.dependency.diff.DiffCapable;
|
||||
import org.jetbrains.jps.dependency.java.ClassShortNameIndex;
|
||||
import org.jetbrains.jps.dependency.java.JavaDifferentiateStrategy;
|
||||
import org.jetbrains.jps.dependency.java.SubclassesIndex;
|
||||
import org.jetbrains.jps.javac.Iterators;
|
||||
@@ -21,6 +21,7 @@ public final class DependencyGraphImpl extends GraphImpl implements DependencyGr
|
||||
public DependencyGraphImpl(MapletFactory containerFactory) {
|
||||
super(containerFactory);
|
||||
addIndex(new SubclassesIndex(containerFactory));
|
||||
addIndex(new ClassShortNameIndex(containerFactory));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -207,15 +208,14 @@ public final class DependencyGraphImpl extends GraphImpl implements DependencyGr
|
||||
}
|
||||
}
|
||||
|
||||
Set<ReferenceID> deltaNodes = Iterators.collect(Iterators.map(Iterators.flat(Iterators.map(delta.getSources(), s -> delta.getNodes(s))), node -> node.getReferenceID()), new HashSet<>());
|
||||
|
||||
var updatedNodes = Iterators.collect(Iterators.flat(Iterators.map(delta.getSources(), s -> getNodes(s))), new HashSet<>());
|
||||
for (BackDependencyIndex index : getIndices()) {
|
||||
BackDependencyIndex deltaIndex = delta.getIndex(index.getName());
|
||||
assert deltaIndex != null;
|
||||
index.integrate(diffResult.getDeletedNodes(), updatedNodes, Iterators.map(deltaNodes, id -> Pair.create(id, deltaIndex.getDependencies(id))));
|
||||
index.integrate(diffResult.getDeletedNodes(), updatedNodes, deltaIndex);
|
||||
}
|
||||
|
||||
var deltaNodes = Iterators.map(Iterators.flat(Iterators.map(delta.getSources(), s -> delta.getNodes(s))), node -> node.getReferenceID());
|
||||
for (ReferenceID nodeID : deltaNodes) {
|
||||
Set<NodeSource> sources = Iterators.collect(myNodeToSourcesMap.get(nodeID), new HashSet<>());
|
||||
sources.removeAll(delta.getBaseSources());
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.nio.file.Path;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public final class PersistentSetMultiMaplet<K extends SerializableGraphElement, V extends SerializableGraphElement>
|
||||
@@ -30,8 +31,8 @@ public final class PersistentSetMultiMaplet<K extends SerializableGraphElement,
|
||||
private static final Collection<?> NULL_COLLECTION = Collections.emptyList();
|
||||
private static final int CACHE_SIZE = 128;
|
||||
|
||||
private final PersistentHashMap<K, Collection<V>> map;
|
||||
private final LoadingCache<K, Collection<V>> cache;
|
||||
private final PersistentHashMap<K, Collection<V>> myMap;
|
||||
private final LoadingCache<K, Collection<V>> myCache;
|
||||
|
||||
public PersistentSetMultiMaplet(Path mapFile) {
|
||||
try {
|
||||
@@ -39,15 +40,15 @@ public final class PersistentSetMultiMaplet<K extends SerializableGraphElement,
|
||||
KeyDescriptor<K> keyDescriptor = NodeKeyDescriptorImpl.getInstance();
|
||||
DataExternalizer<Collection<V>> valueExternalizer =
|
||||
new CollectionDataExternalizer<>(NodeKeyDescriptorImpl.getInstance(), fileCollectionFactory);
|
||||
map = new PersistentHashMap<>(mapFile, keyDescriptor, valueExternalizer);
|
||||
myMap = new PersistentHashMap<>(mapFile, keyDescriptor, valueExternalizer);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
cache = Caffeine.newBuilder().maximumSize(CACHE_SIZE).build(key -> {
|
||||
myCache = Caffeine.newBuilder().maximumSize(CACHE_SIZE).build(key -> {
|
||||
try {
|
||||
Collection<V> collection = map.get(key);
|
||||
Collection<V> collection = myMap.get(key);
|
||||
//noinspection unchecked
|
||||
return collection == null ? (Collection<V>)NULL_COLLECTION : collection;
|
||||
}
|
||||
@@ -60,7 +61,7 @@ public final class PersistentSetMultiMaplet<K extends SerializableGraphElement,
|
||||
@Override
|
||||
public boolean containsKey(K key) {
|
||||
try {
|
||||
return map.containsMapping(key);
|
||||
return myMap.containsMapping(key);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new BuildDataCorruptedException(e);
|
||||
@@ -69,15 +70,21 @@ public final class PersistentSetMultiMaplet<K extends SerializableGraphElement,
|
||||
|
||||
@Override
|
||||
public @Nullable Iterable<V> get(K key) {
|
||||
final Collection<V> collection = cache.get(key);
|
||||
final Collection<V> collection = myCache.get(key);
|
||||
return collection == NULL_COLLECTION ? null : collection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(K key, Iterable<? extends V> values) {
|
||||
try {
|
||||
cache.invalidate(key);
|
||||
map.put(key, Iterators.collect(values, new HashSet<>()));
|
||||
myCache.invalidate(key);
|
||||
Set<V> data = Iterators.collect(values, new HashSet<>());
|
||||
if (data.isEmpty()) {
|
||||
myMap.remove(key);
|
||||
}
|
||||
else {
|
||||
myMap.put(key, data);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new BuildDataCorruptedException(e);
|
||||
@@ -87,8 +94,8 @@ public final class PersistentSetMultiMaplet<K extends SerializableGraphElement,
|
||||
@Override
|
||||
public void remove(K key) {
|
||||
try {
|
||||
cache.invalidate(key);
|
||||
map.remove(key);
|
||||
myCache.invalidate(key);
|
||||
myMap.remove(key);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new BuildDataCorruptedException(e);
|
||||
@@ -97,11 +104,19 @@ public final class PersistentSetMultiMaplet<K extends SerializableGraphElement,
|
||||
|
||||
@Override
|
||||
public void appendValue(K key, V value) {
|
||||
appendValues(key, Collections.singleton(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendValues(K key, Iterable<? extends V> values) {
|
||||
try {
|
||||
map.appendData(key, new AppendablePersistentMap.ValueDataAppender() {
|
||||
myMap.appendData(key, new AppendablePersistentMap.ValueDataAppender() {
|
||||
@Override
|
||||
public void append(final @NotNull DataOutput out) throws IOException {
|
||||
NodeKeyDescriptorImpl.getInstance().save(out, value);
|
||||
var descriptor = NodeKeyDescriptorImpl.getInstance();
|
||||
for (V value : values) {
|
||||
descriptor.save(out, value);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -112,16 +127,25 @@ public final class PersistentSetMultiMaplet<K extends SerializableGraphElement,
|
||||
|
||||
@Override
|
||||
public void removeValue(K key, V value) {
|
||||
removeValues(key, Collections.singleton(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeValues(K key, Iterable<? extends V> values) {
|
||||
try {
|
||||
final Collection<V> collection = cache.get(key);
|
||||
if (collection != NULL_COLLECTION) {
|
||||
if (collection.remove(value)) {
|
||||
cache.invalidate(key);
|
||||
final Collection<V> collection = myCache.get(key);
|
||||
if (!collection.isEmpty()) {
|
||||
boolean changes = false;
|
||||
for (V value : values) {
|
||||
changes |= collection.remove(value);
|
||||
}
|
||||
if (changes) {
|
||||
myCache.invalidate(key);
|
||||
if (collection.isEmpty()) {
|
||||
map.remove(key);
|
||||
myMap.remove(key);
|
||||
}
|
||||
else {
|
||||
map.put(key, collection);
|
||||
myMap.put(key, collection);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -134,7 +158,7 @@ public final class PersistentSetMultiMaplet<K extends SerializableGraphElement,
|
||||
@Override
|
||||
public Iterable<K> getKeys() {
|
||||
try {
|
||||
return map.getAllKeysWithExistingMapping();
|
||||
return myMap.getAllKeysWithExistingMapping();
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
@@ -143,8 +167,8 @@ public final class PersistentSetMultiMaplet<K extends SerializableGraphElement,
|
||||
|
||||
public void close() {
|
||||
try {
|
||||
cache.invalidateAll();
|
||||
map.close();
|
||||
myCache.invalidateAll();
|
||||
myMap.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new BuildDataCorruptedException(e);
|
||||
|
||||
@@ -498,15 +498,17 @@ public final class SerializerUtil {
|
||||
}
|
||||
|
||||
static FieldAssignUsage readFieldAssignUsage(DataInput in) throws IOException {
|
||||
FieldUsage fieldUsage = readFieldUsage(in);
|
||||
return (FieldAssignUsage)fieldUsage;
|
||||
String owner = in.readUTF();
|
||||
String name = in.readUTF();
|
||||
String descriptor = in.readUTF();
|
||||
return new FieldAssignUsage(owner, name, descriptor);
|
||||
}
|
||||
|
||||
static FieldUsage readFieldUsage(DataInput in) throws IOException {
|
||||
String refId = in.readUTF();
|
||||
String owner = in.readUTF();
|
||||
String name = in.readUTF();
|
||||
String descriptor = in.readUTF();
|
||||
return new FieldUsage(refId, name, descriptor);
|
||||
return new FieldUsage(owner, name, descriptor);
|
||||
}
|
||||
|
||||
static JvmClass readJvmClass(DataInput in) throws IOException {
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
// Copyright 2000-2023 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 org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jps.dependency.MapletFactory;
|
||||
import org.jetbrains.jps.dependency.Node;
|
||||
import org.jetbrains.jps.dependency.ReferenceID;
|
||||
import org.jetbrains.jps.dependency.impl.BackDependencyIndexImpl;
|
||||
import org.jetbrains.jps.javac.Iterators;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
public final class ClassShortNameIndex extends BackDependencyIndexImpl {
|
||||
public static final String NAME = "class-short-names";
|
||||
|
||||
public ClassShortNameIndex(@NotNull MapletFactory cFactory) {
|
||||
super(NAME, cFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<ReferenceID> getIndexedDependencies(@NotNull Node<?, ?> node) {
|
||||
if (node instanceof JvmClass) {
|
||||
JvmClass cls = (JvmClass)node;
|
||||
if (!cls.isAnonymous() && !cls.isLocal()) {
|
||||
return Iterators.asIterable(new JvmNodeReferenceID(cls.getShortName()));
|
||||
}
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
@@ -37,23 +37,36 @@ public final class JavaDifferentiateStrategy implements DifferentiateStrategy {
|
||||
Graph.getNodesOfType(nodesBefore, JvmClass.class), Graph.getNodesOfType(nodesAfter, JvmClass.class)
|
||||
);
|
||||
|
||||
debug("Processing removed classes:");
|
||||
for (JvmClass removed : classesDiff.removed()) {
|
||||
if (!processRemovedClass(context, removed, future, present)) {
|
||||
return false;
|
||||
debug("Adding usages of class " + removed.getName());
|
||||
context.affectUsage(new ClassUsage(removed.getName()));
|
||||
}
|
||||
debug("End of removed classes processing.");
|
||||
|
||||
debug("Processing added classes:");
|
||||
try {
|
||||
for (JvmClass added : classesDiff.added()) {
|
||||
if (!processAddedClass(context, added, future, present)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (JvmClass added : classesDiff.added()) {
|
||||
if (!processAddedClass(context, added, future, present)) {
|
||||
return false;
|
||||
}
|
||||
finally {
|
||||
debug("End of added classes processing.");
|
||||
}
|
||||
|
||||
for (Difference.Change<JvmClass, JvmClass.Diff> change : classesDiff.changed()) {
|
||||
if (!processChangedClass(context, change, future, present)) {
|
||||
return false;
|
||||
debug("Processing changed classes:");
|
||||
try {
|
||||
for (Difference.Change<JvmClass, JvmClass.Diff> change : classesDiff.changed()) {
|
||||
if (!processChangedClass(context, change, future, present)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
debug("End of changed classes processing");
|
||||
}
|
||||
|
||||
Difference.Specifier<JvmModule, JvmModule.Diff> modulesDiff = Difference.deepDiff(
|
||||
Graph.getNodesOfType(nodesBefore, JvmModule.class), Graph.getNodesOfType(nodesAfter, JvmModule.class)
|
||||
@@ -80,13 +93,21 @@ public final class JavaDifferentiateStrategy implements DifferentiateStrategy {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean processRemovedClass(DifferentiateContext context, JvmClass removedClass, Utils future, Utils present) {
|
||||
// todo
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean processAddedClass(DifferentiateContext context, JvmClass addedClass, Utils future, Utils present) {
|
||||
// todo
|
||||
// todo: consider if we need to perform a duplucate-class check, when the newly added class is of the same name with the existing one in the same module chunk
|
||||
if (!addedClass.isAnonymous() && !addedClass.isLocal()) {
|
||||
BackDependencyIndex index = context.getGraph().getIndex(ClassShortNameIndex.NAME);
|
||||
if (index != null) {
|
||||
// affecting dependencies on all other classes with the same short name
|
||||
Set<ReferenceID> affectedNodes = Iterators.collect(index.getDependencies(new JvmNodeReferenceID(addedClass.getShortName())), new HashSet<>());
|
||||
affectedNodes.add(addedClass.getReferenceID());
|
||||
for (ReferenceID id : affectedNodes) {
|
||||
debug("Adding usages of class with the same short name: " + id);
|
||||
context.affectUsage(new AffectionScopeMetaUsage(id));
|
||||
}
|
||||
context.affectUsage((n, u) -> affectedNodes.contains(u.getElementOwner()));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -116,7 +137,7 @@ public final class JavaDifferentiateStrategy implements DifferentiateStrategy {
|
||||
parents.removeAll(Iterators.collect(future.allSupertypes(changedClass.getReferenceID()), new HashSet<>()));
|
||||
for (JvmNodeReferenceID parent : parents) {
|
||||
debug("Affecting usages in generic type parameter bounds of class: " + parent);
|
||||
context.affectUsage(new ClassAsGenericBoundUsage(parent.getNodeName())); // todo: need support of usage constraint?
|
||||
context.affectUsage(new ClassAsGenericBoundUsage(parent.getNodeName())); // todo: need support of file-filter usage constraint?
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -222,7 +243,7 @@ public final class JavaDifferentiateStrategy implements DifferentiateStrategy {
|
||||
return true;
|
||||
}
|
||||
|
||||
private <T> boolean processMethodChanges(DifferentiateContext context, Difference.Change<JvmClass, JvmClass.Diff> classChange, Utils future, Utils present) {
|
||||
private boolean processMethodChanges(DifferentiateContext context, Difference.Change<JvmClass, JvmClass.Diff> classChange, Utils future, Utils present) {
|
||||
JvmClass changedClass = classChange.getPast();
|
||||
if (changedClass.isAnnotation()) {
|
||||
debug("Class is annotation, skipping method analysis");
|
||||
|
||||
@@ -45,6 +45,12 @@ public final class JvmClass extends JVMClassNode<JvmClass, JvmClass.Diff> {
|
||||
return getPackageName(getName());
|
||||
}
|
||||
|
||||
public @NotNull String getShortName() {
|
||||
String jvmClassName = getName();
|
||||
int index = jvmClassName.lastIndexOf('/');
|
||||
return index >= 0? jvmClassName.substring(index + 1) : jvmClassName;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String getPackageName(@NotNull String jvmClassName) {
|
||||
int index = jvmClassName.lastIndexOf('/');
|
||||
|
||||
Reference in New Issue
Block a user