Introduce a callback for when optimizations that change the app finish

Change-Id: I5ff0139e27d93f231a760091adab984909ffcfc2
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 3b85d38..9848f4b 100644
--- a/src/main/java/com/android/tools/r8/graph/AppView.java
+++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -1180,6 +1180,14 @@
     this.alreadyLibraryDesugared = alreadyLibraryDesugared;
   }
 
+  /**
+   * Called when an optimization that changes the app has finished. This allows easier diagnosing
+   * some failures, e.g., finding which optimization pass that adds/removes a given method.
+   */
+  public void notifyOptimizationFinishedForTesting() {
+    // Intentionally empty.
+  }
+
   public boolean isAlreadyLibraryDesugared(DexProgramClass clazz) {
     if (!options().desugarSpecificOptions().allowAllDesugaredInput) {
       return false;
diff --git a/src/main/java/com/android/tools/r8/graph/MethodAccessInfoCollection.java b/src/main/java/com/android/tools/r8/graph/MethodAccessInfoCollection.java
index 68f9b0a..e3b45a8 100644
--- a/src/main/java/com/android/tools/r8/graph/MethodAccessInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/graph/MethodAccessInfoCollection.java
@@ -184,7 +184,9 @@
                     if (prunedItems.isRemoved(context.getReference())) {
                       return true;
                     }
-                    assert prunedItems.getPrunedApp().definitionFor(context.getReference()) != null;
+                    assert prunedItems.getPrunedApp().definitionFor(context.getReference()) != null
+                        : "Expected method to be present: "
+                            + context.getReference().toSourceString();
                     return false;
                   });
               return contexts.isEmpty();
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
index 9464ef4..9f2e2ad 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
@@ -96,6 +96,7 @@
 
       // Clear type elements cache after IR building.
       appView.dexItemFactory().clearTypeElementsCache();
+      appView.notifyOptimizationFinishedForTesting();
 
       timing.end();
     } else {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/NestReducer.java b/src/main/java/com/android/tools/r8/ir/optimize/NestReducer.java
index e20e28c..80ea1ad 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/NestReducer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/NestReducer.java
@@ -43,6 +43,7 @@
     } else {
       reduceNests(executorService);
     }
+    appView.notifyOptimizationFinishedForTesting();
     timing.end();
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java
index 5b8e1f7..115ab23 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java
@@ -757,6 +757,7 @@
     // Ensure determinism of method-to-reprocess set.
     appView.testing().checkDeterminism(postMethodProcessorBuilder::dump);
 
+    appView.notifyOptimizationFinishedForTesting();
     timing.end();
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/outliner/OutlinerImpl.java b/src/main/java/com/android/tools/r8/ir/optimize/outliner/OutlinerImpl.java
index 3b0caa2..9cd00c7 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/outliner/OutlinerImpl.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/outliner/OutlinerImpl.java
@@ -1378,6 +1378,7 @@
       outlineMethods.forEach(m -> m.getDefinition().markNotProcessed());
       eventConsumer.finished(appView);
     }
+    appView.notifyOptimizationFinishedForTesting();
     timing.end();
   }
 
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 52fee79..229de6a 100644
--- a/src/main/java/com/android/tools/r8/naming/Minifier.java
+++ b/src/main/java/com/android/tools/r8/naming/Minifier.java
@@ -86,6 +86,7 @@
     new IdentifierMinifier(appView, lens).run(executorService);
     timing.end();
 
+    appView.notifyOptimizationFinishedForTesting();
     return lens;
   }
 
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 3c128fb..38a950d 100644
--- a/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java
@@ -157,6 +157,7 @@
     new IdentifierMinifier(appView, lens).run(executorService);
     timing.end();
 
+    appView.notifyOptimizationFinishedForTesting();
     return lens;
   }
 
diff --git a/src/main/java/com/android/tools/r8/optimize/AccessModifier.java b/src/main/java/com/android/tools/r8/optimize/AccessModifier.java
index 410bec2..dea6346 100644
--- a/src/main/java/com/android/tools/r8/optimize/AccessModifier.java
+++ b/src/main/java/com/android/tools/r8/optimize/AccessModifier.java
@@ -81,6 +81,8 @@
     if (publicizerLens != null) {
       appView.setGraphLens(publicizerLens);
     }
+
+    appView.notifyOptimizationFinishedForTesting();
   }
 
   private void doPublicize(ProgramDefinition definition) {
diff --git a/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java b/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
index ca5ae4a..41b4f59 100644
--- a/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
+++ b/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
@@ -526,6 +526,7 @@
     MemberRebindingLens memberRebindingLens = lensBuilder.build();
     appView.setGraphLens(memberRebindingLens);
     eventConsumer.finished(appView, memberRebindingLens);
+    appView.notifyOptimizationFinishedForTesting();
   }
 
   private boolean verifyFieldAccessCollectionContainsAllNonReboundFieldReferences(
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagator.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagator.java
index 2d47dcc..8a00318 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagator.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagator.java
@@ -199,6 +199,8 @@
 
     // Ensure determinism of method-to-reprocess set.
     appView.testing().checkDeterminism(postMethodProcessorBuilder::dump);
+
+    appView.notifyOptimizationFinishedForTesting();
   }
 
   /**
diff --git a/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoisting.java b/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoisting.java
index 23f8122..1e147e2 100644
--- a/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoisting.java
+++ b/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoisting.java
@@ -122,6 +122,8 @@
             }
           });
     }
+
+    appView.notifyOptimizationFinishedForTesting();
     timing.end();
   }
 
diff --git a/src/main/java/com/android/tools/r8/optimize/fields/FieldFinalizer.java b/src/main/java/com/android/tools/r8/optimize/fields/FieldFinalizer.java
index 9b4bec4..154c354 100644
--- a/src/main/java/com/android/tools/r8/optimize/fields/FieldFinalizer.java
+++ b/src/main/java/com/android/tools/r8/optimize/fields/FieldFinalizer.java
@@ -30,6 +30,7 @@
       AppView<AppInfoWithLiveness> appView, ExecutorService executorService, Timing timing)
       throws ExecutionException {
     timing.time("Finalize fields pass", () -> run(appView, executorService));
+    appView.notifyOptimizationFinishedForTesting();
   }
 
   private static void run(AppView<AppInfoWithLiveness> appView, ExecutorService executorService)
diff --git a/src/main/java/com/android/tools/r8/optimize/proto/ProtoNormalizer.java b/src/main/java/com/android/tools/r8/optimize/proto/ProtoNormalizer.java
index 54ae131..47df2ba 100644
--- a/src/main/java/com/android/tools/r8/optimize/proto/ProtoNormalizer.java
+++ b/src/main/java/com/android/tools/r8/optimize/proto/ProtoNormalizer.java
@@ -153,6 +153,7 @@
     if (!lensBuilder.isEmpty()) {
       appView.rewriteWithLens(lensBuilder.build(), executorService, timing);
     }
+    appView.notifyOptimizationFinishedForTesting();
     timing.end();
   }
 
diff --git a/src/main/java/com/android/tools/r8/optimize/redundantbridgeremoval/RedundantBridgeRemover.java b/src/main/java/com/android/tools/r8/optimize/redundantbridgeremoval/RedundantBridgeRemover.java
index 4a3c874..73a0444 100644
--- a/src/main/java/com/android/tools/r8/optimize/redundantbridgeremoval/RedundantBridgeRemover.java
+++ b/src/main/java/com/android/tools/r8/optimize/redundantbridgeremoval/RedundantBridgeRemover.java
@@ -147,6 +147,7 @@
       }
     }
 
+    appView.notifyOptimizationFinishedForTesting();
     timing.end();
   }
 
diff --git a/src/main/java/com/android/tools/r8/repackaging/Repackaging.java b/src/main/java/com/android/tools/r8/repackaging/Repackaging.java
index 77be1dc..f4c023f 100644
--- a/src/main/java/com/android/tools/r8/repackaging/Repackaging.java
+++ b/src/main/java/com/android/tools/r8/repackaging/Repackaging.java
@@ -77,6 +77,7 @@
     if (lens != null) {
       appView.rewriteWithLensAndApplication(lens, appBuilder.build(), executorService, timing);
     }
+    appView.notifyOptimizationFinishedForTesting();
     timing.end();
   }
 
diff --git a/src/main/java/com/android/tools/r8/shaking/AbstractMethodRemover.java b/src/main/java/com/android/tools/r8/shaking/AbstractMethodRemover.java
index d941a87..a5854e2 100644
--- a/src/main/java/com/android/tools/r8/shaking/AbstractMethodRemover.java
+++ b/src/main/java/com/android/tools/r8/shaking/AbstractMethodRemover.java
@@ -37,6 +37,7 @@
   public void run() {
     assert scope.getParent() == null;
     processClass(appView.dexItemFactory().objectType);
+    appView.notifyOptimizationFinishedForTesting();
   }
 
   private void processClass(DexType type) {
diff --git a/src/main/java/com/android/tools/r8/shaking/ClassInitFieldSynthesizer.java b/src/main/java/com/android/tools/r8/shaking/ClassInitFieldSynthesizer.java
index 848ea2a..1888d15 100644
--- a/src/main/java/com/android/tools/r8/shaking/ClassInitFieldSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/shaking/ClassInitFieldSynthesizer.java
@@ -35,6 +35,7 @@
     ThreadUtils.processMap(
         appView.appInfo().initClassReferences, this::synthesizeClassInitField, executorService);
     appView.setInitClassLens(lensBuilder.build());
+    appView.notifyOptimizationFinishedForTesting();
   }
 
   private void synthesizeClassInitField(DexType type, Visibility minimumRequiredVisibility) {
diff --git a/src/main/java/com/android/tools/r8/shaking/TreePruner.java b/src/main/java/com/android/tools/r8/shaking/TreePruner.java
index fddfe68..3688415 100644
--- a/src/main/java/com/android/tools/r8/shaking/TreePruner.java
+++ b/src/main/java/com/android/tools/r8/shaking/TreePruner.java
@@ -93,6 +93,7 @@
             .addAdditionalPinnedItems(methodsToKeepForConfigurationDebugging)
             .build();
     appView.pruneItems(prunedItems, executorService, timing);
+    appView.notifyOptimizationFinishedForTesting();
     timing.end();
     return prunedItems;
   }
diff --git a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
index 01b19c3..4c152b6 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -658,6 +658,7 @@
           }
         });
 
+    appView.notifyOptimizationFinishedForTesting();
     return lens;
   }
 
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 e7c6a53..9ed366e 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java
@@ -197,6 +197,7 @@
       appView.rewriteWithLens(result.lens, executorService, timing);
     }
     appView.pruneItems(result.prunedItems, executorService, timing);
+    appView.notifyOptimizationFinishedForTesting();
   }
 
   public static void finalizeWithLiveness(
@@ -213,6 +214,7 @@
     }
     appView.setAppInfo(appView.appInfo().rebuildWithLiveness(result.commit));
     appView.pruneItems(result.prunedItems, executorService, timing);
+    appView.notifyOptimizationFinishedForTesting();
   }
 
   Result computeFinalSynthetics(AppView<?> appView, Timing timing) {