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/Minifier.java b/src/main/java/com/android/tools/r8/naming/Minifier.java
index b886f2b..50d1652 100644
--- a/src/main/java/com/android/tools/r8/naming/Minifier.java
+++ b/src/main/java/com/android/tools/r8/naming/Minifier.java
@@ -48,7 +48,7 @@
SubtypingInfo subtypingInfo = appView.appInfo().computeSubtypingInfo();
timing.begin("ComputeInterfaces");
Set<DexClass> interfaces = new TreeSet<>((a, b) -> a.type.slowCompareTo(b.type));
- interfaces.addAll(appView.appInfo().computeReachableInterfaces());
+ appView.appInfo().forEachReachableInterface(interfaces::add);
timing.end();
timing.begin("MinifyClasses");
ClassNameMinifier classNameMinifier =
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 fab1147..770d32e 100644
--- a/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java
@@ -4,6 +4,8 @@
package com.android.tools.r8.naming;
+import static com.android.tools.r8.utils.IterableUtils.fromMethod;
+
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClass;
@@ -47,7 +49,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;
/**
@@ -96,19 +97,17 @@
timing.begin("MappingInterfaces");
Set<DexClass> interfaces = new TreeSet<>((a, b) -> a.type.slowCompareTo(b.type));
- Consumer<DexClass> consumer =
- dexClass -> {
- if (dexClass.isInterface()) {
- // Only visit top level interfaces because computeMapping will visit the hierarchy.
- if (dexClass.interfaces.isEmpty()) {
- computeMapping(dexClass.type, nonPrivateMembers, notMappedReferences, subtypingInfo);
- }
- interfaces.add(dexClass);
- }
- };
// 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/optimize/ClassAndMemberPublicizer.java b/src/main/java/com/android/tools/r8/optimize/ClassAndMemberPublicizer.java
index 4edec01..93dfaa9 100644
--- a/src/main/java/com/android/tools/r8/optimize/ClassAndMemberPublicizer.java
+++ b/src/main/java/com/android/tools/r8/optimize/ClassAndMemberPublicizer.java
@@ -10,7 +10,6 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexApplication;
-import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
@@ -73,9 +72,7 @@
// Phase 2: Visit classes and promote class/member to public if possible.
timing.begin("Phase 2: promoteToPublic");
- for (DexClass iface : appView.appInfo().computeReachableInterfaces()) {
- publicizeType(iface.type);
- }
+ appView.appInfo().forEachReachableInterface(clazz -> publicizeType(clazz.getType()));
publicizeType(appView.dexItemFactory().objectType);
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 fb1eeeb..f78dacd 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -58,6 +58,7 @@
import com.android.tools.r8.utils.Visibility;
import com.android.tools.r8.utils.WorkList;
import com.android.tools.r8.utils.collections.ProgramMethodSet;
+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;
@@ -614,9 +615,14 @@
return clazz == null || !clazz.isProgramClass();
}
- public Collection<DexClass> computeReachableInterfaces() {
- Set<DexClass> interfaces = Sets.newIdentityHashSet();
+ 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);
@@ -628,16 +634,11 @@
continue;
}
if (definition.isInterface()) {
- interfaces.add(definition);
+ consumer.accept(definition);
}
- if (definition.superType != null) {
- worklist.addIfNotSeen(definition.superType);
- }
- worklist.addIfNotSeen(definition.interfaces.values);
+ definition.forEachImmediateSupertype(worklist::addIfNotSeen);
}
- return interfaces;
}
-
/**
* Resolve the methods implemented by the lambda expression that created the {@code callSite}.
*
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 af3208f..8c652f5 100644
--- a/src/main/java/com/android/tools/r8/utils/IterableUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/IterableUtils.java
@@ -7,6 +7,8 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.function.Consumer;
+import java.util.function.Function;
import java.util.function.Predicate;
public class IterableUtils {
@@ -49,4 +51,10 @@
iterable.forEach(result::add);
return result;
}
+
+ 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 8ee6e30..12afc13 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) {
@@ -54,7 +54,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()));
}