Rename merged exception classes in DeadCodeRemover

This CL renames the guards in catch handlers in the DeadCodeRemover, and removes catch handlers that are clearly not needed after renaming.

Example:

  try { ... }
  catch (ExceptionB e) { ... }
  catch (ExceptionA e) {
    // If ExceptionA gets merged into ExceptionB, then this handler is clearly dead
    ...
  }

Bug: 73958515
Change-Id: I85613f28ee45fe1f6edad2644252fb3ba14a747a
diff --git a/src/test/examples/classmerging/ExceptionTest.java b/src/test/examples/classmerging/ExceptionTest.java
index b365b2a..28442f3 100644
--- a/src/test/examples/classmerging/ExceptionTest.java
+++ b/src/test/examples/classmerging/ExceptionTest.java
@@ -8,12 +8,27 @@
   public static void main(String[] args) {
     // The following will lead to a catch handler for ExceptionA, which is merged into ExceptionB.
     try {
-      throw new ExceptionB("Ouch!");
+      doSomethingThatMightThrowExceptionB();
+      doSomethingThatMightThrowException2();
+    } catch (ExceptionB exception) {
+      System.out.println("Caught exception: " + exception.getMessage());
     } catch (ExceptionA exception) {
       System.out.println("Caught exception: " + exception.getMessage());
+    } catch (Exception2 exception) {
+      System.out.println("Caught exception: " + exception.getMessage());
+    } catch (Exception1 exception) {
+      System.out.println("Caught exception: " + exception.getMessage());
     }
   }
 
+  private static void doSomethingThatMightThrowExceptionB() throws ExceptionB {
+    throw new ExceptionB("Ouch!");
+  }
+
+  private static void doSomethingThatMightThrowException2() throws Exception2 {
+    throw new Exception2("Ouch!");
+  }
+
   // Will be merged into ExceptionB when class merging is enabled.
   public static class ExceptionA extends Exception {
     public ExceptionA(String message) {
@@ -26,4 +41,16 @@
       super(message);
     }
   }
+
+  public static class Exception1 extends Exception {
+    public Exception1(String message) {
+      super(message);
+    }
+  }
+
+  public static class Exception2 extends Exception1 {
+    public Exception2(String message) {
+      super(message);
+    }
+  }
 }
diff --git a/src/test/java/com/android/tools/r8/classmerging/ClassMergingTest.java b/src/test/java/com/android/tools/r8/classmerging/ClassMergingTest.java
index 69f925c..d2643cb 100644
--- a/src/test/java/com/android/tools/r8/classmerging/ClassMergingTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/ClassMergingTest.java
@@ -3,8 +3,10 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.classmerging;
 
+import static com.android.tools.r8.utils.DexInspectorMatchers.isPresent;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 
 import com.android.tools.r8.CompilationFailedException;
@@ -12,9 +14,14 @@
 import com.android.tools.r8.R8Command;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.code.Instruction;
+import com.android.tools.r8.code.MoveException;
+import com.android.tools.r8.graph.DexCode;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.DexInspector;
+import com.android.tools.r8.utils.DexInspector.ClassSubject;
 import com.android.tools.r8.utils.DexInspector.FoundClassSubject;
+import com.android.tools.r8.utils.DexInspector.MethodSubject;
 import com.android.tools.r8.utils.InternalOptions;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
@@ -110,14 +117,36 @@
         new Path[] {
           CF_DIR.resolve("ExceptionTest.class"),
           CF_DIR.resolve("ExceptionTest$ExceptionA.class"),
-          CF_DIR.resolve("ExceptionTest$ExceptionB.class")
+          CF_DIR.resolve("ExceptionTest$ExceptionB.class"),
+          CF_DIR.resolve("ExceptionTest$Exception1.class"),
+          CF_DIR.resolve("ExceptionTest$Exception2.class")
         };
     Set<String> preservedClassNames =
-        ImmutableSet.of("classmerging.ExceptionTest", "classmerging.ExceptionTest$ExceptionB");
-    runTest(main, programFiles, preservedClassNames);
+        ImmutableSet.of(
+            "classmerging.ExceptionTest",
+            "classmerging.ExceptionTest$ExceptionB",
+            "classmerging.ExceptionTest$Exception2");
+    DexInspector inspector = runTest(main, programFiles, preservedClassNames);
+
+    ClassSubject mainClass = inspector.clazz(main);
+    assertThat(mainClass, isPresent());
+
+    MethodSubject mainMethod =
+        mainClass.method("void", "main", ImmutableList.of("java.lang.String[]"));
+    assertThat(mainMethod, isPresent());
+
+    // Check that the second catch handler has been removed.
+    DexCode code = mainMethod.getMethod().getCode().asDexCode();
+    int numberOfMoveExceptionInstructions = 0;
+    for (Instruction instruction : code.instructions) {
+      if (instruction instanceof MoveException) {
+        numberOfMoveExceptionInstructions++;
+      }
+    }
+    assertEquals(2, numberOfMoveExceptionInstructions);
   }
 
-  private void runTest(String main, Path[] programFiles, Set<String> preservedClassNames)
+  private DexInspector runTest(String main, Path[] programFiles, Set<String> preservedClassNames)
       throws Exception {
     AndroidApp input = readProgramFiles(programFiles);
     AndroidApp output = compileWithR8(input, EXAMPLE_KEEP, this::configure);
@@ -135,5 +164,6 @@
     }
     // Check that the R8-generated code produces the same result as D8-generated code.
     assertEquals(runOnArt(compileWithD8(input), main), runOnArt(output, main));
+    return inspector;
   }
 }
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
index d6e3612..4214a67 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
@@ -38,7 +38,6 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.DexTypeList;
 import com.android.tools.r8.graph.DirectMappedDexApplication;
-import com.android.tools.r8.graph.GraphLense;
 import com.android.tools.r8.graph.MethodAccessFlags;
 import com.android.tools.r8.graph.ParameterAnnotationsList;
 import com.android.tools.r8.ir.code.CatchHandlers;
@@ -653,7 +652,7 @@
                 code);
         IRCode ir = code.buildIR(method, null, options, Origin.unknown());
         RegisterAllocator allocator = new LinearScanRegisterAllocator(ir, options);
-        method.setCode(ir, GraphLense.getIdentityLense(), allocator, options);
+        method.setCode(ir, allocator, options);
         directMethods[i] = method;
       }
       builder.addProgramClass(