mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
support classes with the same FQ name in different modules
GitOrigin-RevId: e6c7f706d151f32f8236ba2bfaab8df4dde73651
This commit is contained in:
committed by
intellij-monorepo-bot
parent
99fab1e84b
commit
b9fa027b9b
+22
@@ -0,0 +1,22 @@
|
||||
Cleaning output files:
|
||||
out/production/module1/ppp/SomeException.class
|
||||
End of files
|
||||
Compiling files:
|
||||
module1/src/ppp/SomeException.java
|
||||
End of files
|
||||
Cleaning output files:
|
||||
out/production/module1/ppp/Client.class
|
||||
out/production/module1/ppp/Task.class
|
||||
End of files
|
||||
Compiling files:
|
||||
module1/src/ppp/Client.java
|
||||
module1/src/ppp/Task.java
|
||||
End of files
|
||||
Cleaning output files:
|
||||
out/production/module2/ppp/Client2.class
|
||||
out/production/module2/ppp/Task.class
|
||||
End of files
|
||||
Compiling files:
|
||||
module2/src/ppp/Client2.java
|
||||
module2/src/ppp/Task.java
|
||||
End of files
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package ppp;
|
||||
|
||||
public class Client {
|
||||
public void foo(Task task) {
|
||||
try {
|
||||
task.execute();
|
||||
}
|
||||
catch (Throwable/*RuntimeException*/ e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
package ppp;
|
||||
|
||||
public class SomeException extends RuntimeException{
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
package ppp;
|
||||
|
||||
public class SomeException extends Exception{
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
package ppp;
|
||||
|
||||
public class Task {
|
||||
public void execute() throws SomeException{
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package ppp;
|
||||
|
||||
public class Client2 {
|
||||
public void foo(Task task) {
|
||||
try {
|
||||
task.execute2();
|
||||
}
|
||||
catch (Throwable/*RuntimeException*/ e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
package ppp;
|
||||
|
||||
public class Task {
|
||||
public void execute2() throws SomeException{
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
Cleaning output files:
|
||||
out/production/moduleA/com/ppp/A.class
|
||||
End of files
|
||||
Compiling files:
|
||||
moduleA/src/com/ppp/A.java
|
||||
End of files
|
||||
Cleaning output files:
|
||||
out/production/moduleA/com/ppp/BA.class
|
||||
out/production/moduleA/com/ppp/C.class
|
||||
End of files
|
||||
Compiling files:
|
||||
moduleA/src/com/ppp/BA.java
|
||||
moduleA/src/com/ppp/C.java
|
||||
End of files
|
||||
Cleaning output files:
|
||||
out/production/moduleB/com/ppp/BB.class
|
||||
out/production/moduleB/com/ppp/C.class
|
||||
End of files
|
||||
Compiling files:
|
||||
moduleB/src/com/ppp/BB.java
|
||||
moduleB/src/com/ppp/C.java
|
||||
End of files
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
package com.ppp;
|
||||
|
||||
public class A {
|
||||
public static int field2;
|
||||
|
||||
public static void foo(Object obj) {}
|
||||
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package com.ppp;
|
||||
|
||||
public class A {
|
||||
public static int field;
|
||||
|
||||
public static void foo(Object obj) {}
|
||||
|
||||
public static void foo(Integer num) {}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
package com.ppp;
|
||||
|
||||
public class BA {
|
||||
void method() {
|
||||
A.foo(new Integer(42));
|
||||
}
|
||||
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package com.ppp;
|
||||
|
||||
public class C {
|
||||
void method() {
|
||||
A.foo(new Integer(42));
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package com.ppp;
|
||||
|
||||
public class A {
|
||||
public static int field2;
|
||||
|
||||
public static void foo(Object obj) {}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
package com.ppp;
|
||||
|
||||
public class BB {
|
||||
void method() {
|
||||
int val = A.field2;
|
||||
}
|
||||
}
|
||||
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package com.ppp;
|
||||
|
||||
public class C {
|
||||
void method() {
|
||||
A.foo(new Integer(42));
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// 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.javac;
|
||||
|
||||
import com.intellij.util.BooleanFunction;
|
||||
@@ -104,6 +104,7 @@ public final class Iterators {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
if (parts.size() == 1) {
|
||||
//noinspection unchecked
|
||||
return (Iterable<T>)parts.iterator().next();
|
||||
}
|
||||
return flat((Iterable<? extends Iterable<? extends T>>)parts);
|
||||
@@ -155,18 +156,8 @@ public final class Iterators {
|
||||
}
|
||||
|
||||
public static <I> Iterator<I> asIterator(final Iterable<? extends I> from) {
|
||||
final Iterator<? extends I> it = from.iterator();
|
||||
return new BaseIterator<I>() {
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return it.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public I next() {
|
||||
return it.next();
|
||||
}
|
||||
};
|
||||
//noinspection unchecked
|
||||
return from == null? Collections.<I>emptyIterator() : (Iterator<I>)from.iterator();
|
||||
}
|
||||
|
||||
public static <T> Iterable<T> asIterable(final T elem) {
|
||||
@@ -315,6 +306,29 @@ public final class Iterators {
|
||||
}));
|
||||
}
|
||||
|
||||
public static <T> Iterable<T> unique(final Iterable<? extends T> it) {
|
||||
return isEmptyCollection(it)? Collections.<T>emptyList() : new Iterable<T>() {
|
||||
@NotNull
|
||||
@Override
|
||||
public Iterator<T> iterator() {
|
||||
return unique(it.iterator());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static <T> Iterator<T> unique(final Iterator<? extends T> it) {
|
||||
return filter(it, new BooleanFunction<T>() {
|
||||
private Set<T> processed;
|
||||
@Override
|
||||
public boolean fun(T t) {
|
||||
if (processed == null) {
|
||||
processed = new HashSet<>();
|
||||
}
|
||||
return processed.add(t);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> BooleanFunction<? super T> notNullFilter() {
|
||||
return (BooleanFunction<T>)NOT_NULL_FILTER;
|
||||
|
||||
+12
-10
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// 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.builders.java.dependencyView;
|
||||
|
||||
import com.intellij.util.containers.SLRUCache;
|
||||
@@ -103,16 +103,18 @@ public final class IntObjectPersistentMultiMaplet<V> extends IntObjectMultiMaple
|
||||
@Override
|
||||
public void removeAll(int key, Collection<V> values) {
|
||||
try {
|
||||
final Collection<V> collection = myCache.get(key);
|
||||
if (!values.isEmpty()) {
|
||||
final Collection<V> collection = myCache.get(key);
|
||||
|
||||
if (collection != NULL_COLLECTION) {
|
||||
if (collection.removeAll(values)) {
|
||||
myCache.remove(key);
|
||||
if (collection.isEmpty()) {
|
||||
myMap.remove(key);
|
||||
}
|
||||
else {
|
||||
myMap.put(key, collection);
|
||||
if (collection != NULL_COLLECTION) {
|
||||
if (collection.removeAll(values)) {
|
||||
myCache.remove(key);
|
||||
if (collection.isEmpty()) {
|
||||
myMap.remove(key);
|
||||
}
|
||||
else {
|
||||
myMap.put(key, collection);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+294
-222
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// 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.builders.java.dependencyView;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
@@ -10,6 +10,7 @@ import com.intellij.util.containers.CollectionFactory;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.FileCollectionFactory;
|
||||
import com.intellij.util.io.EnumeratorIntegerDescriptor;
|
||||
import it.unimi.dsi.fastutil.ints.IntConsumer;
|
||||
import it.unimi.dsi.fastutil.ints.IntIterator;
|
||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||
@@ -30,6 +31,7 @@ import java.io.PrintStream;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
@@ -135,7 +137,7 @@ public class Mappings {
|
||||
myRemovedSuperClasses = myIsDelta ? new IntIntTransientMultiMaplet() : null;
|
||||
myAddedSuperClasses = myIsDelta ? new IntIntTransientMultiMaplet() : null;
|
||||
|
||||
final Supplier<Collection<String>> fileCollectionFactory = CollectionFactory::createFilePathSet; // todo: do we really need set and not a list here?
|
||||
final Supplier<Collection<String>> fileCollectionFactory = CollectionFactory::createFilePathSet;
|
||||
if (myIsDelta) {
|
||||
myClassToSubclasses = new IntIntTransientMultiMaplet();
|
||||
myClassToClassDependency = new IntIntTransientMultiMaplet();
|
||||
@@ -224,30 +226,31 @@ public class Mappings {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private ClassRepr getClassReprByName(final @Nullable File source, final int qName) {
|
||||
final ClassFileRepr reprByName = getReprByName(source, qName);
|
||||
return reprByName instanceof ClassRepr? (ClassRepr)reprByName : null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private ClassFileRepr getReprByName(@Nullable File source, int qName) {
|
||||
final Iterable<String> sources = source != null? Collections.singleton(toRelative(source)) : myClassToRelativeSourceFilePath.get(qName);
|
||||
if (sources != null) {
|
||||
for (String src : sources) {
|
||||
final Collection<ClassFileRepr> reprs = myRelativeSourceFilePathToClasses.get(src);
|
||||
if (reprs != null) {
|
||||
for (ClassFileRepr repr : reprs) {
|
||||
if (repr.name == qName) {
|
||||
return repr;
|
||||
}
|
||||
}
|
||||
private ClassFileRepr getReprByName(@NotNull File source, int qName) {
|
||||
final Collection<ClassFileRepr> reprs = myRelativeSourceFilePathToClasses.get(toRelative(source));
|
||||
if (reprs != null) {
|
||||
for (ClassFileRepr repr : reprs) {
|
||||
if (repr.name == qName) {
|
||||
return repr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Iterable<ClassRepr> getClassReprsByName(final int qName) {
|
||||
return Iterators.filter(Iterators.map(getReprsByName(qName), repr -> repr instanceof ClassRepr? (ClassRepr)repr : null), Iterators.notNullFilter());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Iterable<ClassFileRepr> getReprsByName(int qName) {
|
||||
return Iterators.unique(Iterators.filter(
|
||||
Iterators.flat(Iterators.map(myClassToRelativeSourceFilePath.get(qName), src -> myRelativeSourceFilePathToClasses.get(src))),
|
||||
repr -> repr.name == qName
|
||||
));
|
||||
}
|
||||
|
||||
private Collection<ClassFileRepr> sourceFileToClassesGet(File unchangedSource) {
|
||||
return myRelativeSourceFilePathToClasses.get(toRelative(unchangedSource));
|
||||
}
|
||||
@@ -336,17 +339,22 @@ public class Mappings {
|
||||
if (acc.contains(reflcass)) {
|
||||
return acc; // SOE prevention
|
||||
}
|
||||
final ClassRepr repr = classReprByName(reflcass);
|
||||
if (repr != null) {
|
||||
final Iterable<ClassRepr> reprs = classReprsByName(reflcass);
|
||||
if (!Iterators.isEmpty(reprs)) {
|
||||
if (!root) {
|
||||
final Set<? extends ProtoMember> members = isField ? repr.getFields() : repr.getMethods();
|
||||
|
||||
for (ProtoMember m : members) {
|
||||
if (isSame.test(m)) {
|
||||
return acc;
|
||||
Iterable<ClassRepr> reprsWithoutMatchingMember = Iterators.filter(reprs, repr -> {
|
||||
for (ProtoMember m : isField? repr.getFields() : repr.getMethods()) {
|
||||
if (isSame.test(m)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
if (Iterators.isEmpty(reprsWithoutMatchingMember)) {
|
||||
return acc;
|
||||
}
|
||||
|
||||
// should continue, if at least one repr does not have matching member defined
|
||||
acc.add(reflcass);
|
||||
}
|
||||
|
||||
@@ -407,18 +415,30 @@ public class Mappings {
|
||||
}
|
||||
final IntSet _visitedClasses = visitedClasses;
|
||||
subClasses.forEach(subClassName -> {
|
||||
final ClassRepr r = classReprByName(subClassName);
|
||||
|
||||
if (r != null) {
|
||||
boolean cont = true;
|
||||
final Collection<MethodRepr> methods = r.findMethods(predicate);
|
||||
for (MethodRepr mm : methods) {
|
||||
if (isVisibleIn(fromClass, m, r)) {
|
||||
container.add(Pair.create(mm, r));
|
||||
cont = false;
|
||||
Iterable<ClassRepr> reprs = classReprsByName(subClassName);
|
||||
if (!Iterators.isEmpty(reprs)) {
|
||||
Iterable<Pair<MethodRepr, ClassRepr>> overriding = Iterators.filter(Iterators.map(reprs, r -> {
|
||||
for (MethodRepr mm : r.findMethods(predicate)) {
|
||||
if (isVisibleIn(fromClass, m, r)) {
|
||||
return Pair.create(mm, r);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}), Iterators.notNullFilter());
|
||||
|
||||
for (Pair<MethodRepr, ClassRepr> pair : overriding) {
|
||||
container.add(pair);
|
||||
}
|
||||
if (cont) {
|
||||
|
||||
for (ClassRepr r : Iterators.filter(reprs, r -> {
|
||||
for (Pair<MethodRepr, ClassRepr> pair : overriding) {
|
||||
if (pair.getSecond() == r) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
})) {
|
||||
// continue with reprs, for those no overriding members were found
|
||||
addOverridingMethods(m, r, predicate, container, _visitedClasses);
|
||||
}
|
||||
}
|
||||
@@ -451,8 +471,7 @@ public class Mappings {
|
||||
if (!visitedClasses.add(superName.className) || superName.className == myObjectClassName) {
|
||||
continue;
|
||||
}
|
||||
final ClassRepr superClass = classReprByName(superName.className);
|
||||
if (superClass != null) {
|
||||
for (ClassRepr superClass : classReprsByName(superName.className)) {
|
||||
for (MethodRepr mm : superClass.findMethods(predicate)) {
|
||||
if (isVisibleIn(superClass, mm, fromClass)) {
|
||||
return true;
|
||||
@@ -475,10 +494,15 @@ public class Mappings {
|
||||
if (!visitedClasses.add(superName.className) || superName.className == myObjectClassName) {
|
||||
continue;
|
||||
}
|
||||
final ClassRepr superClass = classReprByName(superName.className);
|
||||
if (superClass == null || extendsLibraryClass(superClass, visitedClasses)) {
|
||||
Iterable<ClassRepr> superClasses = classReprsByName(superName.className);
|
||||
if (Iterators.isEmpty(superClasses)) {
|
||||
return true;
|
||||
}
|
||||
for (ClassRepr superClass : superClasses) {
|
||||
if (extendsLibraryClass(superClass, visitedClasses)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -492,17 +516,30 @@ public class Mappings {
|
||||
if (!visitedClasses.add(superName.className) || superName.className == myObjectClassName) {
|
||||
continue; // prevent SOE
|
||||
}
|
||||
final ClassRepr superClass = classReprByName(superName.className);
|
||||
if (superClass != null) {
|
||||
boolean cont = true;
|
||||
final Collection<MethodRepr> methods = superClass.findMethods(predicate);
|
||||
for (MethodRepr mm : methods) {
|
||||
if (isVisibleIn(superClass, mm, fromClass)) {
|
||||
container.add(Pair.create(mm, superClass));
|
||||
cont = false;
|
||||
Iterable<ClassRepr> superClasses = classReprsByName(superName.className);
|
||||
if (!Iterators.isEmpty(superClasses)) {
|
||||
Iterable<Pair<MethodRepr, ClassRepr>> pairs = Iterators.filter(Iterators.map(superClasses, superClass -> {
|
||||
for (MethodRepr mm : superClass.findMethods(predicate)) {
|
||||
if (isVisibleIn(superClass, mm, fromClass)) {
|
||||
return Pair.create(mm, superClass);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}), Iterators.notNullFilter());
|
||||
|
||||
for (Pair<MethodRepr, ClassRepr> pair : pairs) {
|
||||
container.add(pair);
|
||||
}
|
||||
if (cont) {
|
||||
|
||||
for (ClassRepr superClass : Iterators.filter(superClasses, superClass -> {
|
||||
for (Pair<MethodRepr, ClassRepr> pair : pairs) {
|
||||
if (pair.getSecond() == superClass) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
})) {
|
||||
// continue with those, for whom the matching method was not found
|
||||
addOverridenMethods(superClass, predicate, container, visitedClasses);
|
||||
}
|
||||
}
|
||||
@@ -521,8 +558,7 @@ public class Mappings {
|
||||
if (!visitedClasses.add(supername.className) || supername.className == myObjectClassName) {
|
||||
continue;
|
||||
}
|
||||
final ClassRepr superClass = classReprByName(supername.className);
|
||||
if (superClass != null) {
|
||||
for (ClassRepr superClass : classReprsByName(supername.className)) {
|
||||
final FieldRepr ff = superClass.findField(f.name);
|
||||
if (ff != null && isVisibleIn(superClass, ff, fromClass)) {
|
||||
container.add(Pair.create(ff, superClass));
|
||||
@@ -543,14 +579,12 @@ public class Mappings {
|
||||
if (!visitedClasses.add(supername.className) || supername.className == myObjectClassName) {
|
||||
continue;
|
||||
}
|
||||
final ClassRepr superClass = classReprByName(supername.className);
|
||||
if (superClass != null) {
|
||||
for (ClassRepr superClass : classReprsByName(supername.className)) {
|
||||
final FieldRepr ff = superClass.findField(f.name);
|
||||
if (ff != null && isVisibleIn(superClass, ff, fromClass)) {
|
||||
return true;
|
||||
}
|
||||
final boolean found = hasOverriddenFields(f, superClass, visitedClasses);
|
||||
if (found) {
|
||||
if (hasOverriddenFields(f, superClass, visitedClasses)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -560,17 +594,20 @@ public class Mappings {
|
||||
|
||||
// test if a ClassRepr is a SAM interface
|
||||
boolean isLambdaTarget(int name) {
|
||||
final ClassRepr cls = classReprByName(name);
|
||||
if (cls == null || !cls.isInterface()) {
|
||||
return false;
|
||||
}
|
||||
int amFound = 0;
|
||||
for (MethodRepr method : allMethodsRecursively(cls)) {
|
||||
if (method.isAbstract() && ++amFound > 1) {
|
||||
return false;
|
||||
for (ClassRepr cls : classReprsByName(name)) {
|
||||
if (cls.isInterface()) {
|
||||
int amFound = 0;
|
||||
for (MethodRepr method : allMethodsRecursively(cls)) {
|
||||
if (method.isAbstract() && ++amFound > 1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (amFound == 1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return amFound == 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
private Iterable<MethodRepr> allMethodsRecursively(ClassRepr cls) {
|
||||
@@ -578,47 +615,45 @@ public class Mappings {
|
||||
}
|
||||
|
||||
private Iterable<OverloadDescriptor> findAllOverloads(final ClassRepr cls, Function<? super MethodRepr, Integer> correspondenceFinder) {
|
||||
Function<ClassRepr, Iterable<OverloadDescriptor>> converter = c -> c == null? Collections.emptyList() : Iterators.filter(Iterators.map(c.getMethods(), m -> {
|
||||
Function<ClassRepr, Iterable<OverloadDescriptor>> converter = c -> Iterators.filter(Iterators.map(c.getMethods(), m -> {
|
||||
Integer accessScope = correspondenceFinder.apply(m);
|
||||
return accessScope != null? new OverloadDescriptor(accessScope, m, c) : null;
|
||||
}), Objects::nonNull);
|
||||
}), Iterators.notNullFilter());
|
||||
|
||||
return Iterators.flat(Iterators.flat(
|
||||
collectRecursively(cls, converter),
|
||||
Iterators.map(getAllSubclasses(cls.name), subName -> converter.apply(subName != cls.name? classReprByName(subName) : null))
|
||||
Iterators.map(
|
||||
Iterators.flat(Iterators.map(getAllSubclasses(cls.name), subName -> subName != cls.name? classReprsByName(subName) : Collections.emptyList())),
|
||||
repr -> converter.apply(repr)
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
private <T> Iterable<T> collectRecursively(ClassRepr cls, Function<? super ClassRepr, ? extends T> mapper) {
|
||||
return Iterators.flat(Iterators.asIterable(mapper.apply(cls)), Iterators.flat(Iterators.map(cls.getSuperTypes(), st -> {
|
||||
final ClassRepr cr = classReprByName(st.className);
|
||||
return cr != null ? collectRecursively(cr, mapper) : Collections.emptyList();
|
||||
return Iterators.flat(Iterators.map(classReprsByName(st.className), cr -> collectRecursively(cr, mapper)));
|
||||
})));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
ClassRepr classReprByName(final int name) {
|
||||
final ClassFileRepr r = reprByName(name);
|
||||
return r instanceof ClassRepr? (ClassRepr)r : null;
|
||||
@NotNull
|
||||
Iterable<ClassRepr> classReprsByName(final int name) {
|
||||
return Iterators.filter(Iterators.map(reprsByName(name), r -> r instanceof ClassRepr? (ClassRepr)r : null), Iterators.notNullFilter());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
ModuleRepr moduleReprByName(final int name) {
|
||||
final ClassFileRepr r = reprByName(name);
|
||||
return r instanceof ModuleRepr? (ModuleRepr)r : null;
|
||||
@NotNull
|
||||
Iterable<ModuleRepr> moduleReprsByName(final int name) {
|
||||
return Iterators.filter(Iterators.map(reprsByName(name), r -> r instanceof ModuleRepr? (ModuleRepr)r : null), Iterators.notNullFilter());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
ClassFileRepr reprByName(final int name) {
|
||||
@NotNull
|
||||
Iterable<ClassFileRepr> reprsByName(final int name) {
|
||||
if (myMappings != null) {
|
||||
final ClassFileRepr r = myMappings.getReprByName(null, name);
|
||||
|
||||
if (r != null) {
|
||||
Iterable<ClassFileRepr> r = myMappings.getReprsByName(name);
|
||||
if (!Iterators.isEmpty(r)) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
return getReprByName(null, name);
|
||||
return getReprsByName(name);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -627,9 +662,7 @@ public class Mappings {
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
|
||||
final ClassRepr repr = classReprByName(who);
|
||||
|
||||
if (repr != null) {
|
||||
for (ClassRepr repr : classReprsByName(who)) {
|
||||
if (visitedClasses == null) {
|
||||
visitedClasses = new IntOpenHashSet();
|
||||
visitedClasses.add(who);
|
||||
@@ -679,20 +712,27 @@ public class Mappings {
|
||||
}
|
||||
|
||||
boolean isMethodVisible(final ClassRepr classRepr, final MethodRepr m) {
|
||||
return classRepr.findMethods(MethodRepr.equalByJavaRules(m)).size() > 0 || hasOverriddenMethods(classRepr, MethodRepr.equalByJavaRules(m), null);
|
||||
return !classRepr.findMethods(MethodRepr.equalByJavaRules(m)).isEmpty() || hasOverriddenMethods(classRepr, MethodRepr.equalByJavaRules(m), null);
|
||||
}
|
||||
|
||||
boolean isFieldVisible(final int className, final FieldRepr field) {
|
||||
final ClassRepr r = classReprByName(className);
|
||||
if (r == null || r.getFields().contains(field)) {
|
||||
final Iterable<ClassRepr> reprs = classReprsByName(className);
|
||||
if (Iterators.isEmpty(reprs)) {
|
||||
return true;
|
||||
}
|
||||
return hasOverriddenFields(field, r, null);
|
||||
for (ClassRepr r : reprs) {
|
||||
if (r.getFields().contains(field)) {
|
||||
return true;
|
||||
}
|
||||
if (hasOverriddenFields(field, r, null)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void collectSupersRecursively(final int className, @NotNull final IntSet container) {
|
||||
final ClassRepr classRepr = classReprByName(className);
|
||||
if (classRepr != null) {
|
||||
for (ClassRepr classRepr : classReprsByName(className)) {
|
||||
final Iterable<TypeRepr.ClassType> supers = classRepr.getSuperTypes();
|
||||
boolean added = false;
|
||||
for (TypeRepr.ClassType aSuper : supers) {
|
||||
@@ -732,10 +772,10 @@ public class Mappings {
|
||||
if (usages) {
|
||||
debug("Class usages affection requested");
|
||||
|
||||
final ClassRepr classRepr = classReprByName(className);
|
||||
if (classRepr != null) {
|
||||
for (ClassRepr classRepr : classReprsByName(className)) {
|
||||
debug("Added class usage for ", classRepr.name);
|
||||
affectedUsages.add(classRepr.createUsage());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -846,11 +886,11 @@ public class Mappings {
|
||||
}
|
||||
depNames.forEach(depName -> {
|
||||
if (visited.add(depName)) {
|
||||
final ClassFileRepr depRepr = reprByName(depName);
|
||||
if (depRepr instanceof ModuleRepr) {
|
||||
for (ModuleRepr depRepr : moduleReprsByName(depName)) {
|
||||
state.myDependants.add(depName);
|
||||
if (checkTransitive && ((ModuleRepr)depRepr).requiresTransitevely(modName)) {
|
||||
if (checkTransitive && depRepr.requiresTransitevely(modName)) {
|
||||
next.add(depName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1296,20 +1336,19 @@ public class Mappings {
|
||||
}
|
||||
|
||||
getAllSubclasses(it.name).forEach(subClass -> {
|
||||
final ClassRepr r = myFuture.classReprByName(subClass);
|
||||
if (r == null) {
|
||||
Iterable<ClassRepr> reprs = myFuture.classReprsByName(subClass);
|
||||
if (Iterators.isEmpty(reprs)) {
|
||||
return;
|
||||
}
|
||||
final Iterable<File> sourceFileNames = classToSourceFileGet(subClass);
|
||||
if (sourceFileNames != null && !containsAll(myCompiledFiles, sourceFileNames)) {
|
||||
final int outerClass = r.getOuterClassName();
|
||||
if (!isEmpty(outerClass)) {
|
||||
final ClassRepr outerClassRepr = myFuture.classReprByName(outerClass);
|
||||
if (outerClassRepr != null && (myFuture.isMethodVisible(outerClassRepr, addedMethod) || myFuture.extendsLibraryClass(outerClassRepr, null))) {
|
||||
for (ClassRepr outerClassRepr : Iterators.flat(Iterators.map(reprs, r -> isEmpty(r.getOuterClassName())? Collections.emptyList() : myFuture.classReprsByName(r.getOuterClassName())))) {
|
||||
if (myFuture.isMethodVisible(outerClassRepr, addedMethod) || myFuture.extendsLibraryClass(outerClassRepr, null)) {
|
||||
ContainerUtil.addAll(myAffectedFiles, sourceFileNames);
|
||||
for (File sourceFileName : sourceFileNames) {
|
||||
debug("Affecting file due to local overriding: ", sourceFileName);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1341,7 +1380,7 @@ public class Mappings {
|
||||
myFuture.affectStaticMemberImportUsages(m.name, it.name, propagated.get(), state.myAffectedUsages, state.myDependants);
|
||||
}
|
||||
|
||||
if (overriddenMethods.size() == 0) {
|
||||
if (overriddenMethods.isEmpty()) {
|
||||
debug("No overridden methods found, affecting method usages");
|
||||
myFuture.affectMethodUsages(m, propagated.get(), m.createUsage(myContext, it.name), state.myAffectedUsages, state.myDependants);
|
||||
}
|
||||
@@ -1383,9 +1422,7 @@ public class Mappings {
|
||||
if (!m.isAbstract() && !m.isStatic()) {
|
||||
propagated.get().forEach(p -> {
|
||||
if (p != it.name) {
|
||||
final ClassRepr s = myFuture.classReprByName(p);
|
||||
|
||||
if (s != null) {
|
||||
for (ClassRepr s : myFuture.classReprsByName(p)) {
|
||||
final Collection<Pair<MethodRepr, ClassRepr>> overridenInS = myFuture.findOverriddenMethods(m, s);
|
||||
|
||||
overridenInS.addAll(overriddenMethods);
|
||||
@@ -1415,7 +1452,6 @@ public class Mappings {
|
||||
|
||||
if (allAbstract && visited) {
|
||||
final Iterable<File> sources = classToSourceFileGet(p);
|
||||
|
||||
if (sources != null && !containsAll(myCompiledFiles, sources)) {
|
||||
ContainerUtil.addAll(myAffectedFiles, sources);
|
||||
debug("Removed method is not abstract & overrides some abstract method which is not then over-overridden in subclass ", p);
|
||||
@@ -1423,6 +1459,7 @@ public class Mappings {
|
||||
debug("Affecting subclass source file ", source);
|
||||
}
|
||||
}
|
||||
break; // classReprs
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1668,8 +1705,12 @@ public class Mappings {
|
||||
state.myAffectedUsages.add(usage);
|
||||
// only mark synthetic classes used to implement switch statements: this will limit the number of recompiled classes to those where switch statements on changed enum are used
|
||||
state.myUsageConstraints.put(usage, residence -> {
|
||||
final ClassRepr candidate = myPresent.classReprByName(residence);
|
||||
return candidate != null && candidate.isSynthetic();
|
||||
for (ClassRepr candidate : myPresent.classReprsByName(residence)) {
|
||||
if (candidate.isSynthetic()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1678,23 +1719,27 @@ public class Mappings {
|
||||
|
||||
if (!f.isPrivate()) {
|
||||
getAllSubclasses(classRepr.name).forEach(subClass -> {
|
||||
final ClassRepr r = myFuture.classReprByName(subClass);
|
||||
if (r != null) {
|
||||
final Iterable<ClassRepr> reprs = myFuture.classReprsByName(subClass);
|
||||
if (!Iterators.isEmpty(reprs)) {
|
||||
final Iterable<File> sourceFileNames = classToSourceFileGet(subClass);
|
||||
if (sourceFileNames != null && !containsAll(myCompiledFiles, sourceFileNames)) {
|
||||
if (r.isLocal()) {
|
||||
for (File sourceFileName : sourceFileNames) {
|
||||
debug("Affecting local subclass (introduced field can potentially hide surrounding method parameters/local variables): ", sourceFileName);
|
||||
myAffectedFiles.add(sourceFileName);
|
||||
}
|
||||
}
|
||||
else {
|
||||
final int outerClass = r.getOuterClassName();
|
||||
if (!isEmpty(outerClass) && myFuture.isFieldVisible(outerClass, f)) {
|
||||
for (ClassRepr r : reprs) {
|
||||
if (r.isLocal()) {
|
||||
for (File sourceFileName : sourceFileNames) {
|
||||
debug("Affecting inner subclass (introduced field can potentially hide surrounding class fields): ", sourceFileName);
|
||||
debug("Affecting local subclass (introduced field can potentially hide surrounding method parameters/local variables): ", sourceFileName);
|
||||
myAffectedFiles.add(sourceFileName);
|
||||
}
|
||||
break;
|
||||
}
|
||||
else {
|
||||
final int outerClass = r.getOuterClassName();
|
||||
if (!isEmpty(outerClass) && myFuture.isFieldVisible(outerClass, f)) {
|
||||
for (File sourceFileName : sourceFileNames) {
|
||||
debug("Affecting inner subclass (introduced field can potentially hide surrounding class fields): ", sourceFileName);
|
||||
myAffectedFiles.add(sourceFileName);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1949,11 +1994,9 @@ public class Mappings {
|
||||
if (superClassChanged) {
|
||||
myDelta.registerRemovedSuperClass(changedClass.name, changedClass.getSuperClass().className);
|
||||
|
||||
final ClassRepr newClass = myDelta.getClassReprByName(null, changedClass.name);
|
||||
|
||||
assert (newClass != null);
|
||||
|
||||
myDelta.registerAddedSuperClass(changedClass.name, newClass.getSuperClass().className);
|
||||
for (ClassRepr newClass : myDelta.getClassReprsByName(changedClass.name)) {
|
||||
myDelta.registerAddedSuperClass(changedClass.name, newClass.getSuperClass().className);
|
||||
}
|
||||
}
|
||||
|
||||
if (interfacesChanged) {
|
||||
@@ -1988,8 +2031,7 @@ public class Mappings {
|
||||
if (extendsChanged && directDeps != null) {
|
||||
final TypeRepr.ClassType excClass = TypeRepr.createClassType(myContext, changedClass.name);
|
||||
directDeps.forEach(depClass -> {
|
||||
final ClassRepr depClassRepr = myPresent.classReprByName(depClass);
|
||||
if (depClassRepr != null) {
|
||||
for (ClassRepr depClassRepr : myPresent.classReprsByName(depClass)) {
|
||||
myPresent.affectMethodUsagesThrowing(depClassRepr, excClass, state.myAffectedUsages, state.myDependants);
|
||||
}
|
||||
});
|
||||
@@ -2284,75 +2326,91 @@ public class Mappings {
|
||||
debug("Checking dependent classes:");
|
||||
assert myAffectedFiles != null;
|
||||
assert myCompiledFiles != null;
|
||||
IntIterator iterator = state.myDependants.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
int depClass = iterator.nextInt();
|
||||
Iterable<File> depFiles = classToSourceFileGet(depClass);
|
||||
if (depFiles != null) {
|
||||
for (File depFile : depFiles) {
|
||||
if (!processDependentFile(depClass, depFile, state)) {
|
||||
debug("Turning non-incremental for the BuildTarget because dependent class is annotation-processor generated");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@SuppressWarnings("DataFlowIssue")
|
||||
private boolean processDependentFile(int depClass, @NotNull File depFile, DiffState state) {
|
||||
debug("Dependent class: ", depClass);
|
||||
|
||||
final ClassFileRepr repr = getReprByName(depFile, depClass);
|
||||
if (repr == null) {
|
||||
if (state.myDependants.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
boolean isGenerated = false;
|
||||
if (repr instanceof ClassRepr) {
|
||||
final ClassRepr clsRepr = (ClassRepr)repr;
|
||||
if (!clsRepr.hasInlinedConstants() && myCompiledFiles.contains(depFile)) {
|
||||
// Classes containing inlined constants from other classes and compiled against older constant values
|
||||
// may need to be recompiled several times within compile session.
|
||||
// Otherwise, it is safe to skip the file if it has already been compiled in this session.
|
||||
return true;
|
||||
|
||||
BiFunction<ClassFileRepr, File, Boolean> dependentReprProcessor = new BiFunction<>() {
|
||||
private final Map<ClassFileRepr, Pair<Boolean, Boolean>> isAffected = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public Boolean apply(ClassFileRepr repr, File depFile) {
|
||||
final boolean isGenerated;
|
||||
if (repr instanceof ClassRepr) {
|
||||
final ClassRepr clsRepr = (ClassRepr)repr;
|
||||
if (!clsRepr.hasInlinedConstants() && myCompiledFiles.contains(depFile)) {
|
||||
// Classes containing inlined constants from other classes and compiled against older constant values
|
||||
// may need to be recompiled several times within compile session.
|
||||
// Otherwise, it is safe to skip the file if it has already been compiled in this session.
|
||||
return true;
|
||||
}
|
||||
|
||||
// If among affected files are annotation processor-generated, then we might need to re-generate them.
|
||||
// To achieve this, we need to recompile the whole chunk which will cause processors to re-generate these affected files
|
||||
isGenerated = clsRepr.isGenerated();
|
||||
}
|
||||
else {
|
||||
isGenerated = false;
|
||||
}
|
||||
|
||||
if (myAffectedFiles.contains(depFile)) {
|
||||
return !isGenerated;
|
||||
}
|
||||
|
||||
Pair<Boolean, Boolean> shouldAffect = isAffected.computeIfAbsent(repr, r -> {
|
||||
debug("Dependent class: ", r.name);
|
||||
final Set<UsageRepr.Usage> depUsages = r.getUsages();
|
||||
if (depUsages == null || depUsages.isEmpty()) {
|
||||
return Pair.create(false, !isGenerated);
|
||||
}
|
||||
for (UsageRepr.Usage usage : depUsages) {
|
||||
if (usage instanceof UsageRepr.AnnotationUsage) {
|
||||
final UsageRepr.AnnotationUsage annotationUsage = (UsageRepr.AnnotationUsage)usage;
|
||||
for (final UsageRepr.AnnotationUsage query : state.myAnnotationQuery) {
|
||||
if (query.satisfies(annotationUsage)) {
|
||||
debug("Added file due to annotation query");
|
||||
return Pair.create(true, !isGenerated);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (state.myAffectedUsages.contains(usage)) {
|
||||
final UsageConstraint constraint = state.myUsageConstraints.get(usage);
|
||||
if (constraint == null) {
|
||||
debug("Added file with no constraints");
|
||||
return Pair.create(true, !isGenerated);
|
||||
}
|
||||
if (constraint.checkResidence(r.name)) {
|
||||
debug("Added file with satisfied constraint");
|
||||
return Pair.create(true, !isGenerated);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Pair.create(false, true);
|
||||
});
|
||||
|
||||
if (shouldAffect.getFirst()) {
|
||||
myAffectedFiles.add(depFile);
|
||||
}
|
||||
return shouldAffect.getSecond();
|
||||
}
|
||||
|
||||
// If among affected files are annotation processor-generated, then we might need to re-generate them.
|
||||
// To achieve this, we need to recompile the whole chunk which will cause processors to re-generate these affected files
|
||||
isGenerated = clsRepr.isGenerated();
|
||||
}
|
||||
};
|
||||
|
||||
if (myAffectedFiles.contains(depFile)) {
|
||||
return !isGenerated;
|
||||
}
|
||||
final Set<UsageRepr.Usage> depUsages = repr.getUsages();
|
||||
if (depUsages == null || depUsages.isEmpty()) {
|
||||
return !isGenerated;
|
||||
}
|
||||
|
||||
for (UsageRepr.Usage usage : depUsages) {
|
||||
if (usage instanceof UsageRepr.AnnotationUsage) {
|
||||
final UsageRepr.AnnotationUsage annotationUsage = (UsageRepr.AnnotationUsage)usage;
|
||||
for (final UsageRepr.AnnotationUsage query : state.myAnnotationQuery) {
|
||||
if (query.satisfies(annotationUsage)) {
|
||||
debug("Added file due to annotation query");
|
||||
myAffectedFiles.add(depFile);
|
||||
return !isGenerated;
|
||||
for (IntIterator dependants = state.myDependants.iterator(); dependants.hasNext(); ) {
|
||||
int depName = dependants.nextInt();
|
||||
Iterable<Pair<ClassFileRepr, File>> dependentReprs = Iterators.filter(Iterators.map(Iterators.map(myClassToRelativeSourceFilePath.get(depName), src -> Pair.create(myRelativeSourceFilePathToClasses.get(src), toFull(src))), p -> {
|
||||
for (ClassFileRepr repr : p.getFirst()) {
|
||||
if (repr.name == depName) {
|
||||
return Pair.create(repr, p.getSecond());
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (state.myAffectedUsages.contains(usage)) {
|
||||
final UsageConstraint constraint = state.myUsageConstraints.get(usage);
|
||||
if (constraint == null) {
|
||||
debug("Added file with no constraints");
|
||||
myAffectedFiles.add(depFile);
|
||||
return !isGenerated;
|
||||
}
|
||||
if (constraint.checkResidence(depClass)) {
|
||||
debug("Added file with satisfied constraint");
|
||||
myAffectedFiles.add(depFile);
|
||||
return !isGenerated;
|
||||
return null;
|
||||
}), Iterators.notNullFilter());
|
||||
|
||||
for (Pair<ClassFileRepr, File> pair : dependentReprs) {
|
||||
if (!dependentReprProcessor.apply(pair.getFirst(), pair.getSecond())) {
|
||||
debug("Turning non-incremental for the BuildTarget because dependent class is annotation-processor generated");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2509,12 +2567,9 @@ public class Mappings {
|
||||
myPresent.affectDependentModules(state, moduleRepr.name, new UsageConstraint() {
|
||||
@Override
|
||||
public boolean checkResidence(int dep) {
|
||||
final ModuleRepr depModule = myPresent.moduleReprByName(dep);
|
||||
if (depModule != null) {
|
||||
for (ModuleRequiresRepr requires : depModule.getRequires()) {
|
||||
if (requires.name == moduleRepr.name && requires.getVersion() == version) {
|
||||
return true;
|
||||
}
|
||||
for (ModuleRequiresRepr requires : Iterators.flat(Iterators.map(myPresent.moduleReprsByName(dep), depModule -> depModule.getRequires()))) {
|
||||
if (requires.name == moduleRepr.name && requires.getVersion() == version) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -2612,20 +2667,13 @@ public class Mappings {
|
||||
return new Differential(delta, removed, filesToCompile, compiledWithErrors, compiledFiles, affectedFiles, filter).differentiate();
|
||||
}
|
||||
|
||||
private void cleanupBackDependency(final int className, @Nullable Set<? extends UsageRepr.Usage> usages, final IntIntMultiMaplet buffer) {
|
||||
private void cleanupBackDependency(final int className, @Nullable Iterable<? extends UsageRepr.Usage> usages, final IntIntMultiMaplet buffer) {
|
||||
if (usages == null) {
|
||||
final ClassFileRepr repr = getReprByName(null, className);
|
||||
if (repr != null) {
|
||||
usages = repr.getUsages();
|
||||
}
|
||||
usages = Iterators.flat(Iterators.map(getReprsByName(className), repr -> repr.getUsages()));
|
||||
}
|
||||
|
||||
if (usages != null) {
|
||||
for (final UsageRepr.Usage u : usages) {
|
||||
final int owner = u.getOwner();
|
||||
if (owner != className) {
|
||||
buffer.put(owner, className);
|
||||
}
|
||||
for (Integer owner : Iterators.unique(Iterators.map(usages, usage -> usage.getOwner()))) {
|
||||
if (owner != className) {
|
||||
buffer.put(owner, className);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2653,6 +2701,8 @@ public class Mappings {
|
||||
// many files
|
||||
for (File file : currentlyMapped) {
|
||||
if (!FileUtil.filesEqual(sourceFile, file) && file.exists()) {
|
||||
// ensure association with particular sourceFile is removed
|
||||
myClassToRelativeSourceFilePath.removeFrom(className, toRelative(sourceFile));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -2755,18 +2805,40 @@ public class Mappings {
|
||||
}
|
||||
});
|
||||
|
||||
delta.getChangedClasses().forEach(className -> {
|
||||
final Collection<String> sourceFiles = delta.myClassToRelativeSourceFilePath.get(className);
|
||||
myClassToRelativeSourceFilePath.replace(className, sourceFiles);
|
||||
final Set<String> changedRelativePaths = CollectionFactory.createFilePathSet();
|
||||
for (File file : delta.getChangedFiles()) {
|
||||
changedRelativePaths.add(toRelative(file));
|
||||
}
|
||||
|
||||
cleanupBackDependency(className, null, dependenciesTrashBin);
|
||||
delta.getChangedClasses().forEach(new IntConsumer() {
|
||||
final Set<String> pathsBuffer = CollectionFactory.createFilePathSet();
|
||||
@Override
|
||||
public void accept(int className) {
|
||||
Collection<String> currentPaths = myClassToRelativeSourceFilePath.get(className);
|
||||
if (currentPaths != null && !currentPaths.isEmpty()) {
|
||||
try {
|
||||
pathsBuffer.addAll(currentPaths);
|
||||
pathsBuffer.removeAll(changedRelativePaths);
|
||||
pathsBuffer.addAll(delta.myClassToRelativeSourceFilePath.get(className));
|
||||
if (pathsBuffer.size() != currentPaths.size() || !pathsBuffer.containsAll(currentPaths)) {
|
||||
myClassToRelativeSourceFilePath.replace(className, pathsBuffer);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
pathsBuffer.clear();
|
||||
}
|
||||
}
|
||||
else {
|
||||
myClassToRelativeSourceFilePath.replace(className, delta.myClassToRelativeSourceFilePath.get(className));
|
||||
}
|
||||
|
||||
cleanupBackDependency(className, null, dependenciesTrashBin);
|
||||
}
|
||||
});
|
||||
|
||||
delta.getChangedFiles().forEach(fileName -> {
|
||||
String relative = toRelative(fileName);
|
||||
Collection<ClassFileRepr> classes = delta.myRelativeSourceFilePathToClasses.get(relative);
|
||||
myRelativeSourceFilePathToClasses.replace(relative, classes);
|
||||
});
|
||||
for (String path : changedRelativePaths) {
|
||||
myRelativeSourceFilePathToClasses.replace(path, delta.myRelativeSourceFilePathToClasses.get(path));
|
||||
}
|
||||
|
||||
// some classes may be associated with multiple sources.
|
||||
// In case some of these sources was not compiled, but the class was changed, we need to update
|
||||
@@ -2807,7 +2879,7 @@ public class Mappings {
|
||||
}
|
||||
else {
|
||||
myClassToSubclasses.putAll(delta.myClassToSubclasses);
|
||||
myClassToRelativeSourceFilePath.replaceAll(delta.myClassToRelativeSourceFilePath);
|
||||
myClassToRelativeSourceFilePath.putAll(delta.myClassToRelativeSourceFilePath);
|
||||
myRelativeSourceFilePathToClasses.replaceAll(delta.myRelativeSourceFilePathToClasses);
|
||||
delta.myRelativeSourceFilePathToClasses.forEachEntry(
|
||||
(src, classes) -> {
|
||||
@@ -3185,7 +3257,7 @@ public class Mappings {
|
||||
}
|
||||
|
||||
private static <T> Supplier<T> lazy(Supplier<? extends T> calculation) {
|
||||
return new Supplier<T>() {
|
||||
return new Supplier<>() {
|
||||
Ref<T> calculated;
|
||||
@Override
|
||||
public T get() {
|
||||
|
||||
@@ -1,20 +1,9 @@
|
||||
/*
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
// 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.ether;
|
||||
|
||||
import org.jetbrains.jps.model.JpsModuleRootModificationUtil;
|
||||
import org.jetbrains.jps.model.module.JpsModule;
|
||||
|
||||
public class ClassPropertyTest extends IncrementalTestCase {
|
||||
public ClassPropertyTest() {
|
||||
super("classProperties");
|
||||
@@ -63,4 +52,11 @@ public class ClassPropertyTest extends IncrementalTestCase {
|
||||
public void testConvertToCheckedException() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testConvertToCheckedExceptionMultiModule() {
|
||||
JpsModule module1 = addModule("module1", "module1/src");
|
||||
JpsModule module2 = addModule("module2", "module2/src");
|
||||
JpsModuleRootModificationUtil.addDependency(module2, module1);
|
||||
doTestBuild(1).assertSuccessful();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
// 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.ether;
|
||||
|
||||
import com.intellij.testFramework.PlatformTestUtil;
|
||||
@@ -141,6 +141,13 @@ public class CommonTest extends IncrementalTestCase {
|
||||
doTestBuild(1).assertSuccessful();
|
||||
}
|
||||
|
||||
public void testSameClassesInDifferentModules() {
|
||||
JpsModule moduleA = addModule("moduleA", "moduleA/src");
|
||||
JpsModule moduleB = addModule("moduleB", "moduleB/src");
|
||||
JpsModuleRootModificationUtil.addDependency(moduleB, moduleA); // ensure compilation sequence
|
||||
doTestBuild(1).assertSuccessful();
|
||||
}
|
||||
|
||||
public void testCompileDependenciesOnMovedClassesInFirstRound() {
|
||||
doTest().assertSuccessful();
|
||||
}
|
||||
@@ -168,12 +175,10 @@ public class CommonTest extends IncrementalTestCase {
|
||||
doTest();
|
||||
}
|
||||
|
||||
// Disabled because now several classes with the same qName in different modules are not supporter
|
||||
//
|
||||
//public void testConflictingClasses() {
|
||||
// JpsModule module1 = addModule("module1", "module1/src");
|
||||
// JpsModule module2 = addModule("module2", "module2/src");
|
||||
// JpsModuleRootModificationUtil.addDependency(module2, module1);
|
||||
// doTestBuild(1).assertSuccessful();
|
||||
//}
|
||||
public void testConflictingClasses() {
|
||||
JpsModule module1 = addModule("module1", "module1/src");
|
||||
JpsModule module2 = addModule("module2", "module2/src");
|
||||
JpsModuleRootModificationUtil.addDependency(module2, module1);
|
||||
doTestBuild(1).assertSuccessful();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user