Version 2.1.42

Cherry-pick: Use compat mode for shrinking the desugared library
CL: https://r8-review.googlesource.com/c/r8/+/52143

Cherry-pick: Collect desugared library types used in check-cast and instanceof
CL: https://r8-review.googlesource.com/c/r8/+/52140

Cherry-pick: Collect desugared library exception types used in try/catch
CL: https://r8-review.googlesource.com/c/r8/+/52124

Cherry-pick: Provide access to try/catch guards in code inspector
CL: https://r8-review.googlesource.com/c/r8/+/52123

Cherry-pick: Add reproduction of duplicate methods due to staticizer
CL: https://r8-review.googlesource.com/52125

Cherry-pick: Disable moving not processed members to host for
staticizer
CL: https://r8-review.googlesource.com/52142

Bug: 158815562
Bug: 158417777
Bug: 157966650
Bug: 158018192
Change-Id: I32cdfc36dd24db48deb4b3e692bbbbb68d89a28e
diff --git a/src/main/java/com/android/tools/r8/L8Command.java b/src/main/java/com/android/tools/r8/L8Command.java
index b1072df..93d688d 100644
--- a/src/main/java/com/android/tools/r8/L8Command.java
+++ b/src/main/java/com/android/tools/r8/L8Command.java
@@ -291,7 +291,7 @@
 
       if (isShrinking()) {
         R8Command.Builder r8Builder =
-            R8Command.builder(getReporter())
+            new CompatProguardCommandBuilder(true, getReporter())
                 .addProgramResourceProvider(desugaredLibrary)
                 .setSynthesizedClassesPrefix(
                     libraryConfiguration.getSynthesizedLibraryClassesPackagePrefix())
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index 04e1817..b315555 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 = "2.1.41";
+  public static final String LABEL = "2.1.42";
 
   private Version() {
   }
diff --git a/src/main/java/com/android/tools/r8/code/CheckCast.java b/src/main/java/com/android/tools/r8/code/CheckCast.java
index 57151fa..f472800 100644
--- a/src/main/java/com/android/tools/r8/code/CheckCast.java
+++ b/src/main/java/com/android/tools/r8/code/CheckCast.java
@@ -38,6 +38,11 @@
   }
 
   @Override
+  public CheckCast asCheckCast() {
+    return this;
+  }
+
+  @Override
   public boolean isCheckCast() {
     return true;
   }
diff --git a/src/main/java/com/android/tools/r8/code/InstanceOf.java b/src/main/java/com/android/tools/r8/code/InstanceOf.java
index 11b2d5c..4550406 100644
--- a/src/main/java/com/android/tools/r8/code/InstanceOf.java
+++ b/src/main/java/com/android/tools/r8/code/InstanceOf.java
@@ -23,6 +23,16 @@
   }
 
   @Override
+  public InstanceOf asInstanceOf() {
+    return this;
+  }
+
+  @Override
+  public boolean isInstanceOf() {
+    return true;
+  }
+
+  @Override
   public String getName() {
     return NAME;
   }
diff --git a/src/main/java/com/android/tools/r8/code/Instruction.java b/src/main/java/com/android/tools/r8/code/Instruction.java
index b6b1f9c..86abac6 100644
--- a/src/main/java/com/android/tools/r8/code/Instruction.java
+++ b/src/main/java/com/android/tools/r8/code/Instruction.java
@@ -127,10 +127,22 @@
     this.offset = offset;
   }
 
+  public CheckCast asCheckCast() {
+    return null;
+  }
+
   public boolean isCheckCast() {
     return false;
   }
 
+  public InstanceOf asInstanceOf() {
+    return null;
+  }
+
+  public boolean isInstanceOf() {
+    return false;
+  }
+
   public ConstString asConstString() {
     return null;
   }
diff --git a/src/main/java/com/android/tools/r8/dex/DexOutputBuffer.java b/src/main/java/com/android/tools/r8/dex/DexOutputBuffer.java
index ef1b81b..037d769 100644
--- a/src/main/java/com/android/tools/r8/dex/DexOutputBuffer.java
+++ b/src/main/java/com/android/tools/r8/dex/DexOutputBuffer.java
@@ -112,6 +112,10 @@
         desugaredLibraryCodeToKeep.recordMethod(method);
       } else if (insn.isConstClass()) {
         desugaredLibraryCodeToKeep.recordClass(insn.asConstClass().getType());
+      } else if (insn.isInstanceOf()) {
+        desugaredLibraryCodeToKeep.recordClass(insn.asInstanceOf().getType());
+      } else if (insn.isCheckCast()) {
+        desugaredLibraryCodeToKeep.recordClass(insn.asCheckCast().getType());
       }
       insn.write(shortBuffer, mapping);
     }
diff --git a/src/main/java/com/android/tools/r8/dex/FileWriter.java b/src/main/java/com/android/tools/r8/dex/FileWriter.java
index 867f32d..0047bf8 100644
--- a/src/main/java/com/android/tools/r8/dex/FileWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/FileWriter.java
@@ -519,6 +519,7 @@
         for (TypeAddrPair pair : handler.pairs) {
           dest.putUleb128(mapping.getOffsetFor(pair.type));
           dest.putUleb128(pair.addr);
+          desugaredLibraryCodeToKeep.recordClass(pair.type);
         }
         if (hasCatchAll) {
           dest.putUleb128(handler.catchAllAddr);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java
index 0e0e1c9..4cc6fdf 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java
@@ -6,6 +6,7 @@
 
 import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
 import static com.android.tools.r8.ir.analysis.type.Nullability.maybeNull;
+import static com.android.tools.r8.utils.PredicateUtils.not;
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DebugLocalInfo;
@@ -758,7 +759,8 @@
       if (candidateClass.type != hostType) {
         DexProgramClass hostClass = asProgramClassOrNull(appView.definitionFor(hostType));
         assert hostClass != null;
-        if (!classMembersConflict(candidateClass, hostClass)) {
+        if (!classMembersConflict(candidateClass, hostClass)
+            && !hasMembersNotStaticized(candidateClass, staticizedMethods)) {
           // Move all members of the candidate class into host class.
           moveMembersIntoHost(staticizedMethods,
               candidateClass, hostType, hostClass, methodMapping, fieldMapping);
@@ -779,6 +781,16 @@
         || Streams.stream(a.methods()).anyMatch(method -> b.lookupMethod(method.method) != null);
   }
 
+  private boolean hasMembersNotStaticized(
+      DexProgramClass candidateClass, ProgramMethodSet staticizedMethods) {
+    // TODO(b/159174309): Refine the analysis to allow for fields.
+    if (candidateClass.hasFields()) {
+      return true;
+    }
+    // TODO(b/158018192): Activate again when picking up all references.
+    return candidateClass.methods(not(staticizedMethods::contains)).iterator().hasNext();
+  }
+
   private void moveMembersIntoHost(
       ProgramMethodSet staticizedMethods,
       DexProgramClass candidateClass,
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaTimeTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaTimeTest.java
index 3cb6218..23d3658 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaTimeTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaTimeTest.java
@@ -6,18 +6,26 @@
 
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
 
+import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.CheckCastInstructionSubject;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import com.android.tools.r8.utils.codeinspector.InvokeInstructionSubject;
-import java.util.Iterator;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import com.android.tools.r8.utils.codeinspector.TryCatchSubject;
+import com.android.tools.r8.utils.codeinspector.TypeSubject;
+import com.google.common.collect.ImmutableSet;
 import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -28,7 +36,8 @@
 
   private final TestParameters parameters;
   private final boolean shrinkDesugaredLibrary;
-  private static final String expectedOutput = StringUtils.lines("Hello, world");
+  private static final String expectedOutput =
+      StringUtils.lines("Caught java.time.format.DateTimeParseException", "true", "Hello, world");
 
   @Parameters(name = "{1}, shrinkDesugaredLibrary: {0}")
   public static List<Object[]> data() {
@@ -47,15 +56,52 @@
   }
 
   private void checkRewrittenInvokes(CodeInspector inspector) {
+    Set<String> expectedInvokeHolders;
+    Set<String> expectedCatchGuards;
+    Set<String> expectedCheckCastType;
+    String expectedInstanceOfTypes;
     if (parameters.getApiLevel().getLevel() >= 26) {
-      return;
+      expectedInvokeHolders =
+          ImmutableSet.of("java.time.Clock", "java.time.LocalDate", "java.time.ZoneOffset");
+      expectedCatchGuards = ImmutableSet.of("java.time.format.DateTimeParseException");
+      expectedCheckCastType = ImmutableSet.of("java.time.ZoneId");
+      expectedInstanceOfTypes = "java.time.ZoneOffset";
+    } else {
+      expectedInvokeHolders =
+          ImmutableSet.of("j$.time.Clock", "j$.time.LocalDate", "j$.time.ZoneOffset");
+      expectedCatchGuards = ImmutableSet.of("j$.time.format.DateTimeParseException");
+      expectedCheckCastType = ImmutableSet.of("j$.time.ZoneId");
+      expectedInstanceOfTypes = "j$.time.ZoneOffset";
     }
     ClassSubject classSubject = inspector.clazz(TestClass.class);
     assertThat(classSubject, isPresent());
-    Iterator<InvokeInstructionSubject> iterator =
-        classSubject.uniqueMethodWithName("main").iterateInstructions(InstructionSubject::isInvoke);
-    InvokeInstructionSubject invoke = iterator.next();
-    assertTrue(invoke.holder().is("j$.time.Clock"));
+    MethodSubject main = classSubject.uniqueMethodWithName("main");
+    Set<String> foundInvokeHolders =
+        main.streamInstructions()
+            .filter(InstructionSubject::isInvoke)
+            .map(
+                instructionSubject ->
+                    ((InvokeInstructionSubject) instructionSubject).holder().toString())
+            .filter(holder -> holder.startsWith("j$.time.") || holder.startsWith("java.time."))
+            .collect(Collectors.toSet());
+    assertEquals(expectedInvokeHolders, foundInvokeHolders);
+    main.streamInstructions()
+        .filter(InstructionSubject::isCheckCast)
+        .map(InstructionSubject::asCheckCast)
+        .map(CheckCastInstructionSubject::getType)
+        .map(DexType::toSourceString)
+        .collect(Collectors.toSet())
+        .equals(expectedCheckCastType);
+    assertEquals(
+        1,
+        main.streamInstructions().filter(io -> io.isInstanceOf(expectedInstanceOfTypes)).count());
+
+    Set<String> foundCatchGuards =
+        main.streamTryCatches()
+            .flatMap(TryCatchSubject::streamGuards)
+            .map(TypeSubject::toString)
+            .collect(Collectors.toSet());
+    assertEquals(expectedCatchGuards, foundCatchGuards);
   }
 
   @Test
@@ -84,6 +130,7 @@
         .addKeepMainRule(TestClass.class)
         .setMinApi(parameters.getApiLevel())
         .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
+        .enableInliningAnnotations()
         .compile()
         .inspect(this::checkRewrittenInvokes)
         .addDesugaredCoreLibraryRunClassPath(
@@ -97,8 +144,28 @@
 
   static class TestClass {
 
+    @NeverInline
+    public static Object newObjectInstance() {
+      return System.currentTimeMillis() > 0 ? new Object() : null;
+    }
+
+    @NeverInline
+    public static Object nullReference() {
+      return System.currentTimeMillis() > 0 ? null : new Object();
+    }
+
     public static void main(String[] args) {
       java.time.Clock.systemDefaultZone();
+      try {
+        java.time.LocalDate.parse("");
+      } catch (java.time.format.DateTimeParseException e) {
+        System.out.println("Caught java.time.format.DateTimeParseException");
+      }
+      java.time.ZoneId id = (java.time.ZoneId) nullReference();
+      if (newObjectInstance() instanceof java.time.ZoneOffset) {
+        System.out.println("NOT!");
+      }
+      System.out.println(java.time.ZoneOffset.getAvailableZoneIds().size() > 0);
       System.out.println("Hello, world");
     }
   }
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/staticizer/HostWithStaticMethodTest.java b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/HostWithStaticMethodTest.java
new file mode 100644
index 0000000..0fcb3ee
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/HostWithStaticMethodTest.java
@@ -0,0 +1,81 @@
+// Copyright (c) 2020, 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 com.android.tools.r8.ir.optimize.staticizer;
+
+import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ir.optimize.staticizer.HostWithStaticMethodTest.Outer.SingletonHolder;
+import java.io.IOException;
+import java.util.concurrent.ExecutionException;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+// This is a reproduction of b/158018192.
+public class HostWithStaticMethodTest extends TestBase {
+
+  private final TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  public HostWithStaticMethodTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Test
+  public void testR8() throws ExecutionException, CompilationFailedException, IOException {
+    testForR8(parameters.getBackend())
+        .addProgramClasses(Outer.class, SingletonHolder.class, Main.class)
+        .addKeepMainRule(Main.class)
+        .setMinApi(parameters.getApiLevel())
+        .enableNeverClassInliningAnnotations()
+        .enableInliningAnnotations()
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutputLines("foo", "bar", "foo");
+  }
+
+  @NeverClassInline
+  public static class Outer {
+
+    public static class SingletonHolder {
+
+      public static final Outer outer = new Outer();
+
+      @NeverInline
+      // This method should not be in conflict with any methods in Outer.
+      public static void foo2() {
+        foo();
+      }
+    }
+
+    @NeverInline
+    public static void foo() {
+      System.out.println("foo");
+    }
+
+    @NeverInline
+    public void bar() {
+      System.out.println("bar");
+    }
+  }
+
+  public static class Main {
+
+    public static void main(String[] args) {
+      Outer.foo();
+      SingletonHolder.outer.bar();
+      SingletonHolder.foo2();
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/staticizer/InstanceInsideCompanionTest.java b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/InstanceInsideCompanionTest.java
index f28235b..5dabfaf 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/staticizer/InstanceInsideCompanionTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/InstanceInsideCompanionTest.java
@@ -46,8 +46,9 @@
         .enableNeverClassInliningAnnotations()
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), MAIN)
-        .assertSuccessWithOutputLines("Candidate#foo(false)")
-        .inspect(this::inspect);
+        .assertSuccessWithOutputLines("Candidate#foo(false)");
+    // TODO(b/159174309): Disable inspection until fixed.
+    // .inspect(this::inspect);
   }
 
   private void inspect(CodeInspector inspector) {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/staticizer/InvokeStaticWithNullOutvalueTest.java b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/InvokeStaticWithNullOutvalueTest.java
index e552581..4e3f691 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/staticizer/InvokeStaticWithNullOutvalueTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/InvokeStaticWithNullOutvalueTest.java
@@ -59,11 +59,13 @@
     assertThat(instance, not(isPresent()));
 
     ClassSubject companion = inspector.clazz(Host.Companion.class);
-    assertThat(companion, not(isPresent()));
+    // TODO(b/158018192): This should not be present.
+    assertThat(companion, isPresent());
 
     // Check if the candidate methods are staticized (if necessary) and migrated.
     for (String name : ImmutableList.of("boo", "foo")) {
-      MethodSubject oo = host.uniqueMethodWithName(name);
+      // TODO(b/158018192): This should be host and not companion.
+      MethodSubject oo = companion.uniqueMethodWithName(name);
       assertThat(oo, isPresent());
       assertTrue(oo.isStatic());
       assertTrue(
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/CfTryCatchSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/CfTryCatchSubject.java
index 3e47f3b..d6bac64 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/CfTryCatchSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/CfTryCatchSubject.java
@@ -11,12 +11,17 @@
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
+import java.util.Collection;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 class CfTryCatchSubject implements TryCatchSubject {
+  private final CodeInspector inspector;
   private final CfCode cfCode;
   private final CfTryCatch tryCatch;
 
-  CfTryCatchSubject(CfCode cfCode, CfTryCatch tryCatch) {
+  CfTryCatchSubject(CodeInspector inspector, CfCode cfCode, CfTryCatch tryCatch) {
+    this.inspector = inspector;
     this.cfCode = cfCode;
     this.tryCatch = tryCatch;
   }
@@ -62,6 +67,16 @@
   }
 
   @Override
+  public Stream<TypeSubject> streamGuards() {
+    return tryCatch.guards.stream().map(type -> new TypeSubject(inspector, type));
+  }
+
+  @Override
+  public Collection<TypeSubject> guards() {
+    return streamGuards().collect(Collectors.toList());
+  }
+
+  @Override
   public int getNumberOfHandlers() {
     return tryCatch.guards.size();
   }
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java b/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
index b2edae2..3cfbb22 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
@@ -386,11 +386,11 @@
   }
 
   TryCatchSubject createTryCatchSubject(DexCode code, Try tryElement, TryHandler tryHandler) {
-    return new DexTryCatchSubject(code, tryElement, tryHandler);
+    return new DexTryCatchSubject(this, code, tryElement, tryHandler);
   }
 
   TryCatchSubject createTryCatchSubject(CfCode code, CfTryCatch tryCatch) {
-    return new CfTryCatchSubject(code, tryCatch);
+    return new CfTryCatchSubject(this, code, tryCatch);
   }
 
   TryCatchIterator createTryCatchIterator(MethodSubject method) {
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/DexTryCatchSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/DexTryCatchSubject.java
index 4a96ff1..4624c33 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/DexTryCatchSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/DexTryCatchSubject.java
@@ -9,13 +9,20 @@
 import com.android.tools.r8.graph.DexCode.Try;
 import com.android.tools.r8.graph.DexCode.TryHandler;
 import com.android.tools.r8.graph.DexCode.TryHandler.TypeAddrPair;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 class DexTryCatchSubject implements TryCatchSubject {
+  private final CodeInspector inspector;
   private final DexCode dexCode;
   private final Try tryElement;
   private final TryHandler tryHandler;
 
-  DexTryCatchSubject(DexCode dexCode, Try tryElement, TryHandler tryHandler) {
+  DexTryCatchSubject(
+      CodeInspector inspector, DexCode dexCode, Try tryElement, TryHandler tryHandler) {
+    this.inspector = inspector;
     this.dexCode = dexCode;
     this.tryElement = tryElement;
     this.tryHandler = tryHandler;
@@ -45,6 +52,18 @@
   }
 
   @Override
+  public Stream<TypeSubject> streamGuards() {
+    return Arrays.stream(tryHandler.pairs)
+        .map(pair -> pair.type)
+        .map(type -> new TypeSubject(inspector, type));
+  }
+
+  @Override
+  public Collection<TypeSubject> guards() {
+    return streamGuards().collect(Collectors.toList());
+  }
+
+  @Override
   public int getNumberOfHandlers() {
     if (tryHandler.catchAllAddr != NO_HANDLER) {
       return tryHandler.pairs.length + 1;
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java
index b158404..72b71b0 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java
@@ -89,6 +89,10 @@
     return Streams.stream(iterateInstructions());
   }
 
+  public Stream<TryCatchSubject> streamTryCatches() {
+    return Streams.stream(iterateTryCatches());
+  }
+
   public void getLineNumberForInstruction(InstructionSubject subject) {
     assert hasLineNumberTable();
     getLineNumberTable().getLineForInstruction(subject);
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/TryCatchSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/TryCatchSubject.java
index 73e9ef1..d34f4e9 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/TryCatchSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/TryCatchSubject.java
@@ -3,10 +3,17 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.utils.codeinspector;
 
+import java.util.Collection;
+import java.util.stream.Stream;
+
 public interface TryCatchSubject {
   RangeSubject getRange();
   boolean isCatching(String exceptionType);
   boolean hasCatchAll();
 
+  Stream<TypeSubject> streamGuards();
+
+  Collection<TypeSubject> guards();
+
   int getNumberOfHandlers();
 }