Only re-evaluate if rules with members on classes with newly live members
Bug: b/206086945
Change-Id: If93573d950c6855f9bd78b8b29173f08715137a9
diff --git a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
index e890a6a..c9ca7e4 100644
--- a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
@@ -838,7 +838,7 @@
public static Iterable<DexProgramClass> asProgramClasses(
Iterable<DexType> types, DexDefinitionSupplier definitions) {
return () ->
- new Iterator<DexProgramClass>() {
+ new Iterator<>() {
private final Iterator<DexType> iterator = types.iterator();
diff --git a/src/main/java/com/android/tools/r8/graph/GenericSignatureEnqueuerAnalysis.java b/src/main/java/com/android/tools/r8/graph/GenericSignatureEnqueuerAnalysis.java
index 2599a50..ed13c75 100644
--- a/src/main/java/com/android/tools/r8/graph/GenericSignatureEnqueuerAnalysis.java
+++ b/src/main/java/com/android/tools/r8/graph/GenericSignatureEnqueuerAnalysis.java
@@ -37,7 +37,7 @@
}
@Override
- public void notifyMarkMethodAsTargeted(ProgramMethod method, EnqueuerWorklist worklist) {
+ public void processNewlyTargetedMethod(ProgramMethod method, EnqueuerWorklist worklist) {
processSignature(method, method.getContext());
}
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java
index b1ca241..f16a2d8 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java
@@ -61,7 +61,7 @@
}
@Override
- public void notifyMarkMethodAsTargeted(ProgramMethod method, EnqueuerWorklist worklist) {
+ public void processNewlyTargetedMethod(ProgramMethod method, EnqueuerWorklist worklist) {
computeAndSetApiLevelForDefinition(method);
}
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerAnalysis.java
index 791b3b4..8fd3ed4 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerAnalysis.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerAnalysis.java
@@ -31,6 +31,8 @@
public void processNewlyLiveField(
ProgramField field, ProgramDefinition context, EnqueuerWorklist worklist) {}
+ public void processNewlyReferencedField(ProgramField field) {}
+
/** Called when a method is found to be live. */
public void processNewlyLiveMethod(
ProgramMethod method,
@@ -45,7 +47,7 @@
public void processTracedCode(
ProgramMethod method, DefaultEnqueuerUseRegistry registry, EnqueuerWorklist worklist) {}
- public void notifyMarkMethodAsTargeted(ProgramMethod method, EnqueuerWorklist worklist) {}
+ public void processNewlyTargetedMethod(ProgramMethod method, EnqueuerWorklist worklist) {}
public void notifyMarkFieldAsReachable(ProgramField field, EnqueuerWorklist worklist) {}
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index 022157e..96be3c1 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -1180,7 +1180,7 @@
}
}
- private FieldAccessInfoImpl getOrCreateFieldAccessInfo(DexEncodedField field) {
+ private FieldAccessInfoImpl getOrCreateFieldAccessInfo(DexClassAndField field) {
// Check if we have previously created a FieldAccessInfo object for the field definition.
FieldAccessInfoImpl info = fieldAccessInfoCollection.get(field.getReference());
@@ -1188,6 +1188,12 @@
if (info == null) {
info = new FieldAccessInfoImpl(field.getReference());
fieldAccessInfoCollection.extend(field.getReference(), info);
+
+ // Notify analyses.
+ if (field.isProgramField()) {
+ ProgramField programField = field.asProgramField();
+ analyses.forEach(analysis -> analysis.processNewlyReferencedField(programField));
+ }
}
return info;
@@ -1215,12 +1221,12 @@
return true;
}
- DexEncodedField encodedField = seenResult.get().getDefinition();
- info = getOrCreateFieldAccessInfo(encodedField);
+ DexClassAndField resolvedField = seenResult.get();
+ info = getOrCreateFieldAccessInfo(resolvedField);
// If `field` is an indirect reference, then create a mapping for it, such that we don't have
// to resolve the field the next time we see the reference.
- if (field != encodedField.getReference()) {
+ if (field != resolvedField.getReference()) {
fieldAccessInfoCollection.extend(field, info);
}
} else if (info == MISSING_FIELD_ACCESS_INFO) {
@@ -4965,7 +4971,7 @@
// Package protected due to entry point from worklist.
void markFieldAsKept(ProgramField field, KeepReason reason) {
- FieldAccessInfoImpl fieldAccessInfo = getOrCreateFieldAccessInfo(field.getDefinition());
+ FieldAccessInfoImpl fieldAccessInfo = getOrCreateFieldAccessInfo(field);
fieldAccessInfo.setHasReflectiveRead();
fieldAccessInfo.setHasReflectiveWrite();
@@ -5084,7 +5090,7 @@
markMethodAsLiveWithCompatRule(method);
}
}
- analyses.forEach(analysis -> analysis.notifyMarkMethodAsTargeted(method, worklist));
+ analyses.forEach(analysis -> analysis.processNewlyTargetedMethod(method, worklist));
}
void traceMethodDefinitionExcludingCode(ProgramMethod method) {
diff --git a/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluator.java b/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluator.java
index c0c05d4..da2ca1d 100644
--- a/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluator.java
+++ b/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluator.java
@@ -29,6 +29,7 @@
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.function.Consumer;
+import java.util.function.Predicate;
import java.util.stream.Collectors;
public class IfRuleEvaluator {
@@ -55,7 +56,8 @@
public void processActiveIfRulesWithMembers(
Map<Wrapper<ProguardIfRule>, Set<ProguardIfRule>> ifRules,
- Set<DexProgramClass> effectivelyFakeLiveClasses)
+ Iterable<DexProgramClass> classesWithNewlyLiveMembers,
+ Predicate<DexProgramClass> isEffectivelyLive)
throws ExecutionException {
MapUtils.removeIf(
ifRules,
@@ -68,10 +70,8 @@
// rule and live types.
for (DexProgramClass clazz :
ifRuleKey.relevantCandidatesForRule(
- appView, subtypingInfo, appView.appInfo().classes())) {
- if (!isEffectivelyLive(clazz, effectivelyFakeLiveClasses)) {
- continue;
- }
+ appView, subtypingInfo, classesWithNewlyLiveMembers, isEffectivelyLive)) {
+ assert isEffectivelyLive.test(clazz);
evaluateRuleOnEffectivelyLiveClass(
ifRuleKey,
ifRulesInEquivalence,
@@ -117,11 +117,6 @@
tasks.await();
}
- private boolean isEffectivelyLive(
- DexProgramClass clazz, Set<DexProgramClass> effectivelyFakeLiveClasses) {
- return enqueuer.isTypeLive(clazz) || effectivelyFakeLiveClasses.contains(clazz);
- }
-
private void evaluateRuleOnEffectivelyLiveClass(
ProguardIfRule ifRuleKey,
Set<ProguardIfRule> ifRulesInEquivalence,
diff --git a/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluatorFactory.java b/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluatorFactory.java
index cc813e2..9fe386a 100644
--- a/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluatorFactory.java
+++ b/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluatorFactory.java
@@ -10,6 +10,9 @@
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.ProgramDefinition;
+import com.android.tools.r8.graph.ProgramField;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.SubtypingInfo;
import com.android.tools.r8.graph.analysis.EnqueuerAnalysis;
import com.android.tools.r8.shaking.RootSetUtils.ConsequentRootSet;
@@ -38,9 +41,9 @@
private final Set<DexProgramClass> effectivelyFakeLiveClasses;
private final Set<DexProgramClass> newlyLiveClasses = Sets.newIdentityHashSet();
+ private final Set<DexProgramClass> classesWithNewlyLiveMembers = Sets.newIdentityHashSet();
private boolean seenFixpoint;
- private long previousNumberOfLiveItems = 0;
private final TaskCollection<?> tasks;
@@ -119,7 +122,7 @@
Enqueuer enqueuer, EnqueuerWorklist worklist, ExecutorService executorService, Timing timing)
throws ExecutionException {
boolean isFirstFixpoint = setSeenFixpoint();
- if (!shouldProcessActiveIfRulesWithMembers(enqueuer)
+ if (!shouldProcessActiveIfRulesWithMembers(isFirstFixpoint)
&& !shouldProcessActiveIfRulesWithoutMembers(isFirstFixpoint)) {
return;
}
@@ -129,14 +132,17 @@
"Find consequent items for -if rules...",
() -> processActiveIfRules(enqueuer, isFirstFixpoint));
enqueuer.addConsequentRootSet(consequentRootSet);
- long numberOfLiveItemsAtEnd = enqueuer.getNumberOfLiveItems();
- assert numberOfLiveItemsAtEnd == numberOfLiveItemsAtStart;
- previousNumberOfLiveItems = numberOfLiveItemsAtEnd;
+ assert enqueuer.getNumberOfLiveItems() == numberOfLiveItemsAtStart;
}
- private boolean shouldProcessActiveIfRulesWithMembers(Enqueuer enqueuer) {
- return !activeIfRulesWithMembers.isEmpty()
- && enqueuer.getNumberOfLiveItems() > previousNumberOfLiveItems;
+ private boolean shouldProcessActiveIfRulesWithMembers(boolean isFirstFixpoint) {
+ if (activeIfRulesWithMembers.isEmpty()) {
+ return false;
+ }
+ if (isFirstFixpoint && !effectivelyFakeLiveClasses.isEmpty()) {
+ return true;
+ }
+ return !classesWithNewlyLiveMembers.isEmpty();
}
private ConsequentRootSet processActiveIfRules(Enqueuer enqueuer, boolean isFirstFixpoint)
@@ -146,8 +152,8 @@
ConsequentRootSet.builder(appView, enqueuer, subtypingInfo);
IfRuleEvaluator evaluator =
new IfRuleEvaluator(appView, subtypingInfo, enqueuer, consequentRootSetBuilder, tasks);
- if (shouldProcessActiveIfRulesWithMembers(enqueuer)) {
- processActiveIfRulesWithMembers(evaluator);
+ if (shouldProcessActiveIfRulesWithMembers(isFirstFixpoint)) {
+ processActiveIfRulesWithMembers(evaluator, isFirstFixpoint);
}
if (shouldProcessActiveIfRulesWithoutMembers(isFirstFixpoint)) {
processActiveIfRulesWithoutMembers(evaluator, isFirstFixpoint);
@@ -155,9 +161,22 @@
return consequentRootSetBuilder.buildConsequentRootSet();
}
- private void processActiveIfRulesWithMembers(IfRuleEvaluator evaluator)
+ private void processActiveIfRulesWithMembers(IfRuleEvaluator evaluator, boolean isFirstFixpoint)
throws ExecutionException {
- evaluator.processActiveIfRulesWithMembers(activeIfRulesWithMembers, effectivelyFakeLiveClasses);
+ if (isFirstFixpoint && !effectivelyFakeLiveClasses.isEmpty()) {
+ evaluator.processActiveIfRulesWithMembers(
+ activeIfRulesWithMembers,
+ Iterables.concat(effectivelyFakeLiveClasses, classesWithNewlyLiveMembers),
+ clazz ->
+ effectivelyFakeLiveClasses.contains(clazz)
+ || classesWithNewlyLiveMembers.contains(clazz));
+ } else {
+ evaluator.processActiveIfRulesWithMembers(
+ activeIfRulesWithMembers,
+ classesWithNewlyLiveMembers,
+ classesWithNewlyLiveMembers::contains);
+ }
+ classesWithNewlyLiveMembers.clear();
}
private boolean shouldProcessActiveIfRulesWithoutMembers(boolean isFirstFixpoint) {
@@ -197,4 +216,36 @@
}
newlyLiveClasses.add(clazz);
}
+
+ @Override
+ public void processNewlyLiveField(
+ ProgramField field, ProgramDefinition context, EnqueuerWorklist worklist) {
+ addClassWithNewlyLiveMembers(field.getHolder());
+ }
+
+ @Override
+ public void processNewlyReferencedField(ProgramField field) {
+ addClassWithNewlyLiveMembers(field.getHolder());
+ }
+
+ @Override
+ public void processNewlyLiveMethod(
+ ProgramMethod method,
+ ProgramDefinition context,
+ Enqueuer enqueuer,
+ EnqueuerWorklist worklist) {
+ addClassWithNewlyLiveMembers(method.getHolder());
+ }
+
+ @Override
+ public void processNewlyTargetedMethod(ProgramMethod method, EnqueuerWorklist worklist) {
+ addClassWithNewlyLiveMembers(method.getHolder());
+ }
+
+ private void addClassWithNewlyLiveMembers(DexProgramClass clazz) {
+ // In the first fixpoint we report all effectively fake live classes as changed.
+ if (seenFixpoint || !effectivelyFakeLiveClasses.contains(clazz)) {
+ classesWithNewlyLiveMembers.add(clazz);
+ }
+ }
}
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardClassNameList.java b/src/main/java/com/android/tools/r8/shaking/ProguardClassNameList.java
index 576588d..25c9cbf 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardClassNameList.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardClassNameList.java
@@ -6,6 +6,7 @@
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.utils.IterableUtils;
+import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.TraversalContinuation;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
@@ -82,7 +83,9 @@
@Override
public abstract int hashCode();
- public abstract List<DexType> asSpecificDexTypes();
+ public abstract boolean hasSpecificTypes();
+
+ public abstract List<DexType> getSpecificTypes();
public abstract boolean matches(DexType type);
@@ -154,7 +157,12 @@
}
@Override
- public List<DexType> asSpecificDexTypes() {
+ public boolean hasSpecificTypes() {
+ return false;
+ }
+
+ @Override
+ public List<DexType> getSpecificTypes() {
return null;
}
@@ -211,9 +219,15 @@
}
@Override
- public List<DexType> asSpecificDexTypes() {
- DexType specific = className.getSpecificType();
- return specific == null ? null : Collections.singletonList(specific);
+ public boolean hasSpecificTypes() {
+ return className.hasSpecificType();
+ }
+
+ @Override
+ public List<DexType> getSpecificTypes() {
+ return className.hasSpecificType()
+ ? Collections.singletonList(className.getSpecificType())
+ : null;
}
@Override
@@ -247,6 +261,8 @@
private final ImmutableList<ProguardTypeMatcher> classNames;
+ private List<DexType> specificTypes;
+
private PositiveClassNameList(Collection<ProguardTypeMatcher> classNames) {
this.classNames = ImmutableList.copyOf(classNames);
}
@@ -287,15 +303,23 @@
}
@Override
- public List<DexType> asSpecificDexTypes() {
- if (classNames.stream().allMatch(k -> k.getSpecificType() != null)) {
- return classNames.stream().map(ProguardTypeMatcher::getSpecificType)
- .collect(Collectors.toList());
- }
- return null;
+ public boolean hasSpecificTypes() {
+ return getSpecificTypes() != null;
}
@Override
+ public List<DexType> getSpecificTypes() {
+ if (specificTypes == null) {
+ specificTypes =
+ classNames.stream().allMatch(ProguardTypeMatcher::hasSpecificType)
+ ? ListUtils.map(classNames, ProguardTypeMatcher::getSpecificType)
+ : Collections.emptyList();
+ }
+ return specificTypes.isEmpty() ? null : specificTypes;
+ }
+
+
+ @Override
public boolean matches(DexType type) {
return Iterables.any(classNames, name -> name.matches(type));
}
@@ -377,7 +401,12 @@
}
@Override
- public List<DexType> asSpecificDexTypes() {
+ public boolean hasSpecificTypes() {
+ return false;
+ }
+
+ @Override
+ public List<DexType> getSpecificTypes() {
return null;
}
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationRule.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationRule.java
index 01c9118..4e80401 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationRule.java
@@ -3,11 +3,12 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.shaking;
+import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
+
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.ClassResolutionResult;
-import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexDefinitionSupplier;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexProgramClass;
@@ -18,11 +19,11 @@
import com.android.tools.r8.utils.BooleanBox;
import com.android.tools.r8.utils.IterableUtils;
import com.android.tools.r8.utils.StringUtils;
-import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
+import java.util.function.Predicate;
public abstract class ProguardConfigurationRule extends ProguardClassSpecification {
@@ -149,47 +150,53 @@
Iterable<DexProgramClass> relevantCandidatesForRule(
AppView<? extends AppInfoWithClassHierarchy> appView,
SubtypingInfo subtypingInfo,
- Iterable<DexProgramClass> defaultValue) {
- List<DexType> specificTypes = getClassNames().asSpecificDexTypes();
- if (specificTypes != null) {
- return DexProgramClass.asProgramClasses(
- specificTypes,
- new DexDefinitionSupplier() {
- @Override
- public ClassResolutionResult contextIndependentDefinitionForWithResolutionResult(
- DexType type) {
- throw new Unreachable("Add support for multiple definitions with rule evaluation");
- }
-
- @Override
- public DexClass definitionFor(DexType type) {
- if (canReferenceDeadTypes) {
- return appView.appInfo().definitionForWithoutExistenceAssert(type);
- }
- return appView.definitionFor(type);
- }
-
- @Override
- public DexItemFactory dexItemFactory() {
- return appView.dexItemFactory();
- }
- });
- }
- if (hasInheritanceClassName() && getInheritanceClassName().hasSpecificType()) {
+ Iterable<DexProgramClass> defaultValue,
+ Predicate<DexProgramClass> isRelevant) {
+ Iterable<DexType> specificTypes;
+ if (getClassNames().hasSpecificTypes()) {
+ specificTypes = getClassNames().getSpecificTypes();
+ } else if (hasInheritanceClassName() && getInheritanceClassName().hasSpecificType()) {
DexType type = getInheritanceClassName().getSpecificType();
if (appView.getVerticallyMergedClasses() != null
&& appView.getVerticallyMergedClasses().hasBeenMergedIntoSubtype(type)) {
DexType target = appView.getVerticallyMergedClasses().getTargetFor(type);
- DexClass clazz = appView.definitionFor(target);
- assert clazz != null && clazz.isProgramClass();
- return Iterables.concat(
- ImmutableList.of(clazz.asProgramClass()),
- DexProgramClass.asProgramClasses(subtypingInfo.subtypes(type), appView));
+ DexProgramClass clazz = asProgramClassOrNull(appView.definitionFor(target));
+ assert clazz != null;
+ specificTypes = IterableUtils.append(subtypingInfo.subtypes(type), clazz.getType());
} else {
- return DexProgramClass.asProgramClasses(subtypingInfo.subtypes(type), appView);
+ specificTypes = subtypingInfo.subtypes(type);
}
+ } else {
+ return defaultValue;
}
- return defaultValue;
+ assert specificTypes != null;
+ return DexProgramClass.asProgramClasses(
+ specificTypes,
+ new DexDefinitionSupplier() {
+ @Override
+ public ClassResolutionResult contextIndependentDefinitionForWithResolutionResult(
+ DexType type) {
+ throw new Unreachable("Add support for multiple definitions with rule evaluation");
+ }
+
+ @Override
+ public DexProgramClass definitionFor(DexType type) {
+ DexProgramClass result =
+ asProgramClassOrNull(
+ canReferenceDeadTypes
+ ? appView.appInfo().definitionForWithoutExistenceAssert(type)
+ : appView.definitionFor(type));
+ if (result != null && isRelevant.test(result)) {
+ return result;
+ }
+ return null;
+ }
+
+ @Override
+ public DexItemFactory dexItemFactory() {
+ return appView.dexItemFactory();
+ }
+ });
}
abstract String typeString();
diff --git a/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java b/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
index 46ef4f1..d2e7a82 100644
--- a/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
+++ b/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
@@ -346,11 +346,10 @@
void runPerRule(TaskCollection<?> tasks, ProguardConfigurationRule rule, ProguardIfRule ifRule)
throws ExecutionException {
- List<DexType> specifics = rule.getClassNames().asSpecificDexTypes();
- if (specifics != null) {
+ if (rule.getClassNames().hasSpecificTypes()) {
// This keep rule only lists specific type matches.
// This means there is no need to iterate over all classes.
- for (DexType type : specifics) {
+ for (DexType type : rule.getClassNames().getSpecificTypes()) {
DexClass clazz = application.definitionFor(type);
// Ignore keep rule iff it does not reference a class in the app.
if (clazz != null) {
@@ -363,7 +362,8 @@
tasks.submit(
() -> {
for (DexProgramClass clazz :
- rule.relevantCandidatesForRule(appView, subtypingInfo, application.classes())) {
+ rule.relevantCandidatesForRule(
+ appView, subtypingInfo, application.classes(), alwaysTrue())) {
process(clazz, rule, ifRule);
}
if (rule.applyToNonProgramClasses()) {
diff --git a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
index 564fd19..9b6bc09 100644
--- a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
@@ -258,7 +258,7 @@
assertEquals(1, rules.size());
assertEquals(ProguardClassType.CLASS, rules.get(0).getClassType());
assertEquals(1, rules.get(0).getClassNames().size());
- List<DexType> classTypes = rules.get(0).getClassNames().asSpecificDexTypes();
+ List<DexType> classTypes = rules.get(0).getClassNames().getSpecificTypes();
assertEquals(1, classTypes.size());
assertSame(dexItemFactory.createType("L-package-/-ClassNameWithDash-;"), classTypes.get(0));
ProguardConfigurationRule rule = rules.get(0);
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/IfSimilarClassSpecificationBundlingTest.java b/src/test/java/com/android/tools/r8/shaking/ifrule/IfSimilarClassSpecificationBundlingTest.java
index 106fffa..4b9155a 100644
--- a/src/test/java/com/android/tools/r8/shaking/ifrule/IfSimilarClassSpecificationBundlingTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/IfSimilarClassSpecificationBundlingTest.java
@@ -92,8 +92,8 @@
public void testBundlingOfIfRulesWithNonConstantSequent()
throws IOException, CompilationFailedException, ExecutionException {
runTest(
- 22,
- 36,
+ 14,
+ 18,
"-if class **$R* { int keepA; }",
"-keep class"
+ " com.android.tools.r8.shaking.ifrule.IfSimilarClassSpecificationBundlingTest$<2> {"