Insert Identity lens after IR processing

- Allows to execute twice the lensCodeRewriter

Bug: 147860220
Change-Id: Id08602ed524d81b5f17fce5ebda2664012720901
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 9f7b4cf..32b996a 100644
--- a/src/main/java/com/android/tools/r8/graph/AppView.java
+++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -149,6 +149,10 @@
     allCodeProcessed = true;
   }
 
+  public GraphLense clearLensCodeRewriting() {
+    return graphLense = graphLense.withCodeRewritingsApplied();
+  }
+
   public AppServices appServices() {
     return appServices;
   }
diff --git a/src/main/java/com/android/tools/r8/graph/AppliedGraphLens.java b/src/main/java/com/android/tools/r8/graph/AppliedGraphLens.java
index 18f8fe6..a05883a 100644
--- a/src/main/java/com/android/tools/r8/graph/AppliedGraphLens.java
+++ b/src/main/java/com/android/tools/r8/graph/AppliedGraphLens.java
@@ -8,7 +8,6 @@
 import com.google.common.collect.BiMap;
 import com.google.common.collect.HashBiMap;
 import java.util.IdentityHashMap;
-import java.util.List;
 import java.util.Map;
 
 /**
@@ -29,7 +28,7 @@
       new IdentityHashMap<>();
 
   public AppliedGraphLens(
-      AppView<? extends AppInfoWithSubtyping> appView, List<DexProgramClass> classes) {
+      AppView<? extends AppInfoWithSubtyping> appView, Iterable<DexProgramClass> classes) {
     this.appView = appView;
 
     for (DexProgramClass clazz : classes) {
@@ -135,4 +134,9 @@
   public boolean isContextFreeForMethods() {
     return true;
   }
+
+  @Override
+  public boolean hasCodeRewritings() {
+    return false;
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/graph/GraphLense.java b/src/main/java/com/android/tools/r8/graph/GraphLense.java
index f1d1a34..6f8d92e 100644
--- a/src/main/java/com/android/tools/r8/graph/GraphLense.java
+++ b/src/main/java/com/android/tools/r8/graph/GraphLense.java
@@ -223,10 +223,21 @@
     return IdentityGraphLense.getInstance();
   }
 
+  public boolean hasCodeRewritings() {
+    return true;
+  }
+
   public final boolean isIdentityLense() {
     return this == getIdentityLense();
   }
 
+  public GraphLense withCodeRewritingsApplied() {
+    if (hasCodeRewritings()) {
+      return new ClearCodeRewritingGraphLens(this);
+    }
+    return this;
+  }
+
   public <T extends DexDefinition> boolean assertDefinitionsNotModified(Iterable<T> definitions) {
     for (DexDefinition definition : definitions) {
       DexReference reference = definition.toReference();
@@ -455,6 +466,46 @@
     public boolean isContextFreeForMethods() {
       return true;
     }
+
+    @Override
+    public boolean hasCodeRewritings() {
+      return false;
+    }
+  }
+
+  // This lens clears all code rewriting (lookup methods mimics identity lens behavior) but still
+  // relies on the previous lens for names (getRenamed/Original methods).
+  public static class ClearCodeRewritingGraphLens extends IdentityGraphLense {
+    private final GraphLense previous;
+
+    public ClearCodeRewritingGraphLens(GraphLense previous) {
+      this.previous = previous;
+    }
+
+    @Override
+    public DexType getOriginalType(DexType type) {
+      return previous.getOriginalType(type);
+    }
+
+    @Override
+    public DexField getOriginalFieldSignature(DexField field) {
+      return previous.getOriginalFieldSignature(field);
+    }
+
+    @Override
+    public DexMethod getOriginalMethodSignature(DexMethod method) {
+      return previous.getOriginalMethodSignature(method);
+    }
+
+    @Override
+    public DexField getRenamedFieldSignature(DexField originalField) {
+      return previous.getRenamedFieldSignature(originalField);
+    }
+
+    @Override
+    public DexMethod getRenamedMethodSignature(DexMethod originalMethod) {
+      return previous.getRenamedMethodSignature(originalMethod);
+    }
   }
 
   /**
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index 6edeab0..08086ff 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -663,6 +663,10 @@
     // Assure that no more optimization feedback left after primary processing.
     assert feedback.noUpdatesLeft();
     appView.setAllCodeProcessed();
+    // All the code has been processed so the rewriting required by the lenses is done everywhere,
+    // we clear lens code rewriting so that the lens rewriter can be re-executed in phase 2 if new
+    // lenses with code rewriting are added.
+    graphLenseForIR = appView.clearLensCodeRewriting();
 
     if (libraryMethodOverrideAnalysis != null) {
       libraryMethodOverrideAnalysis.finish();
@@ -693,6 +697,11 @@
     }
     timing.end();
 
+    // All the code that should be impacted by the lenses inserted between phase 1 and phase 2
+    // have now been processed and rewritten, we clear code lens rewriting so that the class
+    // staticizer and phase 3 does not perform again the rewriting.
+    appView.clearLensCodeRewriting();
+
     // TODO(b/112831361): Implement support for staticizeClasses in CF backend.
     if (!options.isGeneratingClassFiles()) {
       printPhase("Class staticizer post processing");
@@ -1104,18 +1113,18 @@
       codeRewriter.simplifyDebugLocals(code);
     }
 
+    //TODO(b/149364041): Remove !method.isProcessed().
+    if (lensCodeRewriter != null
+        && (!method.isProcessed() || appView.graphLense().hasCodeRewritings())) {
+      timing.begin("Lens rewrite");
+      lensCodeRewriter.rewrite(code, method);
+      timing.end();
+    }
+
     if (method.isProcessed()) {
       assert !appView.enableWholeProgramOptimizations()
           || !appView.appInfo().withLiveness().neverReprocess.contains(method.method);
     } else {
-      if (lensCodeRewriter != null) {
-        timing.begin("Lens rewrite");
-        lensCodeRewriter.rewrite(code, method);
-        timing.end();
-      } else {
-        assert appView.graphLense().isIdentityLense();
-      }
-
       if (lambdaRewriter != null) {
         timing.begin("Desugar lambdas");
         lambdaRewriter.desugarLambdas(method, code);