Remove all uses of SubtypingInfo
Change-Id: I88bb14aa836d782c3e98aa37150889eac982a285
diff --git a/src/main/java/com/android/tools/r8/graph/ImmediateAppSubtypingInfo.java b/src/main/java/com/android/tools/r8/graph/ImmediateAppSubtypingInfo.java
index 84a589a..b313aa2 100644
--- a/src/main/java/com/android/tools/r8/graph/ImmediateAppSubtypingInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/ImmediateAppSubtypingInfo.java
@@ -3,17 +3,15 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.graph;
+import static com.android.tools.r8.graph.DexApplication.classesWithDeterministicOrder;
import static com.android.tools.r8.utils.MapUtils.ignoreKey;
-import com.android.tools.r8.utils.TraversalContinuation;
import com.google.common.collect.Iterables;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
-import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;
-import java.util.function.Predicate;
public class ImmediateAppSubtypingInfo extends ImmediateSubtypingInfo<DexClass, DexClass> {
@@ -29,6 +27,11 @@
DirectMappedDexApplication app = appView.app().asDirect();
Iterable<DexClass> classes =
Iterables.concat(app.programClasses(), app.classpathClasses(), app.libraryClasses());
+ return create(appView, classes);
+ }
+
+ public static ImmediateAppSubtypingInfo create(
+ AppView<? extends AppInfoWithClassHierarchy> appView, Iterable<DexClass> classes) {
return internalCreate(
appView,
classes,
@@ -36,23 +39,21 @@
immediateSubtypes -> new ImmediateAppSubtypingInfo(appView, immediateSubtypes));
}
- public void forEachTransitiveProgramSubclass(
- DexClass clazz, Consumer<? super DexProgramClass> consumer) {
- forEachTransitiveProgramSubclass(clazz, consumer, Function.identity());
+ @Override
+ DexClass toS(DexClass clazz) {
+ return clazz;
}
- public Set<DexProgramClass> getTransitiveProgramSubclasses(DexClass clazz) {
- return getTransitiveProgramSubclasses(clazz, Function.identity());
+ // TODO(b/188395655): This is equivalent to just sorting all interfaces?
+ public List<DexClass> computeReachableInterfacesWithDeterministicOrder() {
+ List<DexClass> interfaces = new ArrayList<>();
+ forEachInterface(interfaces::add);
+ return classesWithDeterministicOrder(interfaces);
}
- public Set<DexProgramClass> getTransitiveProgramSubclassesMatching(
- DexClass clazz, Predicate<DexProgramClass> predicate) {
- return getTransitiveProgramSubclassesMatching(clazz, Function.identity(), predicate);
- }
-
- public <TB, TC> TraversalContinuation<TB, TC> traverseTransitiveSubclasses(
- DexClass clazz, Function<DexClass, TraversalContinuation<TB, TC>> fn) {
- return traverseTransitiveSubclasses(clazz, Function.identity(), fn);
+ private void forEachInterface(Consumer<DexClass> consumer) {
+ DexClass objectClass = appView.definitionFor(appView.dexItemFactory().objectType);
+ forEachImmediateSubClassMatching(objectClass, DexClass::isInterface, consumer);
}
public void update(AppView<? extends AppInfoWithClassHierarchy> appView) {
diff --git a/src/main/java/com/android/tools/r8/graph/ImmediateProgramSubtypingInfo.java b/src/main/java/com/android/tools/r8/graph/ImmediateProgramSubtypingInfo.java
index ffd3958..49dc125 100644
--- a/src/main/java/com/android/tools/r8/graph/ImmediateProgramSubtypingInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/ImmediateProgramSubtypingInfo.java
@@ -33,4 +33,9 @@
DexProgramClass::asProgramClassOrNull,
immediateSubtypes -> new ImmediateProgramSubtypingInfo(appView, immediateSubtypes));
}
+
+ @Override
+ DexProgramClass toS(DexClass clazz) {
+ return DexProgramClass.asProgramClassOrNull(clazz);
+ }
}
diff --git a/src/main/java/com/android/tools/r8/graph/ImmediateSubtypingInfo.java b/src/main/java/com/android/tools/r8/graph/ImmediateSubtypingInfo.java
index 01b66d3..7313380 100644
--- a/src/main/java/com/android/tools/r8/graph/ImmediateSubtypingInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/ImmediateSubtypingInfo.java
@@ -55,6 +55,8 @@
return factory.apply(immediateSubtypes);
}
+ abstract S toS(DexClass clazz);
+
public void forEachImmediateSuperClass(DexClass clazz, Consumer<? super DexClass> consumer) {
forEachImmediateSuperClassMatching(
clazz,
@@ -120,32 +122,42 @@
});
}
- void forEachTransitiveProgramSubclass(
- S clazz, Consumer<? super DexProgramClass> consumer, Function<DexClass, S> cast) {
- forEachTransitiveProgramSubclassMatching(clazz, consumer, cast, Predicates.alwaysTrue());
+ public void forEachTransitiveSubclass(S clazz, Consumer<? super T> consumer) {
+ forEachTransitiveSubclassMatching(clazz, Predicates.alwaysTrue(), consumer);
}
- void forEachTransitiveProgramSubclassMatching(
- S clazz,
- Consumer<? super DexProgramClass> consumer,
- Function<DexClass, S> cast,
- Predicate<DexProgramClass> predicate) {
- WorkList<DexClass> worklist = WorkList.newIdentityWorkList(getSubclasses(clazz));
+ @SuppressWarnings("unchecked")
+ public <U extends DexClass> void forEachTransitiveSubclassMatching(
+ S clazz, Predicate<? super T> predicate, Consumer<? super U> consumer) {
+ WorkList<T> worklist = WorkList.newIdentityWorkList(getSubclasses(clazz));
worklist.process(
subclass -> {
- if (subclass.isProgramClass()) {
- DexProgramClass programSubclass = subclass.asProgramClass();
- if (predicate.test(programSubclass)) {
- consumer.accept(programSubclass);
- }
+ if (predicate.test(subclass)) {
+ consumer.accept((U) subclass);
}
- S subclassOrNull = cast.apply(subclass);
+ S subclassOrNull = toS(subclass);
if (subclassOrNull != null) {
worklist.addIfNotSeen(getSubclasses(subclassOrNull));
}
});
}
+ public void forEachTransitiveProgramSubclass(
+ S clazz, Consumer<? super DexProgramClass> consumer) {
+ forEachTransitiveProgramSubclassMatching(clazz, Predicates.alwaysTrue(), consumer);
+ }
+
+ @SuppressWarnings("unchecked")
+ public void forEachTransitiveProgramSubclassMatching(
+ S clazz,
+ Predicate<? super DexProgramClass> predicate,
+ Consumer<? super DexProgramClass> consumer) {
+ forEachTransitiveSubclassMatching(
+ clazz,
+ subclass -> subclass.isProgramClass() && predicate.test(subclass.asProgramClass()),
+ consumer);
+ }
+
public List<T> getSubclasses(S clazz) {
return immediateSubtypes.getOrDefault(clazz, Collections.emptyList());
}
@@ -163,14 +175,14 @@
Objects::nonNull);
}
- Set<DexProgramClass> getTransitiveProgramSubclasses(S clazz, Function<DexClass, S> cast) {
- return getTransitiveProgramSubclassesMatching(clazz, cast, Predicates.alwaysTrue());
+ public Set<DexProgramClass> getTransitiveProgramSubclasses(S clazz) {
+ return getTransitiveProgramSubclassesMatching(clazz, Predicates.alwaysTrue());
}
- Set<DexProgramClass> getTransitiveProgramSubclassesMatching(
- S clazz, Function<DexClass, S> cast, Predicate<DexProgramClass> predicate) {
+ public Set<DexProgramClass> getTransitiveProgramSubclassesMatching(
+ S clazz, Predicate<DexProgramClass> predicate) {
Set<DexProgramClass> classes = Sets.newIdentityHashSet();
- forEachTransitiveProgramSubclassMatching(clazz, classes::add, cast, predicate);
+ forEachTransitiveProgramSubclassMatching(clazz, predicate, classes::add);
return classes;
}
@@ -178,10 +190,8 @@
return !getSubclasses(clazz).isEmpty();
}
- <TB, TC> TraversalContinuation<TB, TC> traverseTransitiveSubclasses(
- S clazz,
- Function<DexClass, S> cast,
- Function<? super DexClass, TraversalContinuation<TB, TC>> fn) {
+ public <TB, TC> TraversalContinuation<TB, TC> traverseTransitiveSubclasses(
+ S clazz, Function<? super DexClass, TraversalContinuation<TB, TC>> fn) {
TraversalContinuation<TB, TC> traversalContinuation = TraversalContinuation.doContinue();
WorkList<DexClass> worklist = WorkList.newIdentityWorkList(getSubclasses(clazz));
while (worklist.hasNext()) {
@@ -190,7 +200,7 @@
if (traversalContinuation.shouldBreak()) {
return traversalContinuation;
}
- S subclassOrNull = cast.apply(subclass);
+ S subclassOrNull = toS(subclass);
if (subclassOrNull != null) {
worklist.addIfNotSeen(getSubclasses(subclassOrNull));
}
diff --git a/src/main/java/com/android/tools/r8/graph/SubtypingInfo.java b/src/main/java/com/android/tools/r8/graph/SubtypingInfo.java
deleted file mode 100644
index 523caf6..0000000
--- a/src/main/java/com/android/tools/r8/graph/SubtypingInfo.java
+++ /dev/null
@@ -1,377 +0,0 @@
-// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-package com.android.tools.r8.graph;
-
-import static com.android.tools.r8.graph.DexApplication.classesWithDeterministicOrder;
-import static com.android.tools.r8.utils.MapUtils.ignoreKey;
-
-import com.android.tools.r8.utils.WorkList;
-import com.android.tools.r8.utils.structural.StructuralItem;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Sets;
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.Deque;
-import java.util.HashSet;
-import java.util.IdentityHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentSkipListSet;
-import java.util.function.Consumer;
-
-public class SubtypingInfo {
-
- private static final int ROOT_LEVEL = 0;
- private static final int UNKNOWN_LEVEL = -1;
- private static final int INTERFACE_LEVEL = -2;
- // Since most Java types has no sub-types, we can just share an empty immutable set until we
- // need to add to it.
- private static final Set<DexType> NO_DIRECT_SUBTYPE = ImmutableSet.of();
- // Map from types to their subtypes.
- private final Map<DexType, Set<DexType>> subtypeMap;
-
- private Map<DexType, TypeInfo> typeInfo;
-
- private final DexDefinitionSupplier definitionSupplier;
- private final DexItemFactory factory;
-
- private SubtypingInfo(
- Map<DexType, TypeInfo> typeInfo,
- Map<DexType, Set<DexType>> subtypeMap,
- DexDefinitionSupplier definitionSupplier) {
- this.typeInfo = typeInfo;
- this.subtypeMap = subtypeMap;
- this.definitionSupplier = definitionSupplier;
- factory = definitionSupplier.dexItemFactory();
- }
-
- public void update(AppView<? extends AppInfoWithClassHierarchy> appView) {
- assert typeInfo == null : "Extending typeInfo not implemented";
- if (!appView.getSyntheticItems().hasPendingSyntheticClasses()) {
- return;
- }
- WorkList<DexType> worklist = WorkList.newIdentityWorkList();
- for (DexClass clazz : appView.getSyntheticItems().getAllPendingSyntheticClasses()) {
- worklist.addIfNotSeen(clazz.allImmediateSupertypes());
- worklist.process(
- supertype -> {
- DexClass superclass = appView.definitionFor(supertype);
- if (superclass == null) {
- return;
- }
- subtypeMap.computeIfAbsent(supertype, ignoreKey(HashSet::new)).add(clazz.getType());
- worklist.addIfNotSeen(superclass.allImmediateSupertypes());
- });
- worklist.clearSeen();
- }
- }
-
- public SubtypingInfo unsetTypeInfo() {
- typeInfo = null;
- return this;
- }
-
- public static SubtypingInfo create(AppView<? extends AppInfoWithClassHierarchy> appView) {
- AppInfoWithClassHierarchy appInfo = appView.appInfo();
- DirectMappedDexApplication app = appInfo.app().asDirect();
- Iterable<DexClass> classes =
- Iterables.concat(app.programClasses(), app.classpathClasses(), app.libraryClasses());
- return create(classes, appInfo);
- }
-
- public static SubtypingInfo create(
- Iterable<? extends DexClass> classes, DexDefinitionSupplier definitions) {
- Map<DexType, TypeInfo> typeInfo = new ConcurrentHashMap<>();
- Map<DexType, Set<DexType>> subtypeMap = new IdentityHashMap<>();
- populateSubtypeMap(classes, subtypeMap, typeInfo, definitions);
- return new SubtypingInfo(typeInfo, subtypeMap, definitions);
- }
-
- private static void populateSuperType(
- Map<DexType, Set<DexType>> map,
- Map<DexType, TypeInfo> typeInfo,
- DexType superType,
- DexClass baseClass,
- DexDefinitionSupplier definitionSupplier) {
- if (superType != null) {
- Set<DexType> set = map.computeIfAbsent(superType, ignore -> new HashSet<>());
- if (set.add(baseClass.type)) {
- // Only continue recursion if type has been added to set.
- populateAllSuperTypes(map, typeInfo, superType, baseClass, definitionSupplier);
- }
- }
- }
-
- private TypeInfo getTypeInfo(DexType type) {
- return getTypeInfo(type, typeInfo);
- }
-
- private static TypeInfo getTypeInfo(DexType type, Map<DexType, TypeInfo> typeInfo) {
- assert type != null;
- return typeInfo.computeIfAbsent(type, TypeInfo::new);
- }
-
- @SuppressWarnings("ReferenceEquality")
- private static void populateAllSuperTypes(
- Map<DexType, Set<DexType>> map,
- Map<DexType, TypeInfo> typeInfo,
- DexType holder,
- DexClass baseClass,
- DexDefinitionSupplier definitionSupplier) {
- DexClass holderClass = definitionSupplier.contextIndependentDefinitionFor(holder);
- // Skip if no corresponding class is found.
- TypeInfo typeInfoHere = getTypeInfo(holder, typeInfo);
- if (holderClass != null) {
- holderClass.forEachImmediateSupertype(
- (superType, isInterface) -> {
- populateSuperType(map, typeInfo, superType, baseClass, definitionSupplier);
- TypeInfo superTypeInfo = getTypeInfo(superType, typeInfo);
- if (isInterface) {
- superTypeInfo.addInterfaceSubtype(holder);
- } else {
- superTypeInfo.addDirectSubtype(typeInfoHere);
- }
- });
- if (holderClass.isInterface()) {
- typeInfoHere.tagAsInterface();
- }
- } else {
- // The subtype chain is broken, at least make this type a subtype of Object.
- DexType objectType = definitionSupplier.dexItemFactory().objectType;
- if (holder != objectType) {
- getTypeInfo(objectType, typeInfo).addDirectSubtype(typeInfoHere);
- }
- }
- }
-
- private static void populateSubtypeMap(
- Iterable<? extends DexClass> classes,
- Map<DexType, Set<DexType>> map,
- Map<DexType, TypeInfo> typeInfo,
- DexDefinitionSupplier definitionSupplier) {
- getTypeInfo(definitionSupplier.dexItemFactory().objectType, typeInfo).tagAsSubtypeRoot();
- for (DexClass clazz : classes) {
- populateAllSuperTypes(map, typeInfo, clazz.type, clazz, definitionSupplier);
- }
- assert validateLevelsAreCorrect(typeInfo, definitionSupplier);
- }
-
- @SuppressWarnings("ReferenceEquality")
- private static boolean validateLevelsAreCorrect(
- Map<DexType, TypeInfo> typeInfo, DexDefinitionSupplier definitionSupplier) {
- Set<DexType> seenTypes = Sets.newIdentityHashSet();
- Deque<DexType> worklist = new ArrayDeque<>();
- DexType objectType = definitionSupplier.dexItemFactory().objectType;
- worklist.add(objectType);
- while (!worklist.isEmpty()) {
- DexType next = worklist.pop();
- DexClass nextHolder = definitionSupplier.contextIndependentDefinitionFor(next);
- DexType superType;
- if (nextHolder == null) {
- // We might lack the definition of Object, so guard against that.
- superType = next == objectType ? null : objectType;
- } else {
- superType = nextHolder.superType;
- }
- assert !seenTypes.contains(next);
- seenTypes.add(next);
- TypeInfo nextInfo = getTypeInfo(next, typeInfo);
- if (superType == null) {
- assert nextInfo.hierarchyLevel == ROOT_LEVEL;
- } else {
- TypeInfo superInfo = getTypeInfo(superType, typeInfo);
- assert superInfo.hierarchyLevel == nextInfo.hierarchyLevel - 1
- || (superInfo.hierarchyLevel == ROOT_LEVEL
- && nextInfo.hierarchyLevel == INTERFACE_LEVEL);
- assert superInfo.directSubtypes.contains(next);
- }
- if (nextInfo.hierarchyLevel != INTERFACE_LEVEL) {
- // Only traverse the class hierarchy subtypes, not interfaces.
- worklist.addAll(nextInfo.directSubtypes);
- } else if (nextHolder != null) {
- // Test that the interfaces of this class are interfaces and have this class as subtype.
- for (DexType iface : nextHolder.interfaces.values) {
- TypeInfo ifaceInfo = getTypeInfo(iface, typeInfo);
- assert ifaceInfo.directSubtypes.contains(next);
- assert ifaceInfo.hierarchyLevel == INTERFACE_LEVEL;
- }
- }
- }
- return true;
- }
-
- public Set<DexType> subtypes(DexType type) {
- assert type.isClassType();
- Set<DexType> subtypes = subtypeMap.get(type);
- return subtypes == null ? ImmutableSet.of() : subtypes;
- }
-
- /**
- * Apply the given function to all classes that directly extend this class.
- *
- * <p>If this class is an interface, then this method will visit all sub-interfaces. This deviates
- * from the dex-file encoding, where subinterfaces "implement" their super interfaces. However, it
- * is consistent with the source language.
- */
- public void forAllImmediateExtendsSubtypes(DexType type, Consumer<DexType> f) {
- allImmediateExtendsSubtypes(type).forEach(f);
- }
-
- public Iterable<DexType> allImmediateExtendsSubtypes(DexType type) {
- TypeInfo info = getTypeInfo(type);
- assert info.hierarchyLevel != SubtypingInfo.UNKNOWN_LEVEL;
- if (info.hierarchyLevel == SubtypingInfo.INTERFACE_LEVEL) {
- return Iterables.filter(info.directSubtypes, t -> getTypeInfo(t).isInterface());
- } else if (info.hierarchyLevel == SubtypingInfo.ROOT_LEVEL) {
- // This is the object type. Filter out interfaces
- return Iterables.filter(info.directSubtypes, t -> !getTypeInfo(t).isInterface());
- } else {
- return info.directSubtypes;
- }
- }
-
- public Set<DexType> allImmediateSubtypes(DexType type) {
- return getTypeInfo(type).directSubtypes;
- }
-
- public void forAllInterfaceRoots(Consumer<DexType> fn) {
- Iterables.filter(
- getTypeInfo(factory.objectType).directSubtypes,
- subtype -> getTypeInfo(subtype).isInterface())
- .forEach(fn);
- }
-
- public List<DexClass> computeReachableInterfacesWithDeterministicOrder() {
- List<DexClass> interfaces = new ArrayList<>();
- forAllInterfaceRoots(
- type ->
- definitionSupplier
- .contextIndependentDefinitionForWithResolutionResult(type)
- .forEachClassResolutionResult(interfaces::add));
- return classesWithDeterministicOrder(interfaces);
- }
-
- public boolean verifyUpToDate(AppView<AppInfoWithClassHierarchy> appView) {
- DirectMappedDexApplication app = appView.app().asDirect();
- Iterable<DexClass> classes =
- Iterables.concat(app.programClasses(), app.classpathClasses(), app.libraryClasses());
- for (DexClass clazz : classes) {
- assert verifyUpToDate(appView, clazz);
- }
- // This does not check that the `typeInfo` is up-to-date.
- assert typeInfo == null;
- return true;
- }
-
- private boolean verifyUpToDate(AppView<AppInfoWithClassHierarchy> appView, DexClass clazz) {
- WorkList<DexType> worklist = WorkList.newIdentityWorkList(clazz.allImmediateSupertypes());
- worklist.process(
- supertype -> {
- DexClass superclass = appView.definitionFor(supertype);
- if (superclass == null) {
- return;
- }
- assert subtypes(supertype).contains(clazz.getType())
- || (clazz.isLibraryClass()
- && appView.definitionFor(clazz.getType()).isProgramClass())
- : "Expected subtypes("
- + supertype.getTypeName()
- + ") to include "
- + clazz.getTypeName();
- worklist.addIfNotSeen(superclass.allImmediateSupertypes());
- });
- return true;
- }
-
- private static class TypeInfo {
-
- private final DexType type;
-
- private int hierarchyLevel = UNKNOWN_LEVEL;
-
- /**
- * Set of direct subtypes. This set has to remain sorted to ensure determinism. The actual
- * sorting is not important but {@link DexType#compareTo(StructuralItem)} works well.
- */
- private Set<DexType> directSubtypes = NO_DIRECT_SUBTYPE;
-
- TypeInfo(DexType type) {
- this.type = type;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(type, directSubtypes);
- }
-
- @Override
- @SuppressWarnings("ReferenceEquality")
- public boolean equals(Object obj) {
- if (!(obj instanceof TypeInfo)) {
- return false;
- }
- TypeInfo other = (TypeInfo) obj;
- return other.type == type && other.directSubtypes.equals(directSubtypes);
- }
-
- @Override
- public String toString() {
- return "TypeInfo{" + type + ", level:" + hierarchyLevel + "}";
- }
-
- private void ensureDirectSubTypeSet() {
- if (directSubtypes == NO_DIRECT_SUBTYPE) {
- directSubtypes = new ConcurrentSkipListSet<>(DexType::compareTo);
- }
- }
-
- private void setLevel(int level) {
- if (level == hierarchyLevel) {
- return;
- }
- if (hierarchyLevel == INTERFACE_LEVEL) {
- assert level == ROOT_LEVEL + 1;
- } else if (level == INTERFACE_LEVEL) {
- assert hierarchyLevel == ROOT_LEVEL + 1 || hierarchyLevel == UNKNOWN_LEVEL;
- hierarchyLevel = INTERFACE_LEVEL;
- } else {
- assert hierarchyLevel == UNKNOWN_LEVEL;
- hierarchyLevel = level;
- }
- }
-
- private void addDirectSubtype(TypeInfo subtypeInfo) {
- assert hierarchyLevel != UNKNOWN_LEVEL;
- ensureDirectSubTypeSet();
- directSubtypes.add(subtypeInfo.type);
- subtypeInfo.setLevel(hierarchyLevel + 1);
- }
-
- private void tagAsSubtypeRoot() {
- setLevel(ROOT_LEVEL);
- }
-
- private void tagAsInterface() {
- setLevel(INTERFACE_LEVEL);
- }
-
- private boolean isInterface() {
- assert hierarchyLevel != UNKNOWN_LEVEL : "Program class missing: " + this;
- assert type.isClassType();
- return hierarchyLevel == INTERFACE_LEVEL;
- }
-
- private void addInterfaceSubtype(DexType type) {
- // Interfaces all inherit from java.lang.Object. However, we assign a special level to
- // identify them later on.
- setLevel(INTERFACE_LEVEL);
- ensureDirectSubTypeSet();
- directSubtypes.add(type);
- }
- }
-}
diff --git a/src/main/java/com/android/tools/r8/naming/FieldNameMinifier.java b/src/main/java/com/android/tools/r8/naming/FieldNameMinifier.java
index 634854a..cd8798d 100644
--- a/src/main/java/com/android/tools/r8/naming/FieldNameMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/FieldNameMinifier.java
@@ -10,8 +10,8 @@
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ImmediateAppSubtypingInfo;
import com.android.tools.r8.graph.ProgramField;
-import com.android.tools.r8.graph.SubtypingInfo;
import com.android.tools.r8.graph.TopDownClassHierarchyTraversal;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.SetUtils;
@@ -33,7 +33,7 @@
class FieldNameMinifier {
private final AppView<AppInfoWithLiveness> appView;
- private final SubtypingInfo subtypingInfo;
+ private final ImmediateAppSubtypingInfo subtypingInfo;
private final Map<DexField, DexString> renaming = new IdentityHashMap<>();
private final Map<DexType, ReservedFieldNamingState> reservedNamingStates =
new IdentityHashMap<>();
@@ -44,7 +44,7 @@
FieldNameMinifier(
AppView<AppInfoWithLiveness> appView,
- SubtypingInfo subtypingInfo,
+ ImmediateAppSubtypingInfo subtypingInfo,
MemberNamingStrategy strategy) {
this.appView = appView;
this.subtypingInfo = subtypingInfo;
@@ -321,18 +321,18 @@
if (clazz.isInterface()) {
partition.add(clazz);
- for (DexType subtype : minifier.subtypingInfo.allImmediateSubtypes(type)) {
- if (visited.add(subtype)) {
- worklist.add(subtype);
+ for (DexClass subclass : minifier.subtypingInfo.getSubclasses(clazz)) {
+ if (visited.add(subclass.getType())) {
+ worklist.add(subclass.getType());
}
}
} else if (clazz.type != appView.dexItemFactory().objectType) {
if (visited.add(clazz.superType)) {
worklist.add(clazz.superType);
}
- for (DexType subclass : minifier.subtypingInfo.allImmediateExtendsSubtypes(type)) {
- if (visited.add(subclass)) {
- worklist.add(subclass);
+ for (DexClass subclass : minifier.subtypingInfo.getSubclasses(clazz)) {
+ if (visited.add(subclass.getType())) {
+ worklist.add(subclass.getType());
}
}
}
diff --git a/src/main/java/com/android/tools/r8/naming/InterfaceMethodNameMinifier.java b/src/main/java/com/android/tools/r8/naming/InterfaceMethodNameMinifier.java
index 54685b4..b611309 100644
--- a/src/main/java/com/android/tools/r8/naming/InterfaceMethodNameMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/InterfaceMethodNameMinifier.java
@@ -13,7 +13,7 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.SubtypingInfo;
+import com.android.tools.r8.graph.ImmediateAppSubtypingInfo;
import com.android.tools.r8.ir.desugar.LambdaDescriptor;
import com.android.tools.r8.naming.MethodNameMinifier.State;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
@@ -383,7 +383,7 @@
};
private final AppView<AppInfoWithLiveness> appView;
- private final SubtypingInfo subtypingInfo;
+ private final ImmediateAppSubtypingInfo subtypingInfo;
private final MethodNameMinifier.State minifierState;
/** A map from DexMethods to all the states linked to interfaces they appear in. */
@@ -394,7 +394,9 @@
private final Map<DexType, InterfaceReservationState> interfaceStateMap = new HashMap<>();
InterfaceMethodNameMinifier(
- AppView<AppInfoWithLiveness> appView, State minifierState, SubtypingInfo subtypingInfo) {
+ AppView<AppInfoWithLiveness> appView,
+ State minifierState,
+ ImmediateAppSubtypingInfo subtypingInfo) {
this.appView = appView;
this.minifierState = minifierState;
this.subtypingInfo = subtypingInfo;
@@ -656,26 +658,24 @@
private void computeReservationFrontiersForAllImplementingClasses(Iterable<DexClass> interfaces) {
interfaces.forEach(
iface ->
- subtypingInfo
- .subtypes(iface.getType())
- .forEach(
- subType -> {
- DexClass subClass = appView.contextIndependentDefinitionFor(subType);
- if (subClass == null || subClass.isInterface()) {
- return;
- }
- DexType frontierType = minifierState.getFrontier(subType);
- if (minifierState.getReservationState(frontierType) == null) {
- // The reservation state should already be added. If it does not exist
- // it is because it is not reachable from the type hierarchy of program
- // classes and we can therefore disregard this interface.
- return;
- }
- InterfaceReservationState iState = interfaceStateMap.get(iface.getType());
- if (iState != null) {
- iState.addReservationType(frontierType);
- }
- }));
+ subtypingInfo.forEachTransitiveSubclass(
+ iface,
+ subclass -> {
+ if (subclass.isInterface()) {
+ return;
+ }
+ DexType frontierType = minifierState.getFrontier(subclass.getType());
+ if (minifierState.getReservationState(frontierType) == null) {
+ // The reservation state should already be added. If it does not exist
+ // it is because it is not reachable from the type hierarchy of program
+ // classes and we can therefore disregard this interface.
+ return;
+ }
+ InterfaceReservationState iState = interfaceStateMap.get(iface.getType());
+ if (iState != null) {
+ iState.addReservationType(frontierType);
+ }
+ }));
}
private boolean verifyAllCallSitesAreRepresentedIn(List<DexClassAndMethod> groups) {
diff --git a/src/main/java/com/android/tools/r8/naming/MethodNameMinifier.java b/src/main/java/com/android/tools/r8/naming/MethodNameMinifier.java
index 4669081..2d175ce 100644
--- a/src/main/java/com/android/tools/r8/naming/MethodNameMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/MethodNameMinifier.java
@@ -13,7 +13,7 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.SubtypingInfo;
+import com.android.tools.r8.graph.ImmediateAppSubtypingInfo;
import com.android.tools.r8.graph.TopDownClassHierarchyTraversal;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.InternalOptions;
@@ -182,7 +182,7 @@
}
MethodRenaming computeRenaming(
- Iterable<DexClass> interfaces, SubtypingInfo subtypingInfo, Timing timing) {
+ Iterable<DexClass> interfaces, ImmediateAppSubtypingInfo subtypingInfo, Timing timing) {
// Phase 1: Reserve all the names that need to be kept and allocate linked state in the
// library part.
timing.begin("Phase 1");
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 23f9f8d..c499d23 100644
--- a/src/main/java/com/android/tools/r8/naming/Minifier.java
+++ b/src/main/java/com/android/tools/r8/naming/Minifier.java
@@ -21,12 +21,12 @@
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ImmediateAppSubtypingInfo;
import com.android.tools.r8.graph.MethodResolutionResult;
import com.android.tools.r8.graph.ProgramField;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.ReferencedMembersCollector;
import com.android.tools.r8.graph.ReferencedMembersCollector.ReferencedMembersConsumer;
-import com.android.tools.r8.graph.SubtypingInfo;
import com.android.tools.r8.naming.ClassNameMinifier.ClassNamingStrategy;
import com.android.tools.r8.naming.ClassNameMinifier.ClassRenaming;
import com.android.tools.r8.naming.FieldNameMinifier.FieldRenaming;
@@ -57,9 +57,10 @@
public void run(ExecutorService executorService, Timing timing) throws ExecutionException {
assert appView.options().isMinifying();
- SubtypingInfo subtypingInfo = MinifierUtils.createSubtypingInfo(appView);
+ ImmediateAppSubtypingInfo immediateSubtypingInfo = ImmediateAppSubtypingInfo.create(appView);
timing.begin("ComputeInterfaces");
- List<DexClass> interfaces = subtypingInfo.computeReachableInterfacesWithDeterministicOrder();
+ List<DexClass> interfaces =
+ immediateSubtypingInfo.computeReachableInterfacesWithDeterministicOrder();
timing.end();
timing.begin("MinifyClasses");
ClassNameMinifier classNameMinifier =
@@ -81,7 +82,7 @@
timing.begin("MinifyMethods");
MethodRenaming methodRenaming =
new MethodNameMinifier(appView, minifyMembers)
- .computeRenaming(interfaces, subtypingInfo, timing);
+ .computeRenaming(interfaces, immediateSubtypingInfo, timing);
timing.end();
assert new MinifiedRenaming(appView, classRenaming, methodRenaming, FieldRenaming.empty())
@@ -89,7 +90,7 @@
timing.begin("MinifyFields");
FieldRenaming fieldRenaming =
- new FieldNameMinifier(appView, subtypingInfo, minifyMembers)
+ new FieldNameMinifier(appView, immediateSubtypingInfo, minifyMembers)
.computeRenaming(interfaces, timing);
timing.end();
diff --git a/src/main/java/com/android/tools/r8/naming/MinifierUtils.java b/src/main/java/com/android/tools/r8/naming/MinifierUtils.java
deleted file mode 100644
index e259a67..0000000
--- a/src/main/java/com/android/tools/r8/naming/MinifierUtils.java
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-package com.android.tools.r8.naming;
-
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.SubtypingInfo;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.android.tools.r8.utils.SetUtils;
-import java.util.Set;
-
-public class MinifierUtils {
-
- public static SubtypingInfo createSubtypingInfo(AppView<AppInfoWithLiveness> appView) {
- Set<DexClass> classesToBuildSubtypeInformationFor =
- SetUtils.newIdentityHashSet(appView.app().classes());
- appView
- .appInfo()
- .getObjectAllocationInfoCollection()
- .forEachInstantiatedLambdaInterfaces(
- type -> {
- DexClass lambdaInterface = appView.contextIndependentDefinitionFor(type);
- if (lambdaInterface != null) {
- classesToBuildSubtypeInformationFor.add(lambdaInterface);
- }
- });
- appView.appInfo().forEachReferencedClasspathClass(classesToBuildSubtypeInformationFor::add);
- return SubtypingInfo.create(classesToBuildSubtypeInformationFor, appView);
- }
-}
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 aae09f7..78baeb5 100644
--- a/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java
@@ -27,9 +27,9 @@
import com.android.tools.r8.graph.DexReference;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ImmediateAppSubtypingInfo;
import com.android.tools.r8.graph.ProgramField;
import com.android.tools.r8.graph.ProgramOrClasspathClass;
-import com.android.tools.r8.graph.SubtypingInfo;
import com.android.tools.r8.naming.ClassNameMinifier.ClassRenaming;
import com.android.tools.r8.naming.FieldNameMinifier.FieldRenaming;
import com.android.tools.r8.naming.MemberNaming.FieldSignature;
@@ -98,23 +98,20 @@
public NamingLens run(ExecutorService executorService, Timing timing) throws ExecutionException {
ArrayDeque<Map<DexReference, MemberNaming>> nonPrivateMembers = new ArrayDeque<>();
Set<DexReference> notMappedReferences = new HashSet<>();
- SubtypingInfo subtypingInfo = MinifierUtils.createSubtypingInfo(appView);
+ ImmediateAppSubtypingInfo subtypingInfo = ImmediateAppSubtypingInfo.create(appView);
timing.begin("MappingInterfaces");
List<DexClass> interfaces = subtypingInfo.computeReachableInterfacesWithDeterministicOrder();
interfaces.forEach(
- iface ->
- computeMapping(iface.getType(), nonPrivateMembers, notMappedReferences, subtypingInfo));
+ iface -> computeMapping(iface, nonPrivateMembers, notMappedReferences, subtypingInfo));
timing.end();
timing.begin("MappingClasses");
mappedClasses.addAll(appView.appInfo().classes());
- subtypingInfo.forAllImmediateExtendsSubtypes(
- factory.objectType,
- subType -> {
- DexClass dexClass = appView.definitionFor(subType);
- if (dexClass != null && !dexClass.isInterface()) {
- computeMapping(subType, nonPrivateMembers, notMappedReferences, subtypingInfo);
- }
- });
+ DexClass objectClass = appView.definitionFor(factory.objectType);
+ for (DexClass subclass : subtypingInfo.getSubclasses(objectClass)) {
+ if (!subclass.isInterface()) {
+ computeMapping(subclass, nonPrivateMembers, notMappedReferences, subtypingInfo);
+ }
+ }
assert nonPrivateMembers.isEmpty();
timing.end();
@@ -167,21 +164,21 @@
}
private void computeMapping(
- DexType type,
+ DexClass clazz,
Deque<Map<DexReference, MemberNaming>> buildUpNames,
Set<DexReference> notMappedReferences,
- SubtypingInfo subtypingInfo) {
+ ImmediateAppSubtypingInfo subtypingInfo) {
+ DexType type = clazz.getType();
ClassNamingForMapApplier classNaming = seedMapper.getClassNaming(type);
- DexClass clazz = appView.definitionFor(type);
// Keep track of classpath classes that needs to get renamed.
- if (clazz != null && clazz.isClasspathClass() && classNaming != null) {
+ if (clazz.isClasspathClass() && classNaming != null) {
mappedClasses.add(clazz.asClasspathClass());
}
Map<DexReference, MemberNaming> nonPrivateMembers = new IdentityHashMap<>();
- if (classNaming != null && (clazz == null || !clazz.isLibraryClass())) {
+ if (classNaming != null && !clazz.isLibraryClass()) {
DexString mappedName = factory.createString(classNaming.renamedName);
checkAndAddMappedNames(type, mappedName, classNaming.position);
classNaming.forAllMemberNaming(
@@ -204,7 +201,7 @@
if (!memberNames.containsKey(parentReferenceOnCurrentType)) {
addMemberNaming(
parentReferenceOnCurrentType, parentMembers.get(key), additionalMethodNamings);
- } else if (clazz != null) {
+ } else {
DexEncodedMethod method = clazz.lookupMethod(parentReferenceOnCurrentType);
assert method == null
|| method.isStatic()
@@ -227,25 +224,25 @@
}
}
- if (clazz != null) {
- // If a class is marked as abstract it is allowed to not implement methods from interfaces
- // thus the map will not contain a mapping. Also, if an interface is defined in the library
- // and the class is in the program, we have to build up the correct names to reserve them.
- if (clazz.isProgramClass() || clazz.isAbstract()) {
- addNonPrivateInterfaceMappings(type, nonPrivateMembers, clazz.interfaces.values);
- }
+ // If a class is marked as abstract it is allowed to not implement methods from interfaces
+ // thus the map will not contain a mapping. Also, if an interface is defined in the library
+ // and the class is in the program, we have to build up the correct names to reserve them.
+ if (clazz.isProgramClass() || clazz.isAbstract()) {
+ addNonPrivateInterfaceMappings(type, nonPrivateMembers, clazz.interfaces.values);
}
- if (nonPrivateMembers.size() > 0) {
+ if (!nonPrivateMembers.isEmpty()) {
buildUpNames.addLast(nonPrivateMembers);
- subtypingInfo.forAllImmediateExtendsSubtypes(
- type,
- subType -> computeMapping(subType, buildUpNames, notMappedReferences, subtypingInfo));
+ subtypingInfo.forEachImmediateSubClassMatching(
+ clazz,
+ subclass -> clazz.isInterface() == subclass.isInterface(),
+ subclass -> computeMapping(subclass, buildUpNames, notMappedReferences, subtypingInfo));
buildUpNames.removeLast();
} else {
- subtypingInfo.forAllImmediateExtendsSubtypes(
- type,
- subType -> computeMapping(subType, buildUpNames, notMappedReferences, subtypingInfo));
+ subtypingInfo.forEachImmediateSubClassMatching(
+ clazz,
+ subclass -> clazz.isInterface() == subclass.isInterface(),
+ subclass -> computeMapping(subclass, buildUpNames, notMappedReferences, subtypingInfo));
}
}
diff --git a/src/test/java/com/android/tools/r8/internal/R8GMSCoreLookupTest.java b/src/test/java/com/android/tools/r8/internal/R8GMSCoreLookupTest.java
deleted file mode 100644
index 3b676f9..0000000
--- a/src/test/java/com/android/tools/r8/internal/R8GMSCoreLookupTest.java
+++ /dev/null
@@ -1,148 +0,0 @@
-// Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-package com.android.tools.r8.internal;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import com.android.tools.r8.StringResource;
-import com.android.tools.r8.TestBase;
-import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.dex.ApplicationReader;
-import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
-import com.android.tools.r8.graph.AppServices;
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.DirectMappedDexApplication;
-import com.android.tools.r8.graph.LookupResult;
-import com.android.tools.r8.graph.LookupResult.LookupResultSuccess;
-import com.android.tools.r8.graph.MethodResolutionResult;
-import com.android.tools.r8.graph.SubtypingInfo;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.android.tools.r8.utils.AndroidApp;
-import com.android.tools.r8.utils.InternalOptions;
-import com.android.tools.r8.utils.timing.Timing;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-
-public class R8GMSCoreLookupTest extends TestBase {
-
- private static final String APP_DIR = "third_party/gmscore/v5/";
- private DirectMappedDexApplication program;
- private AppView<? extends AppInfoWithClassHierarchy> appView;
- private SubtypingInfo subtypingInfo;
-
- @Before
- public void readGMSCore() throws Exception {
- Path directory = Paths.get(APP_DIR);
- AndroidApp app = ToolHelper.builderFromProgramDirectory(directory).build();
- Path mapFile = directory.resolve(ToolHelper.DEFAULT_PROGUARD_MAP_FILE);
- StringResource proguardMap = null;
- if (Files.exists(mapFile)) {
- proguardMap = StringResource.fromFile(mapFile);
- }
- ExecutorService executorService = Executors.newSingleThreadExecutor();
- Timing timing = Timing.empty();
- program =
- new ApplicationReader(app, new InternalOptions(), timing)
- .read(proguardMap, executorService)
- .toDirect();
- appView = AppView.createForR8(program);
- appView.setAppServices(AppServices.builder(appView).build());
- subtypingInfo = SubtypingInfo.create(appView);
- }
-
- private AppInfoWithClassHierarchy appInfo() {
- return appView.appInfo();
- }
-
- private void testVirtualLookup(DexProgramClass clazz, DexEncodedMethod method) {
- // Check lookup will produce the same result.
- DexMethod id = method.getReference();
- assertEquals(
- appInfo().resolveMethodOnClassLegacy(id.holder, method.getReference()).getSingleTarget(),
- method);
-
- // Check lookup targets with include method.
- MethodResolutionResult resolutionResult =
- appInfo().resolveMethodOnClassLegacy(clazz, method.getReference());
- AppInfoWithLiveness appInfo = null; // TODO(b/154881041): Remove or compute liveness.
- LookupResult lookupResult =
- resolutionResult.lookupVirtualDispatchTargets(
- clazz, appView, appInfo, dexReference -> false);
- assertTrue(lookupResult.isLookupResultSuccess());
- assertTrue(lookupResult.asLookupResultSuccess().contains(method));
- }
-
- private static class Counter {
- int count = 0;
-
- void inc() {
- count++;
- }
- }
-
- private void testInterfaceLookup(DexProgramClass clazz, DexEncodedMethod method) {
- AppInfoWithLiveness appInfo = null; // TODO(b/154881041): Remove or compute liveness.
- LookupResultSuccess lookupResult =
- appInfo()
- .resolveMethodOnInterfaceLegacy(clazz, method.getReference())
- .lookupVirtualDispatchTargets(clazz, appView, appInfo, dexReference -> false)
- .asLookupResultSuccess();
- assertNotNull(lookupResult);
- assertFalse(lookupResult.hasLambdaTargets());
- if (subtypingInfo.subtypes(method.getHolderType()).stream()
- .allMatch(t -> appInfo().definitionFor(t).isInterface())) {
- Counter counter = new Counter();
- lookupResult.forEach(
- target -> {
- DexEncodedMethod m = target.getDefinition();
- if (m.accessFlags.isAbstract() || !m.accessFlags.isBridge()) {
- counter.inc();
- }
- },
- l -> fail());
- assertEquals(0, counter.count);
- } else {
- Counter counter = new Counter();
- lookupResult.forEach(
- target -> {
- if (target.getDefinition().isAbstract()) {
- counter.inc();
- }
- },
- lambda -> fail());
- assertEquals(0, counter.count);
- }
- }
-
- private void testLookup(DexProgramClass clazz) {
- if (clazz.isInterface()) {
- for (DexEncodedMethod method : clazz.virtualMethods()) {
- testInterfaceLookup(clazz, method);
- }
- } else {
- for (DexEncodedMethod method : clazz.virtualMethods()) {
- testVirtualLookup(clazz, method);
- }
- }
- }
-
- @Test
- @Ignore("b/154881041: Does this test add value? If so it needs to compute a liveness app-info")
- public void testLookup() {
- program.classesWithDeterministicOrder().forEach(this::testLookup);
- }
-}
diff --git a/src/test/java/com/android/tools/r8/shaking/R8Shaking2LookupTest.java b/src/test/java/com/android/tools/r8/shaking/R8Shaking2LookupTest.java
index ef19e65..8e6c718 100644
--- a/src/test/java/com/android/tools/r8/shaking/R8Shaking2LookupTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/R8Shaking2LookupTest.java
@@ -5,63 +5,76 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DirectMappedDexApplication;
-import com.android.tools.r8.graph.SubtypingInfo;
+import com.android.tools.r8.graph.ImmediateAppSubtypingInfo;
import com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
-public class R8Shaking2LookupTest {
+@RunWith(Parameterized.class)
+public class R8Shaking2LookupTest extends TestBase {
- private DirectMappedDexApplication program;
private DexItemFactory dexItemFactory;
private AppInfoWithClassHierarchy appInfo;
- private SubtypingInfo subtypingInfo;
+ private ImmediateAppSubtypingInfo subtypingInfo;
+
+ @Parameter(0)
+ public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withNoneRuntime().build();
+ }
@Before
public void readApp() throws IOException, ExecutionException {
- program =
+ DirectMappedDexApplication program =
ToolHelper.buildApplication(
ImmutableList.of(ToolHelper.EXAMPLES_BUILD_DIR + "shaking2.jar"));
dexItemFactory = program.dexItemFactory;
AppView<AppInfoWithClassHierarchy> appView = AppView.createForR8(program);
appInfo = appView.appInfo();
- subtypingInfo = SubtypingInfo.create(appView);
+ subtypingInfo = ImmediateAppSubtypingInfo.create(appView);
}
- private void validateSubtype(DexType super_type, DexType sub_type) {
- assertFalse(super_type.equals(sub_type));
- assertTrue(subtypingInfo.subtypes(super_type).contains(sub_type));
+ private void validateSubtype(DexClass super_type, DexClass sub_type) {
+ assertNotEquals(super_type, sub_type);
+ assertTrue(subtypingInfo.getTransitiveProgramSubclasses(super_type).contains(sub_type));
assertTrue(appInfo.isSubtype(sub_type, super_type));
- assertFalse(subtypingInfo.subtypes(sub_type).contains(super_type));
+ assertFalse(subtypingInfo.getTransitiveProgramSubclasses(sub_type).contains(super_type));
assertFalse(appInfo.isSubtype(super_type, sub_type));
}
- private void validateSubtypeSize(DexType type, int size) {
- assertEquals(size, subtypingInfo.subtypes(type).size());
+ private void validateSubtypeSize(DexClass type, int size) {
+ assertEquals(size, subtypingInfo.getTransitiveProgramSubclasses(type).size());
}
@Test
public void testLookup() {
- DexType object_type = dexItemFactory.createType("Ljava/lang/Object;");
-
- DexType interface_type = dexItemFactory.createType("Lshaking2/Interface;");
- DexType superInterface1_type = dexItemFactory.createType("Lshaking2/SuperInterface1;");
- DexType superInterface2_type = dexItemFactory.createType("Lshaking2/SuperInterface2;");
-
- DexType superclass_type = dexItemFactory.createType("Lshaking2/SuperClass;");
- DexType subClass1_type = dexItemFactory.createType("Lshaking2/SubClass1;");
- DexType subClass2_type = dexItemFactory.createType("Lshaking2/SubClass2;");
-
+ DexClass object_type = definitionFor("Ljava/lang/Object;");
+ DexClass interface_type = definitionFor("Lshaking2/Interface;");
+ DexClass superInterface1_type = definitionFor("Lshaking2/SuperInterface1;");
+ DexClass superInterface2_type = definitionFor("Lshaking2/SuperInterface2;");
+ DexClass superclass_type = definitionFor("Lshaking2/SuperClass;");
+ DexClass subClass1_type = definitionFor("Lshaking2/SubClass1;");
+ DexClass subClass2_type = definitionFor("Lshaking2/SubClass2;");
validateSubtype(object_type, interface_type);
validateSubtypeSize(interface_type, 4);
validateSubtype(interface_type, superclass_type);
@@ -72,4 +85,8 @@
validateSubtype(superInterface2_type, interface_type);
validateSubtypeSize(subClass2_type, 0);
}
+
+ private DexClass definitionFor(String descriptor) {
+ return appInfo.definitionFor(dexItemFactory.createType(descriptor));
+ }
}