Simplify and optimize relevant candidates for if rule

Change-Id: Ic1c007cbe51c2f4cf5a6c7ea7381be306c8eadda
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 7313380..a7f48e7 100644
--- a/src/main/java/com/android/tools/r8/graph/ImmediateSubtypingInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/ImmediateSubtypingInfo.java
@@ -11,14 +11,12 @@
 import com.android.tools.r8.utils.WorkList;
 import com.google.common.base.Predicates;
 import com.google.common.collect.Iterables;
-import com.google.common.collect.Sets;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.IdentityHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
-import java.util.Set;
 import java.util.function.BiConsumer;
 import java.util.function.BiPredicate;
 import java.util.function.Consumer;
@@ -64,11 +62,6 @@
         (supertype, superclass) -> consumer.accept(superclass));
   }
 
-  public void forEachImmediateSuperClass(
-      DexClass clazz, BiConsumer<? super DexType, ? super DexClass> consumer) {
-    forEachImmediateSuperClassMatching(clazz, (supertype, superclass) -> true, consumer);
-  }
-
   public void forEachImmediateSuperClassMatching(
       DexClass clazz,
       BiPredicate<? super DexType, ? super DexClass> predicate,
@@ -175,21 +168,6 @@
         Objects::nonNull);
   }
 
-  public Set<DexProgramClass> getTransitiveProgramSubclasses(S clazz) {
-    return getTransitiveProgramSubclassesMatching(clazz, Predicates.alwaysTrue());
-  }
-
-  public Set<DexProgramClass> getTransitiveProgramSubclassesMatching(
-      S clazz, Predicate<DexProgramClass> predicate) {
-    Set<DexProgramClass> classes = Sets.newIdentityHashSet();
-    forEachTransitiveProgramSubclassMatching(clazz, predicate, classes::add);
-    return classes;
-  }
-
-  public boolean hasSubclasses(S clazz) {
-    return !getSubclasses(clazz).isEmpty();
-  }
-
   public <TB, TC> TraversalContinuation<TB, TC> traverseTransitiveSubclasses(
       S clazz, Function<? super DexClass, TraversalContinuation<TB, TC>> fn) {
     TraversalContinuation<TB, TC> traversalContinuation = TraversalContinuation.doContinue();
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 d08d948..b79bd90 100644
--- a/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluator.java
+++ b/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluator.java
@@ -33,6 +33,7 @@
 import java.util.Set;
 import java.util.concurrent.ExecutionException;
 import java.util.function.BiPredicate;
+import java.util.function.Consumer;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
 
@@ -72,13 +73,16 @@
           // Depending on which types that trigger the -if rule, the application of the subsequent
           // -keep rule may vary (due to back references). So, we need to try all pairs of -if
           // rule and live types.
-          for (DexClass clazz :
-              getRelevantCandidatesForRule(
-                  ifRuleKey, classKind, classesWithNewlyLiveMembers, isEffectivelyLive)) {
-            assert !clazz.isProgramClass() || isEffectivelyLive.test(clazz.asProgramClass());
-            processActiveIfRulesWithMembersAndSameClassPrecondition(
-                ifRuleKey, ifRulesInEquivalence, clazz, toRemove);
-          }
+          forEachRelevantCandidate(
+              ifRuleKey,
+              classKind,
+              classesWithNewlyLiveMembers,
+              isEffectivelyLive,
+              clazz -> {
+                assert !clazz.isProgramClass() || isEffectivelyLive.test(clazz.asProgramClass());
+                processActiveIfRulesWithMembersAndSameClassPrecondition(
+                    ifRuleKey, ifRulesInEquivalence, clazz, toRemove);
+              });
           if (ifRulesInEquivalence.size() == toRemove.size()) {
             return true;
           }
@@ -89,19 +93,22 @@
   }
 
   @SuppressWarnings("unchecked")
-  Iterable<? extends DexClass> getRelevantCandidatesForRule(
+  void forEachRelevantCandidate(
       ProguardIfRule ifRule,
       ClassKind<?> classKind,
       Iterable<? extends DexClass> classesWithNewlyLiveMembers,
-      Predicate<DexProgramClass> isEffectivelyLive) {
+      Predicate<DexProgramClass> isEffectivelyLive,
+      Consumer<DexClass> consumer) {
     if (classKind == ClassKind.PROGRAM) {
-      return ifRule.relevantCandidatesForRule(
+      ifRule.forEachRelevantCandidate(
           appView,
           enqueuer.getSubtypingInfo(),
           (Iterable<DexProgramClass>) classesWithNewlyLiveMembers,
-          isEffectivelyLive);
+          isEffectivelyLive,
+          consumer);
+    } else {
+      classesWithNewlyLiveMembers.forEach(consumer);
     }
-    return classesWithNewlyLiveMembers;
   }
 
   private void processActiveIfRulesWithMembersAndSameClassPrecondition(
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 bfd3024..2adc592 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationRule.java
@@ -6,13 +6,9 @@
 import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
 import static com.google.common.base.Predicates.alwaysTrue;
 
-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;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.ImmediateAppSubtypingInfo;
@@ -23,9 +19,9 @@
 import com.android.tools.r8.utils.IterableUtils;
 import com.android.tools.r8.utils.StringUtils;
 import com.google.common.collect.Iterables;
-import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
+import java.util.function.Consumer;
 import java.util.function.Predicate;
 
 public abstract class ProguardConfigurationRule extends ProguardClassSpecification {
@@ -150,63 +146,41 @@
     this.canReferenceDeadTypes = true;
   }
 
-  Iterable<DexProgramClass> relevantCandidatesForRule(
+  void forEachRelevantCandidate(
       AppView<? extends AppInfoWithClassHierarchy> appView,
       ImmediateAppSubtypingInfo subtypingInfo,
       Iterable<DexProgramClass> defaultValue,
-      Predicate<DexProgramClass> isRelevant) {
-    Iterable<DexType> specificTypes;
+      Predicate<DexProgramClass> isRelevant,
+      Consumer<DexClass> consumer) {
     if (getClassNames().hasSpecificTypes()) {
-      specificTypes = getClassNames().getSpecificTypes();
+      for (DexType type : getClassNames().getSpecificTypes()) {
+        DexProgramClass clazz =
+            asProgramClassOrNull(
+                canReferenceDeadTypes
+                    ? appView.appInfo().definitionForWithoutExistenceAssert(type)
+                    : appView.definitionFor(type));
+        if (clazz != null && isRelevant.test(clazz)) {
+          consumer.accept(clazz);
+        }
+      }
     } else if (hasInheritanceClassName() && getInheritanceClassName().hasSpecificType()) {
       DexType type = getInheritanceClassName().getSpecificType();
       DexClass clazz = appView.definitionFor(type);
-      if (clazz == null) {
-        return Collections.emptyList();
-      }
-      Iterable<DexProgramClass> relevantSubclasses =
-          subtypingInfo.getTransitiveProgramSubclassesMatching(clazz, isRelevant);
-      if (appView.getVerticallyMergedClasses() != null
-          && appView.getVerticallyMergedClasses().hasBeenMergedIntoSubtype(type)) {
-        DexType targetType = appView.getVerticallyMergedClasses().getTargetFor(type);
-        DexProgramClass targetClass = asProgramClassOrNull(appView.definitionFor(targetType));
-        assert targetClass != null;
-        if (isRelevant.test(targetClass)) {
-          return IterableUtils.append(relevantSubclasses, targetClass);
+      if (clazz != null) {
+        subtypingInfo.forEachTransitiveProgramSubclassMatching(clazz, isRelevant, consumer);
+        if (appView.getVerticallyMergedClasses() != null
+            && appView.getVerticallyMergedClasses().hasBeenMergedIntoSubtype(type)) {
+          DexType targetType = appView.getVerticallyMergedClasses().getTargetFor(type);
+          DexProgramClass targetClass = asProgramClassOrNull(appView.definitionFor(targetType));
+          assert targetClass != null;
+          if (isRelevant.test(targetClass)) {
+            consumer.accept(targetClass);
+          }
         }
       }
-      return relevantSubclasses;
     } else {
-      return defaultValue;
+      defaultValue.forEach(consumer);
     }
-    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 acc89d1..6eec044 100644
--- a/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
+++ b/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
@@ -442,11 +442,12 @@
 
       tasks.submit(
           () -> {
-            for (DexProgramClass clazz :
-                rule.relevantCandidatesForRule(
-                    appView, subtypingInfo, application.classes(), alwaysTrue())) {
-              process(clazz, rule, ifRulePreconditionMatch);
-            }
+            rule.forEachRelevantCandidate(
+                appView,
+                subtypingInfo,
+                application.classes(),
+                alwaysTrue(),
+                clazz -> process(clazz, rule, ifRulePreconditionMatch));
             if (rule.applyToNonProgramClasses()) {
               for (DexLibraryClass clazz : application.libraryClasses()) {
                 process(clazz, rule, ifRulePreconditionMatch);