Reland "Collect synthetic inputs in R8"

This reverts commit c225205824ce58503ff38eec05c3b31ade65cfb5.

Change-Id: Ic7c1352a597793307519838ab67806e9f3100cee
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 546fad4..8a4c9cc 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -103,6 +103,7 @@
 import com.android.tools.r8.shaking.VerticalClassMergerGraphLens;
 import com.android.tools.r8.shaking.WhyAreYouKeepingConsumer;
 import com.android.tools.r8.synthesis.SyntheticFinalization;
+import com.android.tools.r8.synthesis.SyntheticItems;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.CfgPrinter;
@@ -291,6 +292,7 @@
 
         appView = AppView.createForR8(application, mainDexInfo);
         appView.setAppServices(AppServices.builder(appView).build());
+        SyntheticItems.collectSyntheticInputs(appView);
       }
 
       // Check for potentially having pass-through of Cf-code for kotlin libraries.
diff --git a/src/main/java/com/android/tools/r8/graph/AppView.java b/src/main/java/com/android/tools/r8/graph/AppView.java
index 7321cc0..1cd36de 100644
--- a/src/main/java/com/android/tools/r8/graph/AppView.java
+++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -558,6 +558,10 @@
     return true;
   }
 
+  public boolean hasClassHierarchy() {
+    return appInfo().hasClassHierarchy();
+  }
+
   @SuppressWarnings("unchecked")
   public AppView<AppInfoWithClassHierarchy> withClassHierarchy() {
     return appInfo.hasClassHierarchy()
@@ -565,6 +569,12 @@
         : null;
   }
 
+  @SuppressWarnings("unchecked")
+  public AppView<AppInfo> withoutClassHierarchy() {
+    assert !hasClassHierarchy();
+    return (AppView<AppInfo>) this;
+  }
+
   public boolean hasLiveness() {
     return appInfo().hasLiveness();
   }
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 86c8ef6..7c2162c 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -2983,7 +2983,8 @@
       ImmutableSet<ProguardKeepRuleBase> keepAllSet =
           ImmutableSet.of(appView.options().getProguardConfiguration().getKeepAllRule());
       for (DexProgramClass clazz : appView.appInfo().classes()) {
-        if (appView.getSyntheticItems().isNonLegacySynthetic(clazz)) {
+        if (appView.getSyntheticItems().isSyntheticClass(clazz)
+            && !appView.getSyntheticItems().isSubjectToKeepRules(clazz)) {
           // Don't treat compiler synthesized classes as kept roots.
           continue;
         }
diff --git a/src/main/java/com/android/tools/r8/synthesis/CommittedSyntheticsCollection.java b/src/main/java/com/android/tools/r8/synthesis/CommittedSyntheticsCollection.java
index 7dbdec5..a201d6a 100644
--- a/src/main/java/com/android/tools/r8/synthesis/CommittedSyntheticsCollection.java
+++ b/src/main/java/com/android/tools/r8/synthesis/CommittedSyntheticsCollection.java
@@ -9,6 +9,7 @@
 import com.android.tools.r8.graph.PrunedItems;
 import com.android.tools.r8.utils.BooleanBox;
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Sets;
 import java.util.Collection;
 import java.util.Map;
@@ -29,6 +30,7 @@
         null;
     private ImmutableMap.Builder<DexType, SyntheticMethodReference> newNonLegacyMethods = null;
     private ImmutableMap.Builder<DexType, LegacySyntheticReference> newLegacyClasses = null;
+    private ImmutableSet.Builder<DexType> newSyntheticInputs = null;
 
     public Builder(CommittedSyntheticsCollection parent) {
       this.parent = parent;
@@ -81,6 +83,11 @@
       return this;
     }
 
+    Builder addToSyntheticInputs() {
+      newSyntheticInputs = ImmutableSet.builder();
+      return this;
+    }
+
     public CommittedSyntheticsCollection build() {
       if (newNonLegacyClasses == null && newNonLegacyMethods == null && newLegacyClasses == null) {
         return parent;
@@ -97,13 +104,22 @@
           newLegacyClasses == null
               ? parent.legacyTypes
               : newLegacyClasses.putAll(parent.legacyTypes).build();
+      ImmutableSet<DexType> allSyntheticInputs =
+          newSyntheticInputs == null
+              ? parent.syntheticInputs
+              : newSyntheticInputs
+                  .addAll(allNonLegacyClasses.keySet())
+                  .addAll(allNonLegacyMethods.keySet())
+                  .addAll(allLegacyClasses.keySet())
+                  .build();
       return new CommittedSyntheticsCollection(
-          allLegacyClasses, allNonLegacyMethods, allNonLegacyClasses);
+          allLegacyClasses, allNonLegacyMethods, allNonLegacyClasses, allSyntheticInputs);
     }
   }
 
   private static final CommittedSyntheticsCollection EMPTY =
-      new CommittedSyntheticsCollection(ImmutableMap.of(), ImmutableMap.of(), ImmutableMap.of());
+      new CommittedSyntheticsCollection(
+          ImmutableMap.of(), ImmutableMap.of(), ImmutableMap.of(), ImmutableSet.of());
 
   /**
    * Immutable set of synthetic types in the application (eg, committed).
@@ -118,13 +134,18 @@
   /** Mapping from synthetic type to its synthetic class item description. */
   private final ImmutableMap<DexType, SyntheticProgramClassReference> nonLegacyClasses;
 
+  /** Set of synthetic types that were present in the input. */
+  private final ImmutableSet<DexType> syntheticInputs;
+
   public CommittedSyntheticsCollection(
       ImmutableMap<DexType, LegacySyntheticReference> legacyTypes,
       ImmutableMap<DexType, SyntheticMethodReference> nonLegacyMethods,
-      ImmutableMap<DexType, SyntheticProgramClassReference> nonLegacyClasses) {
+      ImmutableMap<DexType, SyntheticProgramClassReference> nonLegacyClasses,
+      ImmutableSet<DexType> syntheticInputs) {
     this.legacyTypes = legacyTypes;
     this.nonLegacyMethods = nonLegacyMethods;
     this.nonLegacyClasses = nonLegacyClasses;
+    this.syntheticInputs = syntheticInputs;
     assert legacyTypes.size() + nonLegacyMethods.size() + nonLegacyClasses.size()
         == Sets.union(
                 Sets.union(nonLegacyMethods.keySet(), nonLegacyClasses.keySet()),
@@ -140,8 +161,15 @@
     return new Builder(this);
   }
 
+  Builder builderForSyntheticInputs() {
+    return new Builder(this).addToSyntheticInputs();
+  }
+
   boolean isEmpty() {
-    return legacyTypes.isEmpty() && nonLegacyMethods.isEmpty() && nonLegacyClasses.isEmpty();
+    boolean empty =
+        legacyTypes.isEmpty() && nonLegacyMethods.isEmpty() && nonLegacyClasses.isEmpty();
+    assert !empty || syntheticInputs.isEmpty();
+    return empty;
   }
 
   boolean containsType(DexType type) {
@@ -156,6 +184,10 @@
     return nonLegacyMethods.containsKey(type) || nonLegacyClasses.containsKey(type);
   }
 
+  public boolean containsSyntheticInput(DexType type) {
+    return syntheticInputs.contains(type);
+  }
+
   public ImmutableMap<DexType, LegacySyntheticReference> getLegacyTypes() {
     return legacyTypes;
   }
@@ -176,6 +208,10 @@
     return nonLegacyClasses.get(type);
   }
 
+  public void forEachSyntheticInput(Consumer<DexType> fn) {
+    syntheticInputs.forEach(fn);
+  }
+
   public void forEachNonLegacyItem(Consumer<SyntheticReference<?, ?, ?>> fn) {
     nonLegacyMethods.forEach((t, r) -> fn.accept(r));
     nonLegacyClasses.forEach((t, r) -> fn.accept(r));
@@ -217,7 +253,16 @@
     return new CommittedSyntheticsCollection(
         rewriteItems(legacyTypes, lens),
         rewriteItems(nonLegacyMethods, lens),
-        rewriteItems(nonLegacyClasses, lens));
+        rewriteItems(nonLegacyClasses, lens),
+        rewriteItems(syntheticInputs, lens));
+  }
+
+  private static ImmutableSet<DexType> rewriteItems(Set<DexType> items, NonIdentityGraphLens lens) {
+    ImmutableSet.Builder<DexType> rewrittenItems = ImmutableSet.builder();
+    for (DexType item : items) {
+      rewrittenItems.add(lens.lookupType(item));
+    }
+    return rewrittenItems.build();
   }
 
   private static <R extends Rewritable<R>> ImmutableMap<DexType, R> rewriteItems(
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java
index 8f883ea..5fa5498 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java
@@ -35,6 +35,7 @@
 import com.google.common.collect.ImmutableCollection;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Sets;
 import com.google.common.hash.HashCode;
 import java.util.ArrayList;
@@ -237,6 +238,12 @@
           }
         });
 
+    SyntheticFinalizationGraphLens syntheticFinalizationGraphLens = lensBuilder.build(appView);
+
+    ImmutableSet.Builder<DexType> finalInputSyntheticsBuilder = ImmutableSet.builder();
+    committed.forEachSyntheticInput(
+        type -> finalInputSyntheticsBuilder.add(syntheticFinalizationGraphLens.lookupType(type)));
+
     // TODO(b/181858113): Remove once deprecated main-dex-list is removed.
     MainDexInfo.Builder mainDexInfoBuilder = appView.appInfo().getMainDexInfo().builderFromCopy();
     derivedMainDexTypes.forEach(mainDexInfoBuilder::addList);
@@ -246,9 +253,12 @@
             SyntheticItems.INVALID_ID_AFTER_SYNTHETIC_FINALIZATION,
             application,
             new CommittedSyntheticsCollection(
-                committed.getLegacyTypes(), finalMethods, finalClasses),
+                committed.getLegacyTypes(),
+                finalMethods,
+                finalClasses,
+                finalInputSyntheticsBuilder.build()),
             ImmutableList.of()),
-        lensBuilder.build(appView),
+        syntheticFinalizationGraphLens,
         PrunedItems.builder().setPrunedApp(application).addRemovedClasses(prunedSynthetics).build(),
         mainDexInfoBuilder.build());
   }
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
index d6c93aa..b90083a 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
@@ -109,7 +109,7 @@
     this.committed = committed;
   }
 
-  public static void collectSyntheticInputs(AppView<AppInfo> appView) {
+  public static void collectSyntheticInputs(AppView<?> appView) {
     // Collecting synthetic items must be the very first task after application build.
     SyntheticItems synthetics = appView.getSyntheticItems();
     assert synthetics.nextSyntheticId == 0;
@@ -119,7 +119,8 @@
       // If the compilation is in intermediate mode the synthetics should just be passed through.
       return;
     }
-    CommittedSyntheticsCollection.Builder builder = synthetics.committed.builder();
+    CommittedSyntheticsCollection.Builder builder =
+        synthetics.committed.builderForSyntheticInputs();
     // TODO(b/158159959): Consider identifying synthetics in the input reader to speed this up.
     for (DexProgramClass clazz : appView.appInfo().classes()) {
       SyntheticMarker marker =
@@ -127,10 +128,9 @@
       if (marker.isSyntheticMethods()) {
         clazz.forEachProgramMethod(
             // TODO(b/158159959): Support having multiple methods per class.
-            method -> {
-              builder.addNonLegacyMethod(
-                  new SyntheticMethodDefinition(marker.getKind(), marker.getContext(), method));
-            });
+            method ->
+                builder.addNonLegacyMethod(
+                    new SyntheticMethodDefinition(marker.getKind(), marker.getContext(), method)));
       } else if (marker.isSyntheticClass()) {
         builder.addNonLegacyClass(
             new SyntheticProgramClassDefinition(marker.getKind(), marker.getContext(), clazz));
@@ -143,7 +143,15 @@
     CommittedItems commit =
         new CommittedItems(
             synthetics.nextSyntheticId, appView.appInfo().app(), committed, ImmutableList.of());
-    appView.setAppInfo(new AppInfo(commit, appView.appInfo().getMainDexInfo()));
+    if (appView.appInfo().hasClassHierarchy()) {
+      appView
+          .withClassHierarchy()
+          .setAppInfo(appView.appInfo().withClassHierarchy().rebuildWithClassHierarchy(commit));
+    } else {
+      appView
+          .withoutClassHierarchy()
+          .setAppInfo(new AppInfo(commit, appView.appInfo().getMainDexInfo()));
+    }
   }
 
   // Predicates and accessors.
@@ -239,6 +247,11 @@
     return null;
   }
 
+  public boolean isSubjectToKeepRules(DexProgramClass clazz) {
+    assert isSyntheticClass(clazz);
+    return committed.containsSyntheticInput(clazz.getType());
+  }
+
   public boolean isSyntheticClass(DexType type) {
     return isLegacySyntheticClass(type) || isNonLegacySynthetic(type);
   }