Version 1.0.13.

Merge: Include catched types as direct dependencies (Bug: 74105749)
CL: https://r8-review.googlesource.com/c/r8/+/17160
Change-Id: I8e975260370d33f90a606595c377b585932d8018
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index 9781dc5..5ea4f5f 100644
--- a/src/main/java/com/android/tools/r8/Version.java
+++ b/src/main/java/com/android/tools/r8/Version.java
@@ -11,7 +11,7 @@
 
   // This field is accessed from release scripts using simple pattern matching.
   // Therefore, changing this field could break our release scripts.
-  public static final String LABEL = "v1.0.12";
+  public static final String LABEL = "v1.0.13";
 
   private Version() {
   }
diff --git a/src/main/java/com/android/tools/r8/graph/CfCode.java b/src/main/java/com/android/tools/r8/graph/CfCode.java
index f7c3b24..a9b3c9e 100644
--- a/src/main/java/com/android/tools/r8/graph/CfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/CfCode.java
@@ -14,6 +14,7 @@
 import com.android.tools.r8.utils.InternalOptions;
 import java.util.Collections;
 import java.util.List;
+import java.util.function.Consumer;
 import org.objectweb.asm.Label;
 import org.objectweb.asm.MethodVisitor;
 
@@ -154,7 +155,12 @@
   }
 
   @Override
-  public void registerReachableDefinitions(UseRegistry registry) {
+  public void registerInstructionsReferences(UseRegistry registry) {
+    throw new Unimplemented("Inspecting Java class-file bytecode not yet supported");
+  }
+
+  @Override
+  public void registerCaughtTypes(Consumer<DexType> dexTypeConsumer) {
     throw new Unimplemented("Inspecting Java class-file bytecode not yet supported");
   }
 
diff --git a/src/main/java/com/android/tools/r8/graph/Code.java b/src/main/java/com/android/tools/r8/graph/Code.java
index 14c4bbc..b6c1583 100644
--- a/src/main/java/com/android/tools/r8/graph/Code.java
+++ b/src/main/java/com/android/tools/r8/graph/Code.java
@@ -13,6 +13,7 @@
 import com.android.tools.r8.ir.optimize.Outliner.OutlineCode;
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.utils.InternalOptions;
+import java.util.function.Consumer;
 
 public abstract class Code extends CachedHashValueDexItem {
 
@@ -29,7 +30,9 @@
         + getClass().getCanonicalName());
   }
 
-  public abstract void registerReachableDefinitions(UseRegistry registry);
+  public abstract void registerInstructionsReferences(UseRegistry registry);
+
+  public abstract void registerCaughtTypes(Consumer<DexType> dexTypeConsumer);
 
   @Override
   public abstract String toString();
diff --git a/src/main/java/com/android/tools/r8/graph/DexCode.java b/src/main/java/com/android/tools/r8/graph/DexCode.java
index a522e82..1517dfb 100644
--- a/src/main/java/com/android/tools/r8/graph/DexCode.java
+++ b/src/main/java/com/android/tools/r8/graph/DexCode.java
@@ -10,6 +10,7 @@
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.dex.MixedSectionCollection;
 import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.DexCode.TryHandler.TypeAddrPair;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.Position;
 import com.android.tools.r8.ir.code.ValueNumberGenerator;
@@ -27,6 +28,7 @@
 import java.util.Iterator;
 import java.util.Map;
 import java.util.Set;
+import java.util.function.Consumer;
 
 // DexCode corresponds to code item in dalvik/dex-format.html
 public class DexCode extends Code {
@@ -188,13 +190,22 @@
   }
 
   @Override
-  public void registerReachableDefinitions(UseRegistry registry) {
+  public void registerInstructionsReferences(UseRegistry registry) {
     for (Instruction insn : instructions) {
       insn.registerUse(registry);
     }
   }
 
   @Override
+  public void registerCaughtTypes(Consumer<DexType> dexTypeConsumer) {
+    for (TryHandler handler : handlers) {
+      for (TypeAddrPair pair : handler.pairs) {
+        dexTypeConsumer.accept(pair.type);
+      }
+    }
+  }
+
+  @Override
   public String toString() {
     return toString(null, null);
   }
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index 4a903dc..6a7726f 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -501,12 +501,21 @@
     return !annotations.isEmpty() || !parameterAnnotations.isEmpty();
   }
 
-  public void registerReachableDefinitions(UseRegistry registry) {
+  public void registerInstructionsReferences(UseRegistry registry) {
     if (code != null) {
       if (Log.ENABLED) {
         Log.verbose(getClass(), "Registering definitions reachable from `%s`.", method);
       }
-      code.registerReachableDefinitions(registry);
+      code.registerInstructionsReferences(registry);
+    }
+  }
+
+  public void registerCatchedTypes(Consumer<DexType> dexTypeConsumer) {
+    if (code != null) {
+      if (Log.ENABLED) {
+        Log.verbose(getClass(), "Visiting catched types `%s`.", method);
+      }
+      code.registerCaughtTypes(dexTypeConsumer);
     }
   }
 
diff --git a/src/main/java/com/android/tools/r8/graph/JarCode.java b/src/main/java/com/android/tools/r8/graph/JarCode.java
index 62dc43f..11a70a3 100644
--- a/src/main/java/com/android/tools/r8/graph/JarCode.java
+++ b/src/main/java/com/android/tools/r8/graph/JarCode.java
@@ -13,11 +13,13 @@
 import com.android.tools.r8.jar.JarRegisterEffectsVisitor;
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.InternalOptions;
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.function.Consumer;
 import org.objectweb.asm.ClassReader;
 import org.objectweb.asm.ClassVisitor;
 import org.objectweb.asm.MethodVisitor;
@@ -148,13 +150,20 @@
   }
 
   @Override
-  public void registerReachableDefinitions(UseRegistry registry) {
+  public void registerInstructionsReferences(UseRegistry registry) {
     triggerDelayedParsingIfNeccessary();
     node.instructions.accept(
         new JarRegisterEffectsVisitor(method.getHolder(), registry, application));
   }
 
   @Override
+  public void registerCaughtTypes(Consumer<DexType> dexTypeConsumer) {
+    node.tryCatchBlocks.forEach(tryCatchBlockNode ->
+        dexTypeConsumer.accept(application.getTypeFromDescriptor(
+            DescriptorUtils.getDescriptorFromClassBinaryName(tryCatchBlockNode.type))));
+  }
+
+  @Override
   public String toString() {
     triggerDelayedParsingIfNeccessary();
     TraceMethodVisitor visitor = new TraceMethodVisitor(new Textifier());
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CallGraph.java b/src/main/java/com/android/tools/r8/ir/conversion/CallGraph.java
index b2dafdd..f863778 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CallGraph.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CallGraph.java
@@ -144,7 +144,7 @@
       for (DexEncodedMethod method : clazz.allMethodsSorted()) {
         Node node = graph.ensureMethodNode(method);
         InvokeExtractor extractor = new InvokeExtractor(appInfo, graphLense, node, graph);
-        method.registerReachableDefinitions(extractor);
+        method.registerInstructionsReferences(extractor);
       }
     }
     assert allMethodsExists(application, graph);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
index e834b61..536e4b7 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
@@ -62,6 +62,7 @@
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
+import java.util.function.Consumer;
 
 public class Outliner {
 
@@ -1009,7 +1010,12 @@
     }
 
     @Override
-    public void registerReachableDefinitions(UseRegistry registry) {
+    public void registerInstructionsReferences(UseRegistry registry) {
+      throw new Unreachable();
+    }
+
+    @Override
+    public void registerCaughtTypes(Consumer<DexType> dexTypeConsumer) {
       throw new Unreachable();
     }
 
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/SynthesizedCode.java b/src/main/java/com/android/tools/r8/ir/synthetic/SynthesizedCode.java
index 0de034a..26ef333 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/SynthesizedCode.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/SynthesizedCode.java
@@ -8,6 +8,7 @@
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.Code;
 import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.UseRegistry;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.conversion.IRBuilder;
@@ -47,11 +48,18 @@
   }
 
   @Override
-  public void registerReachableDefinitions(UseRegistry registry) {
+  public void registerInstructionsReferences(UseRegistry registry) {
     registryCallback.accept(registry);
   }
 
   @Override
+  public void registerCaughtTypes(Consumer<DexType> dexTypeConsumer) {
+    // Support for synthesized code with catch handler is not implemented.
+    // Let's check that we're in a well known where no catch handler is possible.
+    assert sourceCode.instructionCount() == 1 || sourceCode instanceof SingleBlockSourceCode;
+  }
+
+  @Override
   protected final int computeHashCode() {
     return sourceCode.hashCode();
   }
diff --git a/src/main/java/com/android/tools/r8/optimize/BridgeMethodAnalysis.java b/src/main/java/com/android/tools/r8/optimize/BridgeMethodAnalysis.java
index a915849..321001e 100644
--- a/src/main/java/com/android/tools/r8/optimize/BridgeMethodAnalysis.java
+++ b/src/main/java/com/android/tools/r8/optimize/BridgeMethodAnalysis.java
@@ -38,7 +38,7 @@
     // be removed.
     if (method.accessFlags.isBridge() && !method.accessFlags.isAbstract()) {
       InvokeSingleTargetExtractor targetExtractor = new InvokeSingleTargetExtractor();
-      method.getCode().registerReachableDefinitions(targetExtractor);
+      method.getCode().registerInstructionsReferences(targetExtractor);
       DexMethod target = targetExtractor.getTarget();
       InvokeKind kind = targetExtractor.getKind();
       if (target != null && target.getArity() == method.method.getArity()) {
diff --git a/src/main/java/com/android/tools/r8/optimize/VisibilityBridgeRemover.java b/src/main/java/com/android/tools/r8/optimize/VisibilityBridgeRemover.java
index 7f5a4f3..685e733 100644
--- a/src/main/java/com/android/tools/r8/optimize/VisibilityBridgeRemover.java
+++ b/src/main/java/com/android/tools/r8/optimize/VisibilityBridgeRemover.java
@@ -30,7 +30,7 @@
   private void identifyBridgeMethod(DexEncodedMethod method) {
     if (method.accessFlags.isBridge()) {
       InvokeSingleTargetExtractor targetExtractor = new InvokeSingleTargetExtractor();
-      method.getCode().registerReachableDefinitions(targetExtractor);
+      method.getCode().registerInstructionsReferences(targetExtractor);
       DexMethod target = targetExtractor.getTarget();
       InvokeKind kind = targetExtractor.getKind();
       if (target != null &&
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 0bd3068..9aff920 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -1119,7 +1119,7 @@
       if (protoLiteExtension != null && protoLiteExtension.appliesTo(method)) {
         protoLiteExtension.processMethod(method, new UseRegistry(method), protoLiteFields);
       } else {
-        method.registerReachableDefinitions(new UseRegistry(method));
+        method.registerInstructionsReferences(new UseRegistry(method));
       }
       // Add all dependent members to the workqueue.
       enqueueRootItems(rootSet.getDependentItems(method));
diff --git a/src/main/java/com/android/tools/r8/shaking/MainDexListBuilder.java b/src/main/java/com/android/tools/r8/shaking/MainDexListBuilder.java
index f8b54ab..de21187 100644
--- a/src/main/java/com/android/tools/r8/shaking/MainDexListBuilder.java
+++ b/src/main/java/com/android/tools/r8/shaking/MainDexListBuilder.java
@@ -151,7 +151,8 @@
       clazz.forEachField(field -> addMainDexType(field.field.type));
       clazz.forEachMethod(method -> {
         traceMethodDirectDependencies(method.method);
-        method.registerReachableDefinitions(codeDirectReferenceCollector);
+        method.registerInstructionsReferences(codeDirectReferenceCollector);
+        method.registerCatchedTypes(this::addMainDexType);
       });
     }
   }
diff --git a/src/main/java/com/android/tools/r8/shaking/SimpleClassMerger.java b/src/main/java/com/android/tools/r8/shaking/SimpleClassMerger.java
index 02159cf..63475b7 100644
--- a/src/main/java/com/android/tools/r8/shaking/SimpleClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/SimpleClassMerger.java
@@ -371,7 +371,7 @@
         return existing;
       } else if (existing.accessFlags.isBridge()) {
         InvokeSingleTargetExtractor extractor = new InvokeSingleTargetExtractor();
-        existing.getCode().registerReachableDefinitions(extractor);
+        existing.getCode().registerInstructionsReferences(extractor);
         if (extractor.getTarget() != method.method) {
           abortMerge = true;
         }
diff --git a/src/main/java/com/android/tools/r8/shaking/protolite/ProtoLiteExtension.java b/src/main/java/com/android/tools/r8/shaking/protolite/ProtoLiteExtension.java
index 8049bf4..c2ba7e5 100644
--- a/src/main/java/com/android/tools/r8/shaking/protolite/ProtoLiteExtension.java
+++ b/src/main/java/com/android/tools/r8/shaking/protolite/ProtoLiteExtension.java
@@ -116,13 +116,13 @@
       // serialized stream for this proto. As we mask all reads in the writing code and normally
       // remove fields that are only written but never read, we have to mark fields used in setters
       // as read and written.
-      method.registerReachableDefinitions(
+      method.registerInstructionsReferences(
           new FieldWriteImpliesReadUseRegistry(registry, method.method.holder));
     } else {
       // Filter all getters and field accesses in these methods. We do not want fields to become
       // live just due to being referenced in a special method. The pruning phase will remove
       // all references to dead fields in the code later.
-      method.registerReachableDefinitions(new FilteringUseRegistry(registry, method.method.holder,
+      method.registerInstructionsReferences(new FilteringUseRegistry(registry, method.method.holder,
           protoLiteFields));
     }
   }
diff --git a/src/test/examples/multidex006/ClassForMainDex.java b/src/test/examples/multidex006/ClassForMainDex.java
new file mode 100644
index 0000000..86c2e9a
--- /dev/null
+++ b/src/test/examples/multidex006/ClassForMainDex.java
@@ -0,0 +1,25 @@
+// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package multidex006;
+
+/**
+ * Class directly referenced from Activity, will be kept in main dex. The class is not referenced
+ * by <clinit> or <init>, its direct references are not kept in main dex.
+ */
+public class ClassForMainDex {
+
+  public static void method1() {
+    try {
+      doNothing();
+    } catch (NotThrownException e) {
+      // ignore
+    }
+  }
+
+  public static void doNothing() {
+
+  }
+
+}
diff --git a/src/test/examples/multidex006/NotThrownException.java b/src/test/examples/multidex006/NotThrownException.java
new file mode 100644
index 0000000..4aa5e6c
--- /dev/null
+++ b/src/test/examples/multidex006/NotThrownException.java
@@ -0,0 +1,8 @@
+// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package multidex006;
+
+public class NotThrownException extends RuntimeException {
+}
diff --git a/src/test/examples/multidex006/main-dex-rules-1.txt b/src/test/examples/multidex006/main-dex-rules-1.txt
new file mode 100644
index 0000000..333d866
--- /dev/null
+++ b/src/test/examples/multidex006/main-dex-rules-1.txt
@@ -0,0 +1,6 @@
+# Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+-keep public class *.ClassForMainDex {
+}
\ No newline at end of file
diff --git a/src/test/examples/multidex006/ref-list-1.txt b/src/test/examples/multidex006/ref-list-1.txt
new file mode 100644
index 0000000..b39deba
--- /dev/null
+++ b/src/test/examples/multidex006/ref-list-1.txt
@@ -0,0 +1,2 @@
+Lmultidex006/ClassForMainDex;
+Lmultidex006/NotThrownException;
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexTracingTest.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexTracingTest.java
index 8b143da..19aaaef 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexTracingTest.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexTracingTest.java
@@ -124,6 +124,17 @@
     doTest5(6);
   }
 
+  @Test
+  public void traceMainDexList006() throws Throwable {
+    doTest(
+        "traceMainDexList006",
+        "multidex006",
+        EXAMPLE_BUILD_DIR,
+        Paths.get(EXAMPLE_SRC_DIR, "multidex006", "main-dex-rules-1.txt"),
+        Paths.get(EXAMPLE_SRC_DIR, "multidex006", "ref-list-1.txt"),
+        AndroidApiLevel.I);
+  }
+
   private void doTest5(int variant) throws Throwable {
     doTest(
         "traceMainDexList003",
@@ -211,9 +222,15 @@
       int nonLambdaOffset = 0;
       for (int i = 0; i < refList.length; i++) {
         String reference = refList[i].trim();
+        if (r8MainDexList.size() <= i) {
+          Assert.fail("R8 main dex list is missing '" + reference + "'");
+        }
         checkSameMainDexEntry(reference, r8MainDexList.get(i));
         // The main dex list generator does not do any lambda desugaring.
         if (!isLambda(reference)) {
+          if (mainDexGeneratorMainDexList.size() <= i - nonLambdaOffset) {
+            Assert.fail("Main dex list generator is missing '" + reference + "'");
+          }
           checkSameMainDexEntry(reference, mainDexGeneratorMainDexList.get(i - nonLambdaOffset));
         } else {
           nonLambdaOffset++;