Visit library interfaces if super interfaces of classpath interfaces
Bug: 181887416
Change-Id: Ifbce94da3702116fa0911b100037befb6c2aa93c
diff --git a/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java b/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java
index b75956e..d902890 100644
--- a/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java
@@ -5,6 +5,7 @@
package com.android.tools.r8.naming;
import static com.android.tools.r8.graph.DexApplication.classesWithDeterministicOrder;
+import static com.android.tools.r8.utils.IterableUtils.fromMethod;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
@@ -51,7 +52,6 @@
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.function.BiPredicate;
-import java.util.function.Consumer;
import java.util.function.Predicate;
/**
@@ -99,19 +99,17 @@
timing.begin("MappingInterfaces");
Set<DexClass> interfaces = new TreeSet<>(Comparator.comparing(DexClass::getType));
- Consumer<DexClass> consumer =
- clazz -> {
- if (clazz.isInterface()) {
- // Only visit top level interfaces because computeMapping will visit the hierarchy.
- if (clazz.interfaces.isEmpty()) {
- computeMapping(clazz.type, nonPrivateMembers, notMappedReferences, subtypingInfo);
- }
- interfaces.add(clazz);
- }
- };
// For union-find of interface methods we also need to add the library types above live types.
- appInfo.forEachTypeInHierarchyOfLiveProgramClasses(consumer);
- appInfo.forEachReferencedClasspathClass(consumer::accept);
+ appInfo.forEachReachableInterface(
+ iFace -> {
+ assert iFace.isInterface();
+ interfaces.add(iFace);
+ if (iFace.interfaces.isEmpty()) {
+ computeMapping(iFace.type, nonPrivateMembers, notMappedReferences, subtypingInfo);
+ }
+ },
+ fromMethod(appInfo::forEachReferencedClasspathClass, DexClass::getType));
+
assert nonPrivateMembers.isEmpty();
timing.end();
diff --git a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
index b186a52..c9db30c 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -59,6 +59,7 @@
import com.android.tools.r8.utils.WorkList;
import com.android.tools.r8.utils.collections.ProgramMethodSet;
import com.android.tools.r8.utils.structural.Ordered;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.Sets;
import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
import it.unimi.dsi.fastutil.objects.Object2BooleanMap;
@@ -662,7 +663,13 @@
}
public void forEachReachableInterface(Consumer<DexClass> consumer) {
+ forEachReachableInterface(consumer, ImmutableList.of());
+ }
+
+ public void forEachReachableInterface(
+ Consumer<DexClass> consumer, Iterable<DexType> additionalPaths) {
WorkList<DexType> worklist = WorkList.newIdentityWorkList();
+ worklist.addIfNotSeen(additionalPaths);
worklist.addIfNotSeen(objectAllocationInfoCollection.getInstantiatedLambdaInterfaces());
for (DexProgramClass clazz : classes()) {
worklist.addIfNotSeen(clazz.type);
@@ -676,10 +683,7 @@
if (definition.isInterface()) {
consumer.accept(definition);
}
- if (definition.superType != null) {
- worklist.addIfNotSeen(definition.superType);
- }
- worklist.addIfNotSeen(definition.interfaces.values);
+ definition.forEachImmediateSupertype(worklist::addIfNotSeen);
}
}
diff --git a/src/main/java/com/android/tools/r8/utils/IterableUtils.java b/src/main/java/com/android/tools/r8/utils/IterableUtils.java
index ce8396f..1354a33 100644
--- a/src/main/java/com/android/tools/r8/utils/IterableUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/IterableUtils.java
@@ -12,6 +12,7 @@
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.BiPredicate;
+import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
@@ -151,4 +152,10 @@
}
return !iterator.hasNext();
}
+
+ public static <T, R> Iterable<R> fromMethod(Consumer<Consumer<T>> method, Function<T, R> mapper) {
+ List<R> ts = new ArrayList<>();
+ method.accept(t -> ts.add(mapper.apply(t)));
+ return ts;
+ }
}
diff --git a/src/main/java/com/android/tools/r8/utils/WorkList.java b/src/main/java/com/android/tools/r8/utils/WorkList.java
index e5fb33f..4279cb7 100644
--- a/src/main/java/com/android/tools/r8/utils/WorkList.java
+++ b/src/main/java/com/android/tools/r8/utils/WorkList.java
@@ -27,7 +27,7 @@
}
public static <T> WorkList<T> newIdentityWorkList() {
- return new WorkList<T>(EqualityTest.IDENTITY);
+ return new WorkList<>(EqualityTest.IDENTITY);
}
public static <T> WorkList<T> newIdentityWorkList(T item) {
@@ -60,7 +60,7 @@
items.forEach(workingList::addLast);
}
- public void addIfNotSeen(Iterable<T> items) {
+ public void addIfNotSeen(Iterable<? extends T> items) {
items.forEach(this::addIfNotSeen);
}
diff --git a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingClassPathInterfaceInheritTest.java b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingClassPathInterfaceInheritTest.java
index 3ec9e8f..5270eab 100644
--- a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingClassPathInterfaceInheritTest.java
+++ b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingClassPathInterfaceInheritTest.java
@@ -61,10 +61,9 @@
.addRunClasspathClasses(LibI.class)
.addRunClasspathFiles(libraryJar)
.run(parameters.getRuntime(), Main.class)
- // TODO(b/181887416): Should not throw an error when minifyLibrary == true.
.applyIf(
minifyLibrary,
- r -> r.assertFailureWithErrorThatThrows(ClassNotFoundException.class),
+ r -> r.assertSuccessWithOutputLines("a.a"),
r -> r.assertSuccessWithOutputLines(ClassPathI.class.getTypeName()));
}