Merge commit '1ca046cd32f799037e856a633fbc632b4392d449' into dev-release
diff --git a/src/library_desugar/desugar_jdk_libs.json b/src/library_desugar/desugar_jdk_libs.json
index 0ba3777..a859aa1 100644
--- a/src/library_desugar/desugar_jdk_libs.json
+++ b/src/library_desugar/desugar_jdk_libs.json
@@ -251,6 +251,7 @@
     "-keepclassmembers class j$.util.DoubleSummaryStatistics { long count; double sum; double min; double max; }",
     "-keepattributes Signature",
     "-keepattributes EnclosingMethod",
-    "-keepattributes InnerClasses"
+    "-keepattributes InnerClasses",
+    "-dontwarn sun.misc.Unsafe"
   ]
 }
diff --git a/src/main/dontwarn.txt b/src/main/dontwarn.txt
new file mode 100644
index 0000000..42afa1d
--- /dev/null
+++ b/src/main/dontwarn.txt
@@ -0,0 +1,4 @@
+# TODO(b/176783536): Avoid need to use -dontwarn.
+-dontwarn com.google.errorprone.annotations.**
+-dontwarn com.google.j2objc.annotations.*
+-dontwarn javax.annotation.Nullable
diff --git a/src/main/java/com/android/tools/r8/cf/CfPrinter.java b/src/main/java/com/android/tools/r8/cf/CfPrinter.java
index 92930b0..09f14ce 100644
--- a/src/main/java/com/android/tools/r8/cf/CfPrinter.java
+++ b/src/main/java/com/android/tools/r8/cf/CfPrinter.java
@@ -395,10 +395,12 @@
     builder.append(opcodeName(Opcodes.INVOKEDYNAMIC)).append(' ');
     builder.append(callSite.methodName);
     builder.append(callSite.methodProto.toDescriptorString());
-    DexMethodHandle handle = callSite.bootstrapArgs.get(1).asDexValueMethodHandle().getValue();
-    builder.append(", handle:");
-    builder.append(handle.toSourceString());
-    builder.append(", itf: ").append(handle.isInterface);
+    if (callSite.bootstrapArgs.size() > 1) {
+      DexMethodHandle handle = callSite.bootstrapArgs.get(1).asDexValueMethodHandle().getValue();
+      builder.append(", handle:");
+      builder.append(handle.toSourceString());
+      builder.append(", itf: ").append(handle.isInterface);
+    }
     builder.append(", bsm:");
     appendMethod(bootstrapMethod.asMethod());
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java b/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java
index 42844fd..c69ba09 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java
@@ -153,6 +153,10 @@
     return false;
   }
 
+  public boolean isInvokeStatic() {
+    return false;
+  }
+
   public CfLabel asLabel() {
     return null;
   }
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java b/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
index 5cc4435..db81a5f 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
@@ -180,6 +180,7 @@
     return opcode == Opcodes.INVOKESPECIAL;
   }
 
+  @Override
   public boolean isInvokeStatic() {
     return opcode == Opcodes.INVOKESTATIC;
   }
diff --git a/src/main/java/com/android/tools/r8/contexts/CompilationContext.java b/src/main/java/com/android/tools/r8/contexts/CompilationContext.java
index aa3247c..b2cc211 100644
--- a/src/main/java/com/android/tools/r8/contexts/CompilationContext.java
+++ b/src/main/java/com/android/tools/r8/contexts/CompilationContext.java
@@ -137,6 +137,10 @@
       return method.getHolder();
     }
 
+    public ProgramMethod getMethodContext() {
+      return method;
+    }
+
     private StringBuilder buildSuffix(StringBuilder builder) {
       // TODO(b/172194101): Sanitize the method descriptor instead of hashing.
       Hasher hasher = Hashing.sha256().newHasher();
diff --git a/src/main/java/com/android/tools/r8/diagnostic/MissingClassInfo.java b/src/main/java/com/android/tools/r8/diagnostic/MissingClassInfo.java
new file mode 100644
index 0000000..41f255a
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/diagnostic/MissingClassInfo.java
@@ -0,0 +1,25 @@
+// Copyright (c) 2021, 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.diagnostic;
+
+import com.android.tools.r8.Keep;
+import com.android.tools.r8.references.ClassReference;
+
+@Keep
+public interface MissingClassInfo extends MissingDefinitionInfo {
+
+  /** Returns the reference of the missing class. */
+  ClassReference getClassReference();
+
+  @Override
+  default boolean isMissingClass() {
+    return true;
+  }
+
+  @Override
+  default MissingClassInfo asMissingClass() {
+    return this;
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/diagnostic/MissingDefinitionClassContext.java b/src/main/java/com/android/tools/r8/diagnostic/MissingDefinitionClassContext.java
new file mode 100644
index 0000000..1b73b9f
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/diagnostic/MissingDefinitionClassContext.java
@@ -0,0 +1,25 @@
+// Copyright (c) 2021, 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.diagnostic;
+
+import com.android.tools.r8.Keep;
+import com.android.tools.r8.references.ClassReference;
+
+@Keep
+public interface MissingDefinitionClassContext extends MissingDefinitionContext {
+
+  /** Returns the reference of the class context. */
+  ClassReference getClassReference();
+
+  @Override
+  default boolean isClassContext() {
+    return true;
+  }
+
+  @Override
+  default MissingDefinitionClassContext asClassContext() {
+    return this;
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/diagnostic/MissingDefinitionContext.java b/src/main/java/com/android/tools/r8/diagnostic/MissingDefinitionContext.java
index 268c7cc..cb5d3b4 100644
--- a/src/main/java/com/android/tools/r8/diagnostic/MissingDefinitionContext.java
+++ b/src/main/java/com/android/tools/r8/diagnostic/MissingDefinitionContext.java
@@ -6,15 +6,56 @@
 
 import com.android.tools.r8.Keep;
 import com.android.tools.r8.origin.Origin;
-import com.android.tools.r8.references.ClassReference;
 
 /** A context that references a missing definition in the program, classpath, or library. */
 @Keep
 public interface MissingDefinitionContext {
 
-  /** The class context from which a missing definition is referenced. */
-  ClassReference getClassReference();
-
   /** The origin of the context. */
   Origin getOrigin();
+
+  /** Predicate that is true iff this is an instance of {@link MissingDefinitionClassContext}. */
+  default boolean isClassContext() {
+    return false;
+  }
+
+  /** Predicate that is true iff this is an instance of {@link MissingDefinitionFieldContext}. */
+  default boolean isFieldContext() {
+    return false;
+  }
+
+  /** Predicate that is true iff this is an instance of {@link MissingDefinitionMethodContext}. */
+  default boolean isMethodContext() {
+    return false;
+  }
+
+  /**
+   * Return a non-null {@link MissingDefinitionClassContext} if this type is {@link
+   * MissingDefinitionClassContext}.
+   *
+   * @return this with static type of {@link MissingDefinitionClassContext}.
+   */
+  default MissingDefinitionClassContext asClassContext() {
+    return null;
+  }
+
+  /**
+   * Return a non-null {@link MissingDefinitionFieldContext} if this type is {@link
+   * MissingDefinitionFieldContext}.
+   *
+   * @return this with static type of {@link MissingDefinitionFieldContext}.
+   */
+  default MissingDefinitionFieldContext asFieldContext() {
+    return null;
+  }
+
+  /**
+   * Return a non-null {@link MissingDefinitionMethodContext} if this type is {@link
+   * MissingDefinitionMethodContext}.
+   *
+   * @return this with static type of {@link MissingDefinitionMethodContext}.
+   */
+  default MissingDefinitionMethodContext asMethodContext() {
+    return null;
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/diagnostic/MissingDefinitionFieldContext.java b/src/main/java/com/android/tools/r8/diagnostic/MissingDefinitionFieldContext.java
new file mode 100644
index 0000000..7564f5a
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/diagnostic/MissingDefinitionFieldContext.java
@@ -0,0 +1,25 @@
+// Copyright (c) 2021, 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.diagnostic;
+
+import com.android.tools.r8.Keep;
+import com.android.tools.r8.references.FieldReference;
+
+@Keep
+public interface MissingDefinitionFieldContext extends MissingDefinitionContext {
+
+  /** Returns the reference of the field context. */
+  FieldReference getFieldReference();
+
+  @Override
+  default boolean isFieldContext() {
+    return true;
+  }
+
+  @Override
+  default MissingDefinitionFieldContext asFieldContext() {
+    return this;
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/diagnostic/MissingDefinitionInfo.java b/src/main/java/com/android/tools/r8/diagnostic/MissingDefinitionInfo.java
index ea8def0..c2905ce 100644
--- a/src/main/java/com/android/tools/r8/diagnostic/MissingDefinitionInfo.java
+++ b/src/main/java/com/android/tools/r8/diagnostic/MissingDefinitionInfo.java
@@ -13,6 +13,57 @@
 @Keep
 public interface MissingDefinitionInfo {
 
+  /**
+   * Predicate that is true iff the MissingDefinitionInfo is an instance of {@link
+   * MissingClassInfo}.
+   */
+  default boolean isMissingClass() {
+    return false;
+  }
+
+  /**
+   * Predicate that is true iff the MissingDefinitionInfo is an instance of {@link
+   * MissingFieldInfo}.
+   */
+  default boolean isMissingField() {
+    return false;
+  }
+
+  /**
+   * Predicate that is true iff the MissingDefinitionInfo is an instance of {@link
+   * MissingMethodInfo}.
+   */
+  default boolean isMissingMethod() {
+    return false;
+  }
+
+  /**
+   * Return a non-null {@link MissingClassInfo} if this type is {@link MissingClassInfo}.
+   *
+   * @return this with static type of {@link MissingClassInfo}.
+   */
+  default MissingClassInfo asMissingClass() {
+    return null;
+  }
+
+  /**
+   * Return a non-null {@link MissingFieldInfo} if this type is {@link MissingFieldInfo}.
+   *
+   * @return this with static type of {@link MissingFieldInfo}.
+   */
+  default MissingFieldInfo asMissingField() {
+    return null;
+  }
+
+  /**
+   * Return a non-null {@link MissingMethodInfo} if this type is {@link MissingMethodInfo}.
+   *
+   * @return this with static type of {@link MissingMethodInfo}.
+   */
+  default MissingMethodInfo asMissingMethod() {
+    return null;
+  }
+
   /** The contexts from which this missing definition was referenced. */
   Collection<MissingDefinitionContext> getReferencedFromContexts();
 }
diff --git a/src/main/java/com/android/tools/r8/diagnostic/MissingDefinitionMethodContext.java b/src/main/java/com/android/tools/r8/diagnostic/MissingDefinitionMethodContext.java
new file mode 100644
index 0000000..315a29c
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/diagnostic/MissingDefinitionMethodContext.java
@@ -0,0 +1,25 @@
+// Copyright (c) 2021, 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.diagnostic;
+
+import com.android.tools.r8.Keep;
+import com.android.tools.r8.references.MethodReference;
+
+@Keep
+public interface MissingDefinitionMethodContext extends MissingDefinitionContext {
+
+  /** Returns the reference of the method context. */
+  MethodReference getMethodReference();
+
+  @Override
+  default boolean isMethodContext() {
+    return true;
+  }
+
+  @Override
+  default MissingDefinitionMethodContext asMethodContext() {
+    return this;
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/diagnostic/MissingFieldInfo.java b/src/main/java/com/android/tools/r8/diagnostic/MissingFieldInfo.java
new file mode 100644
index 0000000..1ae6df1
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/diagnostic/MissingFieldInfo.java
@@ -0,0 +1,25 @@
+// Copyright (c) 2021, 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.diagnostic;
+
+import com.android.tools.r8.Keep;
+import com.android.tools.r8.references.FieldReference;
+
+@Keep
+public interface MissingFieldInfo extends MissingDefinitionInfo {
+
+  /** Returns the reference of the missing field. */
+  FieldReference getFieldReference();
+
+  @Override
+  default boolean isMissingField() {
+    return true;
+  }
+
+  @Override
+  default MissingFieldInfo asMissingField() {
+    return this;
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/diagnostic/MissingMethodInfo.java b/src/main/java/com/android/tools/r8/diagnostic/MissingMethodInfo.java
new file mode 100644
index 0000000..3cf8cc0
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/diagnostic/MissingMethodInfo.java
@@ -0,0 +1,25 @@
+// Copyright (c) 2021, 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.diagnostic;
+
+import com.android.tools.r8.Keep;
+import com.android.tools.r8.references.MethodReference;
+
+@Keep
+public interface MissingMethodInfo extends MissingDefinitionInfo {
+
+  /** Returns the reference of the missing method. */
+  MethodReference getMethodReference();
+
+  @Override
+  default boolean isMissingMethod() {
+    return true;
+  }
+
+  @Override
+  default MissingMethodInfo asMissingMethod() {
+    return this;
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/diagnostic/internal/MissingClassAccessContexts.java b/src/main/java/com/android/tools/r8/diagnostic/internal/MissingClassAccessContexts.java
index 3406c0d..23abebb 100644
--- a/src/main/java/com/android/tools/r8/diagnostic/internal/MissingClassAccessContexts.java
+++ b/src/main/java/com/android/tools/r8/diagnostic/internal/MissingClassAccessContexts.java
@@ -10,6 +10,7 @@
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexReference;
 import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramDerivedContext;
 import com.android.tools.r8.references.ClassReference;
 import com.android.tools.r8.references.FieldReference;
 import com.android.tools.r8.references.MethodReference;
@@ -68,8 +69,10 @@
 
     private final Set<DexReference> contexts = Sets.newIdentityHashSet();
 
-    Builder addAll(Set<DexReference> contexts) {
-      this.contexts.addAll(contexts);
+    Builder addAll(Set<ProgramDerivedContext> contexts) {
+      for (ProgramDerivedContext context : contexts) {
+        this.contexts.add(context.getContext().getReference());
+      }
       return this;
     }
 
diff --git a/src/main/java/com/android/tools/r8/diagnostic/internal/MissingClassInfoImpl.java b/src/main/java/com/android/tools/r8/diagnostic/internal/MissingClassInfoImpl.java
new file mode 100644
index 0000000..b240279
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/diagnostic/internal/MissingClassInfoImpl.java
@@ -0,0 +1,47 @@
+// Copyright (c) 2021, 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.diagnostic.internal;
+
+import com.android.tools.r8.diagnostic.MissingClassInfo;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.MissingDefinitionInfo;
+import com.android.tools.r8.references.ClassReference;
+import java.util.Collection;
+
+public class MissingClassInfoImpl extends MissingDefinitionInfoBase implements MissingClassInfo {
+
+  private final ClassReference classReference;
+
+  private MissingClassInfoImpl(
+      ClassReference classReference, Collection<MissingDefinitionContext> referencedFromContexts) {
+    super(referencedFromContexts);
+    this.classReference = classReference;
+  }
+
+  public static Builder builder() {
+    return new Builder();
+  }
+
+  @Override
+  public ClassReference getClassReference() {
+    return classReference;
+  }
+
+  public static class Builder extends MissingDefinitionInfoBase.Builder {
+
+    private ClassReference classReference;
+
+    private Builder() {}
+
+    public Builder setClass(ClassReference classReference) {
+      this.classReference = classReference;
+      return this;
+    }
+
+    public MissingDefinitionInfo build() {
+      return new MissingClassInfoImpl(classReference, referencedFromContextsBuilder.build());
+    }
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/diagnostic/internal/MissingDefinitionClassContextImpl.java b/src/main/java/com/android/tools/r8/diagnostic/internal/MissingDefinitionClassContextImpl.java
new file mode 100644
index 0000000..7944a1e
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/diagnostic/internal/MissingDefinitionClassContextImpl.java
@@ -0,0 +1,59 @@
+// Copyright (c) 2021, 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.diagnostic.internal;
+
+import com.android.tools.r8.diagnostic.MissingDefinitionClassContext;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.references.ClassReference;
+
+public class MissingDefinitionClassContextImpl extends MissingDefinitionContextBase
+    implements MissingDefinitionClassContext {
+
+  private final ClassReference classReference;
+
+  private MissingDefinitionClassContextImpl(ClassReference classReference, Origin origin) {
+    super(origin);
+    this.classReference = classReference;
+  }
+
+  public static Builder builder() {
+    return new Builder();
+  }
+
+  @Override
+  public ClassReference getClassReference() {
+    return classReference;
+  }
+
+  public static class Builder extends MissingDefinitionContextBase.Builder<Builder> {
+
+    private ClassReference classReference;
+
+    private Builder() {}
+
+    public Builder setClassContext(ClassReference classReference) {
+      this.classReference = classReference;
+      return this;
+    }
+
+    @Override
+    Builder self() {
+      return this;
+    }
+
+    @Override
+    public MissingDefinitionClassContextImpl build() {
+      assert validate();
+      return new MissingDefinitionClassContextImpl(classReference, origin);
+    }
+
+    @Override
+    public boolean validate() {
+      super.validate();
+      assert classReference != null;
+      return true;
+    }
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/diagnostic/internal/MissingDefinitionContextBase.java b/src/main/java/com/android/tools/r8/diagnostic/internal/MissingDefinitionContextBase.java
new file mode 100644
index 0000000..cf6a0d1
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/diagnostic/internal/MissingDefinitionContextBase.java
@@ -0,0 +1,41 @@
+// Copyright (c) 2021, 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.diagnostic.internal;
+
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.origin.Origin;
+
+public abstract class MissingDefinitionContextBase implements MissingDefinitionContext {
+
+  private final Origin origin;
+
+  MissingDefinitionContextBase(Origin origin) {
+    this.origin = origin;
+  }
+
+  @Override
+  public Origin getOrigin() {
+    return origin;
+  }
+
+  abstract static class Builder<B extends Builder<B>> {
+
+    Origin origin;
+
+    public B setOrigin(Origin origin) {
+      this.origin = origin;
+      return self();
+    }
+
+    abstract B self();
+
+    public abstract MissingDefinitionContext build();
+
+    public boolean validate() {
+      assert origin != null;
+      return true;
+    }
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/diagnostic/internal/MissingDefinitionContextUtils.java b/src/main/java/com/android/tools/r8/diagnostic/internal/MissingDefinitionContextUtils.java
new file mode 100644
index 0000000..74b48c5
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/diagnostic/internal/MissingDefinitionContextUtils.java
@@ -0,0 +1,79 @@
+// Copyright (c) 2021, 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.diagnostic.internal;
+
+import com.android.tools.r8.diagnostic.MissingDefinitionClassContext;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.MissingDefinitionFieldContext;
+import com.android.tools.r8.diagnostic.MissingDefinitionMethodContext;
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.Definition;
+import com.android.tools.r8.graph.ProgramDerivedContext;
+import com.android.tools.r8.utils.FieldReferenceUtils;
+import com.android.tools.r8.utils.MethodReferenceUtils;
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+public class MissingDefinitionContextUtils {
+
+  public static void accept(
+      MissingDefinitionContext missingDefinitionContext,
+      Consumer<MissingDefinitionClassContext> missingDefinitionClassContextConsumer,
+      Consumer<MissingDefinitionFieldContext> missingDefinitionFieldContextConsumer,
+      Consumer<MissingDefinitionMethodContext> missingDefinitionMethodContextConsumer) {
+    if (missingDefinitionContext.isClassContext()) {
+      missingDefinitionClassContextConsumer.accept(missingDefinitionContext.asClassContext());
+    } else if (missingDefinitionContext.isFieldContext()) {
+      missingDefinitionFieldContextConsumer.accept(missingDefinitionContext.asFieldContext());
+    } else {
+      assert missingDefinitionContext.isMethodContext();
+      missingDefinitionMethodContextConsumer.accept(missingDefinitionContext.asMethodContext());
+    }
+  }
+
+  public static <T> T apply(
+      MissingDefinitionContext missingDefinitionContext,
+      Function<MissingDefinitionClassContext, T> missingDefinitionClassContextFn,
+      Function<MissingDefinitionFieldContext, T> missingDefinitionFieldContextFn,
+      Function<MissingDefinitionMethodContext, T> missingDefinitionMethodContextFn) {
+    if (missingDefinitionContext.isClassContext()) {
+      return missingDefinitionClassContextFn.apply(missingDefinitionContext.asClassContext());
+    } else if (missingDefinitionContext.isFieldContext()) {
+      return missingDefinitionFieldContextFn.apply(missingDefinitionContext.asFieldContext());
+    } else {
+      assert missingDefinitionContext.isMethodContext();
+      return missingDefinitionMethodContextFn.apply(missingDefinitionContext.asMethodContext());
+    }
+  }
+
+  public static MissingDefinitionContext create(ProgramDerivedContext programDerivedContext) {
+    Definition context = programDerivedContext.getContext();
+    MissingDefinitionContextBase.Builder<?> builder;
+    if (context.isClass()) {
+      builder =
+          MissingDefinitionClassContextImpl.builder()
+              .setClassContext(context.asClass().getClassReference());
+    } else if (context.isField()) {
+      builder =
+          MissingDefinitionFieldContextImpl.builder()
+              .setFieldContext(context.asField().getFieldReference());
+    } else if (context.isMethod()) {
+      builder =
+          MissingDefinitionMethodContextImpl.builder()
+              .setMethodContext(context.asMethod().getMethodReference());
+    } else {
+      throw new Unreachable();
+    }
+    return builder.setOrigin(context.getOrigin()).build();
+  }
+
+  public static String toSourceString(MissingDefinitionContext missingDefinitionContext) {
+    return MissingDefinitionContextUtils.apply(
+        missingDefinitionContext,
+        classContext -> classContext.getClassReference().getTypeName(),
+        fieldContext -> FieldReferenceUtils.toSourceString(fieldContext.getFieldReference()),
+        methodContext -> MethodReferenceUtils.toSourceString(methodContext.getMethodReference()));
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/diagnostic/internal/MissingDefinitionFieldContextImpl.java b/src/main/java/com/android/tools/r8/diagnostic/internal/MissingDefinitionFieldContextImpl.java
new file mode 100644
index 0000000..b9ecf41
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/diagnostic/internal/MissingDefinitionFieldContextImpl.java
@@ -0,0 +1,59 @@
+// Copyright (c) 2021, 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.diagnostic.internal;
+
+import com.android.tools.r8.diagnostic.MissingDefinitionFieldContext;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.references.FieldReference;
+
+public class MissingDefinitionFieldContextImpl extends MissingDefinitionContextBase
+    implements MissingDefinitionFieldContext {
+
+  private final FieldReference fieldReference;
+
+  private MissingDefinitionFieldContextImpl(FieldReference fieldReference, Origin origin) {
+    super(origin);
+    this.fieldReference = fieldReference;
+  }
+
+  public static Builder builder() {
+    return new Builder();
+  }
+
+  @Override
+  public FieldReference getFieldReference() {
+    return fieldReference;
+  }
+
+  public static class Builder extends MissingDefinitionContextBase.Builder<Builder> {
+
+    private FieldReference fieldReference;
+
+    private Builder() {}
+
+    public Builder setFieldContext(FieldReference fieldReference) {
+      this.fieldReference = fieldReference;
+      return this;
+    }
+
+    @Override
+    Builder self() {
+      return this;
+    }
+
+    @Override
+    public MissingDefinitionFieldContextImpl build() {
+      assert validate();
+      return new MissingDefinitionFieldContextImpl(fieldReference, origin);
+    }
+
+    @Override
+    public boolean validate() {
+      super.validate();
+      assert fieldReference != null;
+      return true;
+    }
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/diagnostic/internal/MissingDefinitionInfoBase.java b/src/main/java/com/android/tools/r8/diagnostic/internal/MissingDefinitionInfoBase.java
new file mode 100644
index 0000000..0f9e655
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/diagnostic/internal/MissingDefinitionInfoBase.java
@@ -0,0 +1,37 @@
+// Copyright (c) 2021, 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.diagnostic.internal;
+
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.MissingDefinitionInfo;
+import com.google.common.collect.ImmutableList;
+import java.util.Collection;
+
+public abstract class MissingDefinitionInfoBase implements MissingDefinitionInfo {
+
+  final Collection<MissingDefinitionContext> referencedFromContexts;
+
+  MissingDefinitionInfoBase(Collection<MissingDefinitionContext> referencedFromContexts) {
+    this.referencedFromContexts = referencedFromContexts;
+  }
+
+  @Override
+  public final Collection<MissingDefinitionContext> getReferencedFromContexts() {
+    return referencedFromContexts;
+  }
+
+  public abstract static class Builder {
+
+    final ImmutableList.Builder<MissingDefinitionContext> referencedFromContextsBuilder =
+        ImmutableList.builder();
+
+    Builder() {}
+
+    public Builder addReferencedFromContext(MissingDefinitionContext missingDefinitionContext) {
+      referencedFromContextsBuilder.add(missingDefinitionContext);
+      return this;
+    }
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/diagnostic/internal/MissingDefinitionInfoUtils.java b/src/main/java/com/android/tools/r8/diagnostic/internal/MissingDefinitionInfoUtils.java
new file mode 100644
index 0000000..29d008f
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/diagnostic/internal/MissingDefinitionInfoUtils.java
@@ -0,0 +1,83 @@
+// Copyright (c) 2021, 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.diagnostic.internal;
+
+import com.android.tools.r8.diagnostic.MissingClassInfo;
+import com.android.tools.r8.diagnostic.MissingDefinitionInfo;
+import com.android.tools.r8.diagnostic.MissingFieldInfo;
+import com.android.tools.r8.diagnostic.MissingMethodInfo;
+import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.references.FieldReference;
+import com.android.tools.r8.references.MethodReference;
+import com.android.tools.r8.utils.ClassReferenceUtils;
+import com.android.tools.r8.utils.FieldReferenceUtils;
+import com.android.tools.r8.utils.MethodReferenceUtils;
+import java.util.Comparator;
+import java.util.function.Consumer;
+
+public class MissingDefinitionInfoUtils {
+
+  private static final Comparator<MissingDefinitionInfo> COMPARATOR =
+      (info, other) -> {
+        if (info.isMissingClass()) {
+          ClassReference classReference = info.asMissingClass().getClassReference();
+          if (other.isMissingClass()) {
+            return ClassReferenceUtils.compare(
+                classReference, other.asMissingClass().getClassReference());
+          }
+          if (other.isMissingField()) {
+            return ClassReferenceUtils.compare(
+                classReference, other.asMissingField().getFieldReference().getHolderClass());
+          }
+          return ClassReferenceUtils.compare(
+              classReference, other.asMissingMethod().getMethodReference().getHolderClass());
+        }
+        if (info.isMissingField()) {
+          FieldReference fieldReference = info.asMissingField().getFieldReference();
+          if (other.isMissingClass()) {
+            return ClassReferenceUtils.compare(
+                fieldReference.getHolderClass(), other.asMissingClass().getClassReference());
+          }
+          if (other.isMissingField()) {
+            return FieldReferenceUtils.compare(
+                fieldReference, other.asMissingField().getFieldReference());
+          }
+          return ClassReferenceUtils.compare(
+              fieldReference.getHolderClass(),
+              other.asMissingMethod().getMethodReference().getHolderClass());
+        }
+        MethodReference methodReference = info.asMissingMethod().getMethodReference();
+        if (other.isMissingClass()) {
+          return ClassReferenceUtils.compare(
+              methodReference.getHolderClass(), other.asMissingClass().getClassReference());
+        }
+        if (other.isMissingField()) {
+          ClassReferenceUtils.compare(
+              methodReference.getHolderClass(),
+              other.asMissingField().getFieldReference().getHolderClass());
+        }
+        return MethodReferenceUtils.compare(
+            methodReference, other.asMissingMethod().getMethodReference());
+      };
+
+  public static void accept(
+      MissingDefinitionInfo missingDefinitionInfo,
+      Consumer<MissingClassInfo> missingClassInfoConsumer,
+      Consumer<MissingFieldInfo> missingFieldInfoConsumer,
+      Consumer<MissingMethodInfo> missingMethodInfoConsumer) {
+    if (missingDefinitionInfo.isMissingClass()) {
+      missingClassInfoConsumer.accept(missingDefinitionInfo.asMissingClass());
+    } else if (missingDefinitionInfo.isMissingField()) {
+      missingFieldInfoConsumer.accept(missingDefinitionInfo.asMissingField());
+    } else {
+      assert missingDefinitionInfo.isMissingMethod();
+      missingMethodInfoConsumer.accept(missingDefinitionInfo.asMissingMethod());
+    }
+  }
+
+  public static Comparator<MissingDefinitionInfo> getComparator() {
+    return COMPARATOR;
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/diagnostic/internal/MissingDefinitionMethodContextImpl.java b/src/main/java/com/android/tools/r8/diagnostic/internal/MissingDefinitionMethodContextImpl.java
new file mode 100644
index 0000000..eba8719
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/diagnostic/internal/MissingDefinitionMethodContextImpl.java
@@ -0,0 +1,59 @@
+// Copyright (c) 2021, 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.diagnostic.internal;
+
+import com.android.tools.r8.diagnostic.MissingDefinitionMethodContext;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.references.MethodReference;
+
+public class MissingDefinitionMethodContextImpl extends MissingDefinitionContextBase
+    implements MissingDefinitionMethodContext {
+
+  private final MethodReference methodReference;
+
+  private MissingDefinitionMethodContextImpl(MethodReference methodReference, Origin origin) {
+    super(origin);
+    this.methodReference = methodReference;
+  }
+
+  public static Builder builder() {
+    return new Builder();
+  }
+
+  @Override
+  public MethodReference getMethodReference() {
+    return methodReference;
+  }
+
+  public static class Builder extends MissingDefinitionContextBase.Builder<Builder> {
+
+    private MethodReference methodReference;
+
+    private Builder() {}
+
+    public Builder setMethodContext(MethodReference methodReference) {
+      this.methodReference = methodReference;
+      return this;
+    }
+
+    @Override
+    Builder self() {
+      return this;
+    }
+
+    @Override
+    public MissingDefinitionMethodContextImpl build() {
+      assert validate();
+      return new MissingDefinitionMethodContextImpl(methodReference, origin);
+    }
+
+    @Override
+    public boolean validate() {
+      super.validate();
+      assert methodReference != null;
+      return true;
+    }
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/diagnostic/internal/MissingDefinitionsDiagnosticImpl.java b/src/main/java/com/android/tools/r8/diagnostic/internal/MissingDefinitionsDiagnosticImpl.java
index 044b1d5..5da21fd 100644
--- a/src/main/java/com/android/tools/r8/diagnostic/internal/MissingDefinitionsDiagnosticImpl.java
+++ b/src/main/java/com/android/tools/r8/diagnostic/internal/MissingDefinitionsDiagnosticImpl.java
@@ -4,48 +4,50 @@
 
 package com.android.tools.r8.diagnostic.internal;
 
+import static com.android.tools.r8.utils.ClassReferenceUtils.getClassReferenceComparator;
+import static com.android.tools.r8.utils.FieldReferenceUtils.getFieldReferenceComparator;
+import static com.android.tools.r8.utils.MethodReferenceUtils.getMethodReferenceComparator;
+
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
 import com.android.tools.r8.diagnostic.MissingDefinitionInfo;
 import com.android.tools.r8.diagnostic.MissingDefinitionsDiagnostic;
-import com.android.tools.r8.errors.Unimplemented;
-import com.android.tools.r8.graph.DexReference;
-import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.position.Position;
 import com.android.tools.r8.references.ClassReference;
-import com.android.tools.r8.references.Reference;
-import com.google.common.collect.ImmutableSortedMap;
+import com.android.tools.r8.references.FieldReference;
+import com.android.tools.r8.references.MethodReference;
+import com.android.tools.r8.utils.Box;
+import com.android.tools.r8.utils.FieldReferenceUtils;
+import com.android.tools.r8.utils.MethodReferenceUtils;
+import com.google.common.collect.ImmutableList;
+import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Comparator;
 import java.util.Iterator;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.SortedMap;
+import java.util.List;
 
 public class MissingDefinitionsDiagnosticImpl implements MissingDefinitionsDiagnostic {
 
-  private final boolean fatal;
-  private final SortedMap<ClassReference, MissingClassAccessContexts> missingClasses;
+  private final Collection<MissingDefinitionInfo> missingDefinitions;
 
-  private MissingDefinitionsDiagnosticImpl(
-      boolean fatal, SortedMap<ClassReference, MissingClassAccessContexts> missingClasses) {
-    assert !missingClasses.isEmpty();
-    this.fatal = fatal;
-    this.missingClasses = missingClasses;
+  private MissingDefinitionsDiagnosticImpl(Collection<MissingDefinitionInfo> missingDefinitions) {
+    assert !missingDefinitions.isEmpty();
+    this.missingDefinitions = missingDefinitions;
   }
 
   public static Builder builder() {
     return new Builder();
   }
 
-  @Deprecated
-  public Set<ClassReference> getMissingClasses() {
-    return missingClasses.keySet();
-  }
-
   @Override
   public Collection<MissingDefinitionInfo> getMissingDefinitions() {
-    throw new Unimplemented();
+    return missingDefinitions;
+  }
+
+  private Collection<MissingDefinitionInfo> getMissingDefinitionsWithDeterministicOrder() {
+    List<MissingDefinitionInfo> missingDefinitionsWithDeterministicOrder =
+        new ArrayList<>(getMissingDefinitions());
+    missingDefinitionsWithDeterministicOrder.sort(MissingDefinitionInfoUtils.getComparator());
+    return missingDefinitionsWithDeterministicOrder;
   }
 
   /** A missing class(es) failure can generally not be attributed to a single origin. */
@@ -62,84 +64,102 @@
 
   @Override
   public String getDiagnosticMessage() {
-    return fatal ? getFatalDiagnosticMessage() : getNonFatalDiagnosticMessage();
-  }
-
-  private String getFatalDiagnosticMessage() {
-    if (missingClasses.size() == 1) {
-      StringBuilder builder =
-          new StringBuilder(
-              "Compilation can't be completed because the following class is missing: ");
-      writeMissingClass(builder, missingClasses.entrySet().iterator().next());
-      return builder.append(".").toString();
-    }
-
-    StringBuilder builder =
-        new StringBuilder("Compilation can't be completed because the following ")
-            .append(missingClasses.size())
-            .append(" classes are missing:");
-    missingClasses.forEach(
-        (missingClass, contexts) ->
-            writeMissingClass(
-                builder.append(System.lineSeparator()).append("- "), missingClass, contexts));
-    return builder.toString();
-  }
-
-  private String getNonFatalDiagnosticMessage() {
     StringBuilder builder = new StringBuilder();
-    Iterator<Entry<ClassReference, MissingClassAccessContexts>> missingClassesIterator =
-        missingClasses.entrySet().iterator();
+    Iterator<MissingDefinitionInfo> missingDefinitionsIterator =
+        getMissingDefinitionsWithDeterministicOrder().iterator();
 
     // The diagnostic is always non-empty.
-    assert missingClassesIterator.hasNext();
+    assert missingDefinitionsIterator.hasNext();
 
     // Write first line.
-    writeMissingClass(builder.append("Missing class "), missingClassesIterator.next());
+    writeMissingDefinition(builder.append("Missing class "), missingDefinitionsIterator.next());
 
     // Write remaining lines with line separator before.
-    missingClassesIterator.forEachRemaining(
-        missingClassInfo ->
-            writeMissingClass(
-                builder.append(System.lineSeparator()).append("Missing class "), missingClassInfo));
+    missingDefinitionsIterator.forEachRemaining(
+        missingDefinition ->
+            writeMissingDefinition(
+                builder.append(System.lineSeparator()).append("Missing class "),
+                missingDefinition));
 
     return builder.toString();
   }
 
-  private static void writeMissingClass(
-      StringBuilder builder, Entry<ClassReference, MissingClassAccessContexts> missingClassInfo) {
-    writeMissingClass(builder, missingClassInfo.getKey(), missingClassInfo.getValue());
+  private static void writeMissingDefinition(
+      StringBuilder builder, MissingDefinitionInfo missingDefinitionInfo) {
+    MissingDefinitionInfoUtils.accept(
+        missingDefinitionInfo,
+        missingClassInfo -> builder.append(missingClassInfo.getClassReference().getTypeName()),
+        missingFieldInfo ->
+            builder.append(
+                FieldReferenceUtils.toSourceString(missingFieldInfo.getFieldReference())),
+        missingMethodInfo ->
+            builder.append(
+                MethodReferenceUtils.toSourceString(missingMethodInfo.getMethodReference())));
+    writeReferencedFromSuffix(builder, missingDefinitionInfo);
   }
 
-  private static void writeMissingClass(
-      StringBuilder builder, ClassReference missingClass, MissingClassAccessContexts contexts) {
-    builder
-        .append(missingClass.getTypeName())
-        .append(contexts.getReferencedFromMessageSuffix(missingClass));
+  private static void writeReferencedFromSuffix(
+      StringBuilder builder, MissingDefinitionInfo missingDefinitionInfo) {
+    Box<ClassReference> classContext = new Box<>();
+    Box<FieldReference> fieldContext = new Box<>();
+    Box<MethodReference> methodContext = new Box<>();
+    for (MissingDefinitionContext missingDefinitionContext :
+        missingDefinitionInfo.getReferencedFromContexts()) {
+      MissingDefinitionContextUtils.accept(
+          missingDefinitionContext,
+          missingDefinitionClassContext ->
+              classContext.setMin(
+                  missingDefinitionClassContext.getClassReference(), getClassReferenceComparator()),
+          missingDefinitionFieldContext ->
+              fieldContext.setMin(
+                  missingDefinitionFieldContext.getFieldReference(), getFieldReferenceComparator()),
+          missingDefinitionMethodContext ->
+              methodContext.setMin(
+                  missingDefinitionMethodContext.getMethodReference(),
+                  getMethodReferenceComparator()));
+    }
+    if (fieldContext.isSet()) {
+      writeReferencedFromSuffix(
+          builder, missingDefinitionInfo, FieldReferenceUtils.toSourceString(fieldContext.get()));
+    } else if (methodContext.isSet()) {
+      writeReferencedFromSuffix(
+          builder, missingDefinitionInfo, MethodReferenceUtils.toSourceString(methodContext.get()));
+    } else if (classContext.isSet()) {
+      writeReferencedFromSuffix(builder, missingDefinitionInfo, classContext.get().getTypeName());
+    } else {
+      // TODO(b/175543745): Once legacy reporting is removed this should never happen.
+      builder.append(" (referenced from: <not known>)");
+    }
+  }
+
+  private static void writeReferencedFromSuffix(
+      StringBuilder builder, MissingDefinitionInfo missingDefinitionInfo, String referencedFrom) {
+    int numberOfOtherContexts = missingDefinitionInfo.getReferencedFromContexts().size() - 1;
+    assert numberOfOtherContexts >= 0;
+    builder.append(" (referenced from: ").append(referencedFrom);
+    if (numberOfOtherContexts >= 1) {
+      builder.append(", and ").append(numberOfOtherContexts).append(" other context");
+      if (numberOfOtherContexts >= 2) {
+        builder.append("s");
+      }
+    }
+    builder.append(")");
   }
 
   public static class Builder {
 
-    private boolean fatal;
-    private ImmutableSortedMap.Builder<ClassReference, MissingClassAccessContexts>
-        missingClassesBuilder =
-            ImmutableSortedMap.orderedBy(Comparator.comparing(ClassReference::getDescriptor));
+    private ImmutableList.Builder<MissingDefinitionInfo> missingDefinitionsBuilder =
+        ImmutableList.builder();
 
-    public Builder addMissingClasses(Map<DexType, Set<DexReference>> missingClasses) {
-      missingClasses.forEach(
-          (missingClass, contexts) ->
-              missingClassesBuilder.put(
-                  Reference.classFromDescriptor(missingClass.toDescriptorString()),
-                  MissingClassAccessContexts.builder().addAll(contexts).build()));
-      return this;
-    }
+    private Builder() {}
 
-    public Builder setFatal(boolean fatal) {
-      this.fatal = fatal;
+    public Builder addMissingDefinitionInfo(MissingDefinitionInfo missingDefinition) {
+      missingDefinitionsBuilder.add(missingDefinition);
       return this;
     }
 
     public MissingDefinitionsDiagnostic build() {
-      return new MissingDefinitionsDiagnosticImpl(fatal, missingClassesBuilder.build());
+      return new MissingDefinitionsDiagnosticImpl(missingDefinitionsBuilder.build());
     }
   }
 }
diff --git a/src/main/java/com/android/tools/r8/errors/dontwarn/DontWarnConfiguration.java b/src/main/java/com/android/tools/r8/errors/dontwarn/DontWarnConfiguration.java
index ff4a73d..d14300b 100644
--- a/src/main/java/com/android/tools/r8/errors/dontwarn/DontWarnConfiguration.java
+++ b/src/main/java/com/android/tools/r8/errors/dontwarn/DontWarnConfiguration.java
@@ -4,11 +4,10 @@
 
 package com.android.tools.r8.errors.dontwarn;
 
-import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.Definition;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.shaking.ProguardConfiguration;
 import com.android.tools.r8.utils.InternalOptions;
-import java.util.Set;
 
 public abstract class DontWarnConfiguration {
 
@@ -24,10 +23,8 @@
     return new EmptyDontWarnConfiguration();
   }
 
-  public abstract Set<DexType> getNonMatches(Set<DexType> types);
-
-  public final boolean matches(DexClass clazz) {
-    return matches(clazz.getType());
+  public final boolean matches(Definition clazz) {
+    return matches(clazz.getContextType());
   }
 
   public abstract boolean matches(DexType type);
diff --git a/src/main/java/com/android/tools/r8/errors/dontwarn/EmptyDontWarnConfiguration.java b/src/main/java/com/android/tools/r8/errors/dontwarn/EmptyDontWarnConfiguration.java
index e115168..4cc7f04 100644
--- a/src/main/java/com/android/tools/r8/errors/dontwarn/EmptyDontWarnConfiguration.java
+++ b/src/main/java/com/android/tools/r8/errors/dontwarn/EmptyDontWarnConfiguration.java
@@ -6,16 +6,10 @@
 
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.utils.InternalOptions;
-import java.util.Set;
 
 public class EmptyDontWarnConfiguration extends DontWarnConfiguration {
 
   @Override
-  public Set<DexType> getNonMatches(Set<DexType> types) {
-    return types;
-  }
-
-  @Override
   public boolean matches(DexType type) {
     return false;
   }
diff --git a/src/main/java/com/android/tools/r8/errors/dontwarn/NonEmptyDontWarnConfiguration.java b/src/main/java/com/android/tools/r8/errors/dontwarn/NonEmptyDontWarnConfiguration.java
index 89bcb10..ae31723 100644
--- a/src/main/java/com/android/tools/r8/errors/dontwarn/NonEmptyDontWarnConfiguration.java
+++ b/src/main/java/com/android/tools/r8/errors/dontwarn/NonEmptyDontWarnConfiguration.java
@@ -29,17 +29,6 @@
   }
 
   @Override
-  public Set<DexType> getNonMatches(Set<DexType> types) {
-    Set<DexType> nonMatches = Sets.newIdentityHashSet();
-    for (DexType type : types) {
-      if (!matches(type)) {
-        nonMatches.add(type);
-      }
-    }
-    return nonMatches;
-  }
-
-  @Override
   public boolean matches(DexType type) {
     for (ProguardClassNameList dontWarnPattern : dontWarnPatterns) {
       if (dontWarnPattern.matches(type)) {
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 8b09674..7622121 100644
--- a/src/main/java/com/android/tools/r8/graph/AppView.java
+++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -39,6 +39,7 @@
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.InternalOptions.TestingOptions;
 import com.android.tools.r8.utils.OptionalBool;
+import com.android.tools.r8.utils.Reporter;
 import com.android.tools.r8.utils.ThrowingConsumer;
 import com.google.common.base.Predicates;
 import com.google.common.collect.ImmutableSet;
@@ -454,6 +455,10 @@
     return appInfo.options();
   }
 
+  public Reporter reporter() {
+    return options().reporter;
+  }
+
   public TestingOptions testing() {
     return options().testing;
   }
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 4247d74..337ec1d 100644
--- a/src/main/java/com/android/tools/r8/graph/CfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/CfCode.java
@@ -135,8 +135,8 @@
   // TODO(b/135969130): Make IR building lens aware and avoid caching the holder type.
   private final DexType originalHolder;
 
-  private final int maxStack;
   private int maxLocals;
+  private int maxStack;
   private List<CfInstruction> instructions;
   private final List<CfTryCatch> tryCatchRanges;
   private final List<LocalVariableInfo> localVariables;
@@ -188,6 +188,10 @@
     maxLocals = newMaxLocals;
   }
 
+  public void setMaxStack(int newMaxStack) {
+    maxStack = newMaxStack;
+  }
+
   public List<CfTryCatch> getTryCatchRanges() {
     return tryCatchRanges;
   }
diff --git a/src/main/java/com/android/tools/r8/graph/ClassDefinition.java b/src/main/java/com/android/tools/r8/graph/ClassDefinition.java
new file mode 100644
index 0000000..f4f1c31
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/ClassDefinition.java
@@ -0,0 +1,45 @@
+// Copyright (c) 2021, 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.graph;
+
+import com.android.tools.r8.references.ClassReference;
+import java.util.function.Consumer;
+
+public interface ClassDefinition extends Definition {
+
+  Iterable<DexType> allImmediateSupertypes();
+
+  void forEachClassField(Consumer<? super DexClassAndField> consumer);
+
+  void forEachClassMethod(Consumer<? super DexClassAndMethod> consumer);
+
+  MethodCollection getMethodCollection();
+
+  ClassReference getClassReference();
+
+  DexType getType();
+
+  @Override
+  default boolean isClass() {
+    return true;
+  }
+
+  @Override
+  default ClassDefinition asClass() {
+    return this;
+  }
+
+  boolean isClasspathClass();
+
+  DexClasspathClass asClasspathClass();
+
+  boolean isLibraryClass();
+
+  DexLibraryClass asLibraryClass();
+
+  boolean isProgramClass();
+
+  DexProgramClass asProgramClass();
+}
diff --git a/src/main/java/com/android/tools/r8/graph/ClasspathClass.java b/src/main/java/com/android/tools/r8/graph/ClasspathClass.java
new file mode 100644
index 0000000..9ae72e4
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/ClasspathClass.java
@@ -0,0 +1,7 @@
+// Copyright (c) 2021, 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.graph;
+
+public interface ClasspathClass extends ClasspathDefinition, ClasspathOrLibraryClass {}
diff --git a/src/main/java/com/android/tools/r8/graph/ClasspathDefinition.java b/src/main/java/com/android/tools/r8/graph/ClasspathDefinition.java
index 89013fd..11cd7ad 100644
--- a/src/main/java/com/android/tools/r8/graph/ClasspathDefinition.java
+++ b/src/main/java/com/android/tools/r8/graph/ClasspathDefinition.java
@@ -6,7 +6,7 @@
 
 import java.util.function.Function;
 
-public interface ClasspathDefinition extends Definition {
+public interface ClasspathDefinition extends ClasspathOrLibraryDefinition {
 
   @Override
   default <T> T apply(
diff --git a/src/main/java/com/android/tools/r8/graph/ClasspathOrLibraryClass.java b/src/main/java/com/android/tools/r8/graph/ClasspathOrLibraryClass.java
new file mode 100644
index 0000000..cf385e0
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/ClasspathOrLibraryClass.java
@@ -0,0 +1,7 @@
+// Copyright (c) 2021, 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.graph;
+
+public interface ClasspathOrLibraryClass extends ClassDefinition, ClasspathOrLibraryDefinition {}
diff --git a/src/main/java/com/android/tools/r8/graph/ClasspathOrLibraryDefinition.java b/src/main/java/com/android/tools/r8/graph/ClasspathOrLibraryDefinition.java
new file mode 100644
index 0000000..261e6bd
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/ClasspathOrLibraryDefinition.java
@@ -0,0 +1,13 @@
+// Copyright (c) 2021, 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.graph;
+
+public interface ClasspathOrLibraryDefinition extends Definition {
+
+  @Override
+  default ClasspathOrLibraryDefinition asClasspathOrLibraryDefinition() {
+    return this;
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/graph/Definition.java b/src/main/java/com/android/tools/r8/graph/Definition.java
index a7e4ed9..7e42398 100644
--- a/src/main/java/com/android/tools/r8/graph/Definition.java
+++ b/src/main/java/com/android/tools/r8/graph/Definition.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.graph;
 
+import com.android.tools.r8.origin.Origin;
 import java.util.function.Function;
 
 public interface Definition {
@@ -13,9 +14,51 @@
       Function<ClasspathDefinition, T> classpathFunction,
       Function<LibraryDefinition, T> libraryFunction);
 
+  default ClasspathOrLibraryClass asClasspathOrLibraryClass() {
+    return null;
+  }
+
+  default ClasspathOrLibraryDefinition asClasspathOrLibraryDefinition() {
+    return null;
+  }
+
   ProgramDerivedContext asProgramDerivedContext(ProgramDerivedContext witness);
 
   DexType getContextType();
 
+  Origin getOrigin();
+
   DexReference getReference();
+
+  default boolean isClass() {
+    return false;
+  }
+
+  default ClassDefinition asClass() {
+    return null;
+  }
+
+  default boolean isField() {
+    return false;
+  }
+
+  default DexClassAndField asField() {
+    return null;
+  }
+
+  default boolean isMethod() {
+    return false;
+  }
+
+  default DexClassAndMethod asMethod() {
+    return null;
+  }
+
+  default boolean isProgramDefinition() {
+    return false;
+  }
+
+  default ProgramDefinition asProgramDefinition() {
+    return null;
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/graph/DexClass.java b/src/main/java/com/android/tools/r8/graph/DexClass.java
index 2b45551..f0745c8 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -12,6 +12,8 @@
 import com.android.tools.r8.graph.GenericSignature.ClassSignature;
 import com.android.tools.r8.kotlin.KotlinClassLevelInfo;
 import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.references.Reference;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.IterableUtils;
 import com.android.tools.r8.utils.OptionalBool;
@@ -33,7 +35,7 @@
 import java.util.function.Function;
 import java.util.function.Predicate;
 
-public abstract class DexClass extends DexDefinition implements Definition {
+public abstract class DexClass extends DexDefinition implements ClassDefinition {
 
   public interface FieldSetter {
     void setField(int index, DexEncodedField field);
@@ -132,6 +134,17 @@
       Consumer<DexClasspathClass> classpathClassConsumer,
       Consumer<DexLibraryClass> libraryClassConsumer);
 
+  @Override
+  public void forEachClassField(Consumer<? super DexClassAndField> consumer) {
+    forEachClassFieldMatching(alwaysTrue(), consumer);
+  }
+
+  public void forEachClassFieldMatching(
+      Predicate<DexEncodedField> predicate, Consumer<? super DexClassAndField> consumer) {
+    forEachFieldMatching(predicate, field -> consumer.accept(DexClassAndField.create(this, field)));
+  }
+
+  @Override
   public void forEachClassMethod(Consumer<? super DexClassAndMethod> consumer) {
     forEachClassMethodMatching(alwaysTrue(), consumer);
   }
@@ -177,6 +190,7 @@
     return Iterables.concat(fields(predicate), methods(predicate));
   }
 
+  @Override
   public MethodCollection getMethodCollection() {
     return methodCollection;
   }
@@ -277,12 +291,12 @@
   }
 
   public void forEachField(Consumer<DexEncodedField> consumer) {
-    for (DexEncodedField field : staticFields()) {
-      consumer.accept(field);
-    }
-    for (DexEncodedField field : instanceFields()) {
-      consumer.accept(field);
-    }
+    forEachFieldMatching(alwaysTrue(), consumer);
+  }
+
+  public void forEachFieldMatching(
+      Predicate<DexEncodedField> predicate, Consumer<DexEncodedField> consumer) {
+    fields(predicate).forEach(consumer);
   }
 
   public TraversalContinuation traverseFields(Function<DexEncodedField, TraversalContinuation> fn) {
@@ -613,20 +627,24 @@
     return this;
   }
 
+  @Override
   public boolean isClasspathClass() {
     return false;
   }
 
+  @Override
   public DexClasspathClass asClasspathClass() {
     return null;
   }
 
   public abstract boolean isNotProgramClass();
 
+  @Override
   public boolean isLibraryClass() {
     return false;
   }
 
+  @Override
   public DexLibraryClass asLibraryClass() {
     return null;
   }
@@ -655,10 +673,17 @@
     return classInitializer;
   }
 
+  @Override
+  public ClassReference getClassReference() {
+    return Reference.classFromDescriptor(getType().toDescriptorString());
+  }
+
+  @Override
   public Origin getOrigin() {
     return this.origin;
   }
 
+  @Override
   public DexType getType() {
     return type;
   }
@@ -761,6 +786,7 @@
     }
   }
 
+  @Override
   public Iterable<DexType> allImmediateSupertypes() {
     Iterator<DexType> iterator =
         superType != null
diff --git a/src/main/java/com/android/tools/r8/graph/DexClassAndField.java b/src/main/java/com/android/tools/r8/graph/DexClassAndField.java
index 505a7ec..e2deec9 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClassAndField.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClassAndField.java
@@ -4,6 +4,8 @@
 
 package com.android.tools.r8.graph;
 
+import com.android.tools.r8.references.FieldReference;
+
 public abstract class DexClassAndField extends DexClassAndMember<DexEncodedField, DexField> {
 
   DexClassAndField(DexClass holder, DexEncodedField field) {
@@ -29,10 +31,24 @@
     return getDefinition().getAccessFlags();
   }
 
+  public FieldReference getFieldReference() {
+    return getReference().asFieldReference();
+  }
+
   public DexType getType() {
     return getReference().getType();
   }
 
+  @Override
+  public boolean isField() {
+    return true;
+  }
+
+  @Override
+  public DexClassAndField asField() {
+    return this;
+  }
+
   public boolean isClasspathField() {
     return false;
   }
diff --git a/src/main/java/com/android/tools/r8/graph/DexClassAndMember.java b/src/main/java/com/android/tools/r8/graph/DexClassAndMember.java
index 8459067..2ac7ced 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClassAndMember.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClassAndMember.java
@@ -49,6 +49,7 @@
     return definition.getReference();
   }
 
+  @Override
   public Origin getOrigin() {
     return holder.origin;
   }
diff --git a/src/main/java/com/android/tools/r8/graph/DexClassAndMethod.java b/src/main/java/com/android/tools/r8/graph/DexClassAndMethod.java
index d944c02..6ab995d 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClassAndMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClassAndMethod.java
@@ -4,6 +4,8 @@
 
 package com.android.tools.r8.graph;
 
+import com.android.tools.r8.references.MethodReference;
+
 public abstract class DexClassAndMethod extends DexClassAndMember<DexEncodedMethod, DexMethod>
     implements LookupTarget {
 
@@ -42,10 +44,22 @@
     return getDefinition().getAccessFlags();
   }
 
+  public MethodReference getMethodReference() {
+    return getReference().asMethodReference();
+  }
+
+  public DexTypeList getParameters() {
+    return getReference().getParameters();
+  }
+
   public DexProto getProto() {
     return getReference().getProto();
   }
 
+  public DexType getReturnType() {
+    return getReference().getReturnType();
+  }
+
   @Override
   public boolean isMethodTarget() {
     return true;
@@ -56,6 +70,16 @@
     return this;
   }
 
+  @Override
+  public boolean isMethod() {
+    return true;
+  }
+
+  @Override
+  public DexClassAndMethod asMethod() {
+    return this;
+  }
+
   public boolean isClasspathMethod() {
     return false;
   }
diff --git a/src/main/java/com/android/tools/r8/graph/DexClasspathClass.java b/src/main/java/com/android/tools/r8/graph/DexClasspathClass.java
index 125155e..6385ecc 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClasspathClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClasspathClass.java
@@ -22,7 +22,7 @@
 import java.util.function.Supplier;
 
 public class DexClasspathClass extends DexClass
-    implements ClasspathDefinition, Supplier<DexClasspathClass>, StructuralItem<DexClasspathClass> {
+    implements ClasspathClass, Supplier<DexClasspathClass>, StructuralItem<DexClasspathClass> {
 
   public DexClasspathClass(
       DexType type,
@@ -103,6 +103,11 @@
     return this;
   }
 
+  @Override
+  public DexClasspathClass asClasspathOrLibraryClass() {
+    return this;
+  }
+
   public static DexClasspathClass asClasspathClassOrNull(DexClass clazz) {
     return clazz != null ? clazz.asClasspathClass() : null;
   }
diff --git a/src/main/java/com/android/tools/r8/graph/DexField.java b/src/main/java/com/android/tools/r8/graph/DexField.java
index 5ebf3ae..ef99d01 100644
--- a/src/main/java/com/android/tools/r8/graph/DexField.java
+++ b/src/main/java/com/android/tools/r8/graph/DexField.java
@@ -36,6 +36,19 @@
   }
 
   @Override
+  public int compareTo(DexReference other) {
+    if (other.isDexField()) {
+      return compareTo(other.asDexField());
+    }
+    if (other.isDexMethod()) {
+      int comparisonResult = getHolderType().compareTo(other.getContextType());
+      return comparisonResult != 0 ? comparisonResult : -1;
+    }
+    int comparisonResult = getHolderType().compareTo(other.asDexType());
+    return comparisonResult != 0 ? comparisonResult : 1;
+  }
+
+  @Override
   public DexField self() {
     return this;
   }
diff --git a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
index ed0339d..0752d20 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -438,7 +438,18 @@
   public final DexType timeConversionsType =
       createStaticallyKnownType("Ljava/time/TimeConversions;");
 
-  public Iterable<DexType> getConversionTypes() {
+  public final DexType doubleSummaryStatisticsConversionsJ$Type =
+      createStaticallyKnownType("Lj$/util/DoubleSummaryStatisticsConversions;");
+  public final DexType intSummaryStatisticsConversionsJ$Type =
+      createStaticallyKnownType("Lj$/util/IntSummaryStatisticsConversions;");
+  public final DexType longSummaryStatisticsConversionsJ$Type =
+      createStaticallyKnownType("Lj$/util/LongSummaryStatisticsConversions;");
+  public final DexType optionalConversionsJ$Type =
+      createStaticallyKnownType("Lj$/util/OptionalConversions;");
+  public final DexType timeConversionsJ$Type =
+      createStaticallyKnownType("Lj$/time/TimeConversions;");
+
+  public Iterable<DexType> getJavaConversionTypes() {
     return ImmutableList.of(
         doubleSummaryStatisticsConversionsType,
         intSummaryStatisticsConversionsType,
@@ -447,6 +458,15 @@
         timeConversionsType);
   }
 
+  public Iterable<DexType> getJ$ConversionTypes() {
+    return ImmutableList.of(
+        doubleSummaryStatisticsConversionsJ$Type,
+        intSummaryStatisticsConversionsJ$Type,
+        longSummaryStatisticsConversionsJ$Type,
+        optionalConversionsJ$Type,
+        timeConversionsJ$Type);
+  }
+
   public final DexType javaIoFileType = createStaticallyKnownType("Ljava/io/File;");
   public final DexType javaMathBigIntegerType = createStaticallyKnownType("Ljava/math/BigInteger;");
   public final DexType javaNioByteOrderType = createStaticallyKnownType("Ljava/nio/ByteOrder;");
@@ -616,8 +636,12 @@
   public final DexType externalizableType = createStaticallyKnownType("Ljava/io/Externalizable;");
   public final DexType cloneableType = createStaticallyKnownType("Ljava/lang/Cloneable;");
   public final DexType comparableType = createStaticallyKnownType("Ljava/lang/Comparable;");
+  public final DexType stringConcatFactoryType =
+      createStaticallyKnownType("Ljava/lang/invoke/StringConcatFactory;");
 
   public final ServiceLoaderMethods serviceLoaderMethods = new ServiceLoaderMethods();
+  public final StringConcatFactoryMembers stringConcatFactoryMembers =
+      new StringConcatFactoryMembers();
 
   public final BiMap<DexType, DexType> primitiveToBoxed = HashBiMap.create(
       ImmutableMap.<DexType, DexType>builder()
@@ -678,33 +702,6 @@
   public final DexMethod deserializeLambdaMethod =
       createMethod(objectType, deserializeLambdaMethodProto, deserializeLambdaMethodName);
 
-  public final DexType stringConcatFactoryType =
-      createStaticallyKnownType("Ljava/lang/invoke/StringConcatFactory;");
-
-  public final DexMethod stringConcatWithConstantsMethod =
-      createMethod(
-          stringConcatFactoryType,
-          createProto(
-              callSiteType,
-              lookupType,
-              stringType,
-              methodTypeType,
-              stringType,
-              objectArrayType),
-          createString("makeConcatWithConstants")
-      );
-
-  public final DexMethod stringConcatMethod =
-      createMethod(
-          stringConcatFactoryType,
-          createProto(
-              callSiteType,
-              lookupType,
-              stringType,
-              methodTypeType),
-          createString("makeConcat")
-      );
-
   public Map<DexMethod, int[]> libraryMethodsNonNullParamOrThrow =
       buildLibraryMethodsNonNullParamOrThrow();
 
@@ -1155,6 +1152,21 @@
     }
   }
 
+  public class StringConcatFactoryMembers {
+
+    public final DexMethod makeConcat =
+        createMethod(
+            stringConcatFactoryType,
+            createProto(callSiteType, lookupType, stringType, methodTypeType),
+            createString("makeConcat"));
+    public final DexMethod makeConcatWithConstants =
+        createMethod(
+            stringConcatFactoryType,
+            createProto(
+                callSiteType, lookupType, stringType, methodTypeType, stringType, objectArrayType),
+            createString("makeConcatWithConstants"));
+  }
+
   public class ThrowableMethods {
 
     public final DexMethod addSuppressed;
diff --git a/src/main/java/com/android/tools/r8/graph/DexLibraryClass.java b/src/main/java/com/android/tools/r8/graph/DexLibraryClass.java
index f34162c..92659f8 100644
--- a/src/main/java/com/android/tools/r8/graph/DexLibraryClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexLibraryClass.java
@@ -17,8 +17,7 @@
 import java.util.function.Predicate;
 import java.util.function.Supplier;
 
-public class DexLibraryClass extends DexClass
-    implements LibraryDefinition, Supplier<DexLibraryClass> {
+public class DexLibraryClass extends DexClass implements LibraryClass, Supplier<DexLibraryClass> {
 
   public DexLibraryClass(
       DexType type,
@@ -126,6 +125,11 @@
   }
 
   @Override
+  public DexLibraryClass asClasspathOrLibraryClass() {
+    return this;
+  }
+
+  @Override
   public KotlinClassLevelInfo getKotlinInfo() {
     throw new Unreachable("We should never consider metadata for library classes");
   }
diff --git a/src/main/java/com/android/tools/r8/graph/DexMethod.java b/src/main/java/com/android/tools/r8/graph/DexMethod.java
index 29e9792..8484a94 100644
--- a/src/main/java/com/android/tools/r8/graph/DexMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexMethod.java
@@ -36,6 +36,15 @@
   }
 
   @Override
+  public int compareTo(DexReference other) {
+    if (other.isDexMethod()) {
+      return compareTo(other.asDexMethod());
+    }
+    int comparisonResult = getHolderType().compareTo(other.getContextType());
+    return comparisonResult != 0 ? comparisonResult : 1;
+  }
+
+  @Override
   public StructuralMapping<DexMethod> getStructuralMapping() {
     return DexMethod::specify;
   }
diff --git a/src/main/java/com/android/tools/r8/graph/DexProto.java b/src/main/java/com/android/tools/r8/graph/DexProto.java
index 36ad355..dc30560 100644
--- a/src/main/java/com/android/tools/r8/graph/DexProto.java
+++ b/src/main/java/com/android/tools/r8/graph/DexProto.java
@@ -83,6 +83,10 @@
     return parameters.values[index];
   }
 
+  public DexTypeList getParameters() {
+    return parameters;
+  }
+
   public int getArity() {
     return parameters.size();
   }
diff --git a/src/main/java/com/android/tools/r8/graph/DexReference.java b/src/main/java/com/android/tools/r8/graph/DexReference.java
index 77976f1..27264bb 100644
--- a/src/main/java/com/android/tools/r8/graph/DexReference.java
+++ b/src/main/java/com/android/tools/r8/graph/DexReference.java
@@ -29,6 +29,8 @@
 
   public abstract void collectIndexedItems(IndexedItemCollection indexedItems);
 
+  public abstract int compareTo(DexReference other);
+
   public abstract DexType getContextType();
 
   public boolean isDexType() {
diff --git a/src/main/java/com/android/tools/r8/graph/DexType.java b/src/main/java/com/android/tools/r8/graph/DexType.java
index aaeb156..75b592b 100644
--- a/src/main/java/com/android/tools/r8/graph/DexType.java
+++ b/src/main/java/com/android/tools/r8/graph/DexType.java
@@ -53,6 +53,15 @@
   }
 
   @Override
+  public int compareTo(DexReference other) {
+    if (other.isDexType()) {
+      return compareTo(other.asDexType());
+    }
+    int comparisonResult = compareTo(other.getContextType());
+    return comparisonResult != 0 ? comparisonResult : -1;
+  }
+
+  @Override
   public DexType self() {
     return this;
   }
diff --git a/src/main/java/com/android/tools/r8/graph/FieldResolutionResult.java b/src/main/java/com/android/tools/r8/graph/FieldResolutionResult.java
index 8b1ca9d..dbc2119 100644
--- a/src/main/java/com/android/tools/r8/graph/FieldResolutionResult.java
+++ b/src/main/java/com/android/tools/r8/graph/FieldResolutionResult.java
@@ -25,6 +25,7 @@
     return null;
   }
 
+  @Override
   public DexClassAndField getResolutionPair() {
     return null;
   }
diff --git a/src/main/java/com/android/tools/r8/graph/GenericSignatureCorrectnessHelper.java b/src/main/java/com/android/tools/r8/graph/GenericSignatureCorrectnessHelper.java
index a7979f6..3401560 100644
--- a/src/main/java/com/android/tools/r8/graph/GenericSignatureCorrectnessHelper.java
+++ b/src/main/java/com/android/tools/r8/graph/GenericSignatureCorrectnessHelper.java
@@ -110,6 +110,7 @@
     return result;
   }
 
+  @SuppressWarnings("unchecked")
   private <T extends DexDefinitionSignature<?>> SignatureEvaluationResult evaluate(
       Supplier<T> getter, Function<T, SignatureEvaluationResult> evaluate, Consumer<T> setter) {
     T signature = getter.get();
diff --git a/src/main/java/com/android/tools/r8/graph/LibraryClass.java b/src/main/java/com/android/tools/r8/graph/LibraryClass.java
new file mode 100644
index 0000000..f4a7081
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/LibraryClass.java
@@ -0,0 +1,7 @@
+// Copyright (c) 2021, 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.graph;
+
+public interface LibraryClass extends LibraryDefinition, ClasspathOrLibraryClass {}
diff --git a/src/main/java/com/android/tools/r8/graph/LibraryDefinition.java b/src/main/java/com/android/tools/r8/graph/LibraryDefinition.java
index a2fb6a8..6767199 100644
--- a/src/main/java/com/android/tools/r8/graph/LibraryDefinition.java
+++ b/src/main/java/com/android/tools/r8/graph/LibraryDefinition.java
@@ -6,7 +6,7 @@
 
 import java.util.function.Function;
 
-public interface LibraryDefinition extends Definition {
+public interface LibraryDefinition extends ClasspathOrLibraryDefinition {
 
   @Override
   default <T> T apply(
diff --git a/src/main/java/com/android/tools/r8/graph/MemberResolutionResult.java b/src/main/java/com/android/tools/r8/graph/MemberResolutionResult.java
index 01294be..285859d 100644
--- a/src/main/java/com/android/tools/r8/graph/MemberResolutionResult.java
+++ b/src/main/java/com/android/tools/r8/graph/MemberResolutionResult.java
@@ -9,6 +9,10 @@
 public abstract class MemberResolutionResult<
     D extends DexEncodedMember<D, R>, R extends DexMember<D, R>> {
 
+  public DexClassAndMember<D, R> getResolutionPair() {
+    return null;
+  }
+
   public abstract boolean isSuccessfulMemberResolutionResult();
 
   public abstract SuccessfulMemberResolutionResult<D, R> asSuccessfulMemberResolutionResult();
diff --git a/src/main/java/com/android/tools/r8/graph/ProgramDefinition.java b/src/main/java/com/android/tools/r8/graph/ProgramDefinition.java
index 862efbc..17e779e 100644
--- a/src/main/java/com/android/tools/r8/graph/ProgramDefinition.java
+++ b/src/main/java/com/android/tools/r8/graph/ProgramDefinition.java
@@ -4,7 +4,6 @@
 
 package com.android.tools.r8.graph;
 
-import com.android.tools.r8.origin.Origin;
 import java.util.function.Function;
 
 public interface ProgramDefinition extends Definition, ProgramDerivedContext {
@@ -28,8 +27,6 @@
 
   DexDefinition getDefinition();
 
-  Origin getOrigin();
-
   default boolean isProgramClass() {
     return false;
   }
@@ -38,6 +35,16 @@
     return null;
   }
 
+  @Override
+  default boolean isProgramDefinition() {
+    return true;
+  }
+
+  @Override
+  default ProgramDefinition asProgramDefinition() {
+    return this;
+  }
+
   default boolean isProgramField() {
     return false;
   }
diff --git a/src/main/java/com/android/tools/r8/graph/ProgramDerivedContext.java b/src/main/java/com/android/tools/r8/graph/ProgramDerivedContext.java
index f9ec920..d46cf33 100644
--- a/src/main/java/com/android/tools/r8/graph/ProgramDerivedContext.java
+++ b/src/main/java/com/android/tools/r8/graph/ProgramDerivedContext.java
@@ -7,4 +7,8 @@
 public interface ProgramDerivedContext {
 
   Definition getContext();
+
+  default boolean isProgramContext() {
+    return getContext().isProgramDefinition();
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/graph/ResolutionResult.java b/src/main/java/com/android/tools/r8/graph/ResolutionResult.java
index 3356777..041033e 100644
--- a/src/main/java/com/android/tools/r8/graph/ResolutionResult.java
+++ b/src/main/java/com/android/tools/r8/graph/ResolutionResult.java
@@ -74,6 +74,11 @@
     return null;
   }
 
+  @Override
+  public DexClassAndMethod getResolutionPair() {
+    return null;
+  }
+
   public abstract OptionalBool isAccessibleForVirtualDispatchFrom(
       ProgramDefinition context, AppInfoWithClassHierarchy appInfo);
 
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/ClassConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/ClassConverter.java
index fb9c5d3..6d79c9c 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/ClassConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/ClassConverter.java
@@ -67,36 +67,36 @@
 
       // Process the wave and wait for all IR processing to complete.
       D8CfInstructionDesugaringEventConsumer desugaringEventConsumer =
-          CfInstructionDesugaringEventConsumer.createForD8(
-              resultBuilder::addSynthesizedLambdaClass, methodProcessor);
+          CfInstructionDesugaringEventConsumer.createForD8(methodProcessor);
       methodProcessor.newWave();
       ThreadUtils.processItems(
           wave, clazz -> convertClass(clazz, desugaringEventConsumer), executorService);
       methodProcessor.awaitMethodProcessing();
 
-      // Finalize the desugaring of the processed classes. This may require reprocessing of some
-      // methods, because nest-based access desugaring changes the body of virtual methods.
-      List<ProgramMethod> needsReprocessing = desugaringEventConsumer.finalizeDesugaring(appView);
-      if (!needsReprocessing.isEmpty()) {
+      // Finalize the desugaring of the processed classes. This may require processing (and
+      // reprocessing) of some methods.
+      List<ProgramMethod> needsProcessing =
+          desugaringEventConsumer.finalizeDesugaring(appView, resultBuilder);
+      if (!needsProcessing.isEmpty()) {
         // Create a new processor context to ensure unique method processing contexts.
         methodProcessor.newWave();
 
         // Process the methods that require reprocessing. These are all simple bridge methods and
         // should therefore not lead to additional desugaring.
         ThreadUtils.processItems(
-            needsReprocessing,
+            needsProcessing,
             method -> {
               DexEncodedMethod definition = method.getDefinition();
-              assert definition.isProcessed();
-              definition.markNotProcessed();
+              if (definition.isProcessed()) {
+                definition.markNotProcessed();
+              }
               methodProcessor.processMethod(method, desugaringEventConsumer);
             },
             executorService);
 
-        // Verify that there is no more desugaring to do, and that all IR processing has been
-        // completed.
+        // Verify there is nothing to finalize once method processing finishes.
+        methodProcessor.awaitMethodProcessing();
         assert desugaringEventConsumer.verifyNothingToFinalize();
-        assert methodProcessor.verifyNoPendingMethodProcessing();
       }
 
       classes = deferred;
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/ClassConverterResult.java b/src/main/java/com/android/tools/r8/ir/conversion/ClassConverterResult.java
index 4a07e14..e65179a 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/ClassConverterResult.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/ClassConverterResult.java
@@ -4,48 +4,38 @@
 
 package com.android.tools.r8.ir.conversion;
 
-import com.android.tools.r8.ir.desugar.LambdaClass;
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.List;
-import java.util.function.Consumer;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.ir.desugar.lambda.ForcefullyMovedLambdaMethodConsumer;
+import java.util.IdentityHashMap;
+import java.util.Map;
 
 public class ClassConverterResult {
 
-  private final List<LambdaClass> synthesizedLambdaClassesWithDeterministicOrder;
+  private final Map<DexMethod, DexMethod> forcefullyMovedLambdaMethods;
 
-  private ClassConverterResult(List<LambdaClass> synthesizedLambdaClassesWithDeterministicOrder) {
-    this.synthesizedLambdaClassesWithDeterministicOrder =
-        synthesizedLambdaClassesWithDeterministicOrder;
+  private ClassConverterResult(Map<DexMethod, DexMethod> forcefullyMovedLambdaMethods) {
+    this.forcefullyMovedLambdaMethods = forcefullyMovedLambdaMethods;
   }
 
   public static Builder builder() {
     return new Builder();
   }
 
-  public void forEachSynthesizedLambdaClassWithDeterministicOrdering(
-      Consumer<LambdaClass> consumer) {
-    synthesizedLambdaClassesWithDeterministicOrder.forEach(consumer);
+  public Map<DexMethod, DexMethod> getForcefullyMovedLambdaMethods() {
+    return forcefullyMovedLambdaMethods;
   }
 
-  public List<LambdaClass> getSynthesizedLambdaClasses() {
-    return synthesizedLambdaClassesWithDeterministicOrder;
-  }
+  public static class Builder implements ForcefullyMovedLambdaMethodConsumer {
 
-  public static class Builder {
+    private final Map<DexMethod, DexMethod> forcefullyMovedLambdaMethods = new IdentityHashMap<>();
 
-    private final List<LambdaClass> synthesizedLambdaClasses = new ArrayList<>();
-
-    public Builder addSynthesizedLambdaClass(LambdaClass lambdaClass) {
-      synchronized (synthesizedLambdaClasses) {
-        synthesizedLambdaClasses.add(lambdaClass);
-      }
-      return this;
+    @Override
+    public void acceptForcefullyMovedLambdaMethod(DexMethod from, DexMethod to) {
+      forcefullyMovedLambdaMethods.put(from, to);
     }
 
     public ClassConverterResult build() {
-      synthesizedLambdaClasses.sort(Comparator.comparing(LambdaClass::getType));
-      return new ClassConverterResult(synthesizedLambdaClasses);
+      return new ClassConverterResult(forcefullyMovedLambdaMethods);
     }
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/D8MethodProcessor.java b/src/main/java/com/android/tools/r8/ir/conversion/D8MethodProcessor.java
index bee8182..bb8e12a 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/D8MethodProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/D8MethodProcessor.java
@@ -9,6 +9,7 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
+import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer.D8CfInstructionDesugaringEventConsumer;
 import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackIgnore;
 import com.android.tools.r8.utils.ThreadUtils;
 import com.google.common.collect.Sets;
@@ -24,9 +25,18 @@
 
   private final IRConverter converter;
   private final ExecutorService executorService;
-  private final List<Future<?>> futures = Collections.synchronizedList(new ArrayList<>());
   private final Set<DexType> scheduled = Sets.newIdentityHashSet();
 
+  // Asynchronous method processing actions. These are "terminal" method processing actions in the
+  // sense that the method processing is known not to fork any other futures.
+  private final List<Future<?>> terminalFutures = Collections.synchronizedList(new ArrayList<>());
+
+  // Asynchronous method processing actions. This list includes both "terminal" and "non-terminal"
+  // method processing actions. Thus, before the asynchronous method processing finishes, it may
+  // fork the processing of another method.
+  private final List<Future<?>> nonTerminalFutures =
+      Collections.synchronizedList(new ArrayList<>());
+
   private ProcessorContext processorContext;
 
   public D8MethodProcessor(IRConverter converter, ExecutorService executorService) {
@@ -55,6 +65,27 @@
     return true;
   }
 
+  public void scheduleMethodForProcessing(
+      ProgramMethod method, D8CfInstructionDesugaringEventConsumer eventConsumer) {
+    // TODO(b/179755192): By building up waves of methods in the class converter, we can avoid the
+    //  following check and always process the method asynchronously.
+    if (!scheduled.contains(method.getHolderType())
+        && !converter.appView.getSyntheticItems().isNonLegacySynthetic(method.getHolder())) {
+      // The non-synthetic holder is not scheduled. It will be processed once holder is scheduled.
+      return;
+    }
+    nonTerminalFutures.add(
+        ThreadUtils.processAsynchronously(
+            () ->
+                converter.rewriteCode(
+                    method,
+                    eventConsumer,
+                    OptimizationFeedbackIgnore.getInstance(),
+                    this,
+                    processorContext.createMethodProcessingContext(method)),
+            executorService));
+  }
+
   @Override
   public void scheduleDesugaredMethodForProcessing(ProgramMethod method) {
     // TODO(b/179755192): By building up waves of methods in the class converter, we can avoid the
@@ -64,7 +95,7 @@
       // The non-synthetic holder is not scheduled. It will be processed once holder is scheduled.
       return;
     }
-    futures.add(
+    terminalFutures.add(
         ThreadUtils.processAsynchronously(
             () ->
                 converter.rewriteDesugaredCode(
@@ -86,8 +117,21 @@
   }
 
   public void awaitMethodProcessing() throws ExecutionException {
-    ThreadUtils.awaitFutures(futures);
-    futures.clear();
+    // Await the non-terminal futures until there are only terminal futures left.
+    while (!nonTerminalFutures.isEmpty()) {
+      List<Future<?>> futuresToAwait;
+      synchronized (nonTerminalFutures) {
+        futuresToAwait = new ArrayList<>(nonTerminalFutures);
+        nonTerminalFutures.clear();
+      }
+      ThreadUtils.awaitFutures(futuresToAwait);
+    }
+
+    // Await the terminal futures. There futures will by design not to fork new method processing.
+    int numberOfTerminalFutures = terminalFutures.size();
+    ThreadUtils.awaitFutures(terminalFutures);
+    assert terminalFutures.size() == numberOfTerminalFutures;
+    terminalFutures.clear();
   }
 
   public void processMethod(
@@ -99,12 +143,9 @@
         processorContext.createMethodProcessingContext(method));
   }
 
-  public void processDesugaredMethod(ProgramMethod method) {
-    processMethod(method, CfInstructionDesugaringEventConsumer.createForDesugaredCode());
-  }
-
   public boolean verifyNoPendingMethodProcessing() {
-    assert futures.isEmpty();
+    assert terminalFutures.isEmpty();
+    assert nonTerminalFutures.isEmpty();
     return true;
   }
 }
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 db7c135..72f9ac7 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
@@ -5,13 +5,12 @@
 
 import static com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.Flavor.ExcludeDexResources;
 import static com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.Flavor.IncludeAllResources;
-import static com.android.tools.r8.ir.desugar.lambda.D8LambdaDesugaring.synthesizeAccessibilityBridgesForLambdaClasses;
+import static com.android.tools.r8.ir.desugar.lambda.D8LambdaDesugaring.rewriteEnclosingLambdaMethodAttributes;
 
 import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
 import com.android.tools.r8.errors.CompilationError;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppInfo;
-import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.Code;
@@ -43,7 +42,6 @@
 import com.android.tools.r8.ir.code.InvokeStatic;
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.code.Value;
-import com.android.tools.r8.ir.desugar.BackportedMethodRewriter;
 import com.android.tools.r8.ir.desugar.CfInstructionDesugaringCollection;
 import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
 import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer.D8CfInstructionDesugaringEventConsumer;
@@ -53,8 +51,6 @@
 import com.android.tools.r8.ir.desugar.DesugaredLibraryRetargeter;
 import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
 import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.Flavor;
-import com.android.tools.r8.ir.desugar.StringConcatRewriter;
-import com.android.tools.r8.ir.desugar.TwrCloseResourceRewriter;
 import com.android.tools.r8.ir.desugar.lambda.LambdaDeserializationMethodRemover;
 import com.android.tools.r8.ir.desugar.nest.D8NestBasedAccessDesugaring;
 import com.android.tools.r8.ir.optimize.AssertionsRewriter;
@@ -101,10 +97,8 @@
 import com.android.tools.r8.utils.ExceptionUtils;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.InternalOptions.DesugarState;
-import com.android.tools.r8.utils.IterableUtils;
 import com.android.tools.r8.utils.ListUtils;
 import com.android.tools.r8.utils.StringDiagnostic;
-import com.android.tools.r8.utils.SupplierUtils;
 import com.android.tools.r8.utils.ThreadUtils;
 import com.android.tools.r8.utils.Timing;
 import com.android.tools.r8.utils.collections.ProgramMethodSet;
@@ -134,13 +128,10 @@
   private final CfInstructionDesugaringCollection desugaring;
   private final FieldAccessAnalysis fieldAccessAnalysis;
   private final LibraryMethodOverrideAnalysis libraryMethodOverrideAnalysis;
-  private final StringConcatRewriter stringConcatRewriter;
   private final StringOptimizer stringOptimizer;
   private final StringBuilderOptimizer stringBuilderOptimizer;
   private final IdempotentFunctionCallCanonicalizer idempotentFunctionCallCanonicalizer;
   private final InterfaceMethodRewriter interfaceMethodRewriter;
-  private final TwrCloseResourceRewriter twrCloseResourceRewriter;
-  private final BackportedMethodRewriter backportedMethodRewriter;
   private final DesugaredLibraryRetargeter desugaredLibraryRetargeter;
   private final ClassInliner classInliner;
   private final ClassStaticizer classStaticizer;
@@ -199,7 +190,6 @@
     this.constantCanonicalizer = new ConstantCanonicalizer(codeRewriter);
     this.classInitializerDefaultsOptimization =
         new ClassInitializerDefaultsOptimization(appView, this);
-    this.stringConcatRewriter = new StringConcatRewriter(appView);
     this.stringOptimizer = new StringOptimizer(appView);
     this.stringBuilderOptimizer = new StringBuilderOptimizer(appView);
     this.deadCodeRemover = new DeadCodeRemover(appView, codeRewriter);
@@ -223,7 +213,7 @@
       // The following desugaring are present so all desugaring is performed cf to cf in L8, and
       // the second L8 phase can just run with Desugar turned off:
       // - InterfaceMethodRewriter for non L8 specific interface method desugaring,
-      // - TwrCloseResourceRewriter,
+      // - twr close resource desugaring,
       // - nest based access desugaring,
       // - invoke-special desugaring.
       assert options.desugarState.isOn();
@@ -238,11 +228,6 @@
               : new InterfaceMethodRewriter(appView, this);
       this.desugaredLibraryAPIConverter =
           new DesugaredLibraryAPIConverter(appView, Mode.GENERATE_CALLBACKS_AND_WRAPPERS);
-      this.backportedMethodRewriter = new BackportedMethodRewriter(appView);
-      this.twrCloseResourceRewriter =
-          TwrCloseResourceRewriter.enableTwrCloseResourceDesugaring(appView.options())
-              ? new TwrCloseResourceRewriter(appView)
-              : null;
       this.covariantReturnTypeAnnotationTransformer = null;
       this.dynamicTypeOptimization = null;
       this.classInliner = null;
@@ -272,15 +257,6 @@
         options.isInterfaceMethodDesugaringEnabled()
             ? new InterfaceMethodRewriter(appView, this)
             : null;
-    this.twrCloseResourceRewriter =
-        (TwrCloseResourceRewriter.enableTwrCloseResourceDesugaring(options)
-                && !appView.enableWholeProgramOptimizations())
-            ? new TwrCloseResourceRewriter(appView)
-            : null;
-    this.backportedMethodRewriter =
-        (options.desugarState == DesugarState.ON && !appView.enableWholeProgramOptimizations())
-            ? new BackportedMethodRewriter(appView)
-            : null;
     this.desugaredLibraryRetargeter =
         options.desugaredLibraryConfiguration.getRetargetCoreLibMember().isEmpty()
             ? null
@@ -410,19 +386,6 @@
     }
   }
 
-  private void processTwrCloseResourceUtilityMethods() {
-    if (twrCloseResourceRewriter != null) {
-      twrCloseResourceRewriter.processSynthesizedMethods(this);
-    }
-  }
-
-  private void processSynthesizedJava8UtilityClasses(ExecutorService executorService)
-      throws ExecutionException {
-    if (backportedMethodRewriter != null) {
-      backportedMethodRewriter.processSynthesizedClasses(this, executorService);
-    }
-  }
-
   private void synthesizeRetargetClass(Builder<?> builder, ExecutorService executorService)
       throws ExecutionException {
     if (desugaredLibraryRetargeter != null) {
@@ -454,7 +417,6 @@
     convertClasses(executor);
 
     reportNestDesugarDependencies();
-    processTwrCloseResourceUtilityMethods();
 
     if (appView.getSyntheticItems().hasPendingSyntheticClasses()) {
       appView.setAppInfo(
@@ -468,7 +430,6 @@
     Builder<?> builder = application.builder().setHighestSortingString(highestSortingString);
 
     desugarInterfaceMethods(builder, ExcludeDexResources, executor);
-    processSynthesizedJava8UtilityClasses(executor);
     synthesizeRetargetClass(builder, executor);
     processCovariantReturnTypeAnnotations(builder);
     generateDesugaredLibraryAPIWrappers(builder, executor);
@@ -487,19 +448,15 @@
     ClassConverterResult classConverterResult =
         ClassConverter.create(appView, this, methodProcessor).convertClasses(executorService);
 
-    // The synthesis of accessibility bridges in lambda desugaring and nest based access desugaring
-    // will schedule and await the processing of synthesized methods.
+    // The synthesis of accessibility bridges in nest based access desugaring will schedule and
+    // await the processing of synthesized methods.
     synthesizeBridgesForNestBasedAccessesOnClasspath(methodProcessor, executorService);
-    synthesizeAccessibilityBridgesForLambdaClasses(appView, classConverterResult, methodProcessor);
-    methodProcessor
-        .scheduleDesugaredMethodsForProcessing(
-            IterableUtils.flatMap(
-                classConverterResult.getSynthesizedLambdaClasses(),
-                lambdaClass -> lambdaClass.getLambdaProgramClass().programMethods()))
-        .awaitMethodProcessing();
 
     // There should be no outstanding method processing.
     methodProcessor.verifyNoPendingMethodProcessing();
+
+    rewriteEnclosingLambdaMethodAttributes(
+        appView, classConverterResult.getForcefullyMovedLambdaMethods());
   }
 
   void convertMethods(
@@ -584,14 +541,12 @@
     if (options.isDesugaredLibraryCompilation()) {
       return true;
     }
-
     if (!options.cfToCfDesugar) {
       return true;
     }
-    if (method.getHolder().isInANest()) {
+    if (desugaring.needsDesugaring(method)) {
       return true;
     }
-
     if (desugaredLibraryAPIConverter != null
         && desugaredLibraryAPIConverter.shouldRegisterCallback(method)) {
       return true;
@@ -600,7 +555,6 @@
     NeedsIRDesugarUseRegistry useRegistry =
         new NeedsIRDesugarUseRegistry(
             appView,
-            backportedMethodRewriter,
             desugaredLibraryRetargeter,
             interfaceMethodRewriter,
             desugaredLibraryAPIConverter);
@@ -793,7 +747,6 @@
     feedback.updateVisibleOptimizationInfo();
 
     printPhase("Utility classes synthesis");
-    processSynthesizedJava8UtilityClasses(executorService);
     synthesizeRetargetClass(builder, executorService);
     synthesizeEnumUnboxingUtilityMethods(executorService);
 
@@ -1129,8 +1082,7 @@
           method.toSourceString(),
           logCode(options, method.getDefinition()));
     }
-    boolean didDesugar =
-        desugar(method, desugaringEventConsumer, methodProcessor, methodProcessingContext);
+    boolean didDesugar = desugar(method, desugaringEventConsumer, methodProcessingContext);
     if (Log.ENABLED && didDesugar) {
       Log.debug(
           getClass(),
@@ -1156,24 +1108,14 @@
   private boolean desugar(
       ProgramMethod method,
       CfInstructionDesugaringEventConsumer desugaringEventConsumer,
-      MethodProcessor methodProcessor,
       MethodProcessingContext methodProcessingContext) {
-    if (options.desugarState.isOff() || !method.getDefinition().getCode().isCfCode()) {
+    if (options.desugarState.isOff()
+        || !method.getDefinition().getCode().isCfCode()
+        || !desugaring.needsDesugaring(method)) {
       return false;
     }
-
-    boolean didDesugar = false;
-    Supplier<AppInfoWithClassHierarchy> lazyAppInfo =
-        SupplierUtils.nonThreadSafeMemoize(appView::appInfoForDesugaring);
-    if (desugaring.needsDesugaring(method)) {
-      desugaring.desugar(method, methodProcessingContext, desugaringEventConsumer);
-      didDesugar = true;
-    }
-    if (backportedMethodRewriter != null) {
-      didDesugar |=
-          backportedMethodRewriter.desugar(method, lazyAppInfo.get(), methodProcessingContext);
-    }
-    return didDesugar;
+    desugaring.desugar(method, methodProcessingContext, desugaringEventConsumer);
+    return true;
   }
 
   // TODO(b/140766440): Convert all sub steps an implementer of CodeOptimization
@@ -1457,10 +1399,6 @@
       timing.end();
     }
 
-    timing.begin("Desugar string concat");
-    stringConcatRewriter.desugarStringConcats(method.method, code);
-    timing.end();
-
     previous = printMethod(code, "IR after lambda desugaring (SSA)", previous);
 
     assert code.verifyTypes(appView);
@@ -1520,12 +1458,6 @@
 
     previous = printMethod(code, "IR after desugared library API Conversion (SSA)", previous);
 
-    if (twrCloseResourceRewriter != null) {
-      timing.begin("Rewrite TWR close");
-      twrCloseResourceRewriter.rewriteIR(code, methodProcessingContext);
-      timing.end();
-    }
-
     assert code.verifyTypes(appView);
 
     previous = printMethod(code, "IR after twr close resource rewriter (SSA)", previous);
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/NeedsIRDesugarUseRegistry.java b/src/main/java/com/android/tools/r8/ir/conversion/NeedsIRDesugarUseRegistry.java
index c12c6f0..9877f8d 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/NeedsIRDesugarUseRegistry.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/NeedsIRDesugarUseRegistry.java
@@ -17,30 +17,23 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.UseRegistry;
 import com.android.tools.r8.ir.code.Invoke.Type;
-import com.android.tools.r8.ir.desugar.BackportedMethodRewriter;
 import com.android.tools.r8.ir.desugar.DesugaredLibraryAPIConverter;
 import com.android.tools.r8.ir.desugar.DesugaredLibraryRetargeter;
 import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
-import com.android.tools.r8.ir.desugar.TwrCloseResourceRewriter;
 
 class NeedsIRDesugarUseRegistry extends UseRegistry {
 
   private boolean needsDesugaring = false;
-  private final AppView appView;
-  private final BackportedMethodRewriter backportedMethodRewriter;
   private final DesugaredLibraryRetargeter desugaredLibraryRetargeter;
   private final InterfaceMethodRewriter interfaceMethodRewriter;
   private final DesugaredLibraryAPIConverter desugaredLibraryAPIConverter;
 
   public NeedsIRDesugarUseRegistry(
-      AppView appView,
-      BackportedMethodRewriter backportedMethodRewriter,
+      AppView<?> appView,
       DesugaredLibraryRetargeter desugaredLibraryRetargeter,
       InterfaceMethodRewriter interfaceMethodRewriter,
       DesugaredLibraryAPIConverter desugaredLibraryAPIConverter) {
     super(appView.dexItemFactory());
-    this.appView = appView;
-    this.backportedMethodRewriter = backportedMethodRewriter;
     this.desugaredLibraryRetargeter = desugaredLibraryRetargeter;
     this.interfaceMethodRewriter = interfaceMethodRewriter;
     this.desugaredLibraryAPIConverter = desugaredLibraryAPIConverter;
@@ -61,7 +54,6 @@
 
   @Override
   public void registerInvokeVirtual(DexMethod method) {
-    registerBackportedMethodRewriting(method);
     registerLibraryRetargeting(method, false);
     registerInterfaceMethodRewriting(method, VIRTUAL);
     registerDesugaredLibraryAPIConverter(method);
@@ -74,19 +66,6 @@
     registerDesugaredLibraryAPIConverter(method);
   }
 
-  private void registerTwrCloseResourceRewriting(DexMethod method) {
-    if (!needsDesugaring) {
-      needsDesugaring =
-          TwrCloseResourceRewriter.isTwrCloseResourceMethod(method, appView.dexItemFactory());
-    }
-  }
-
-  private void registerBackportedMethodRewriting(DexMethod method) {
-    if (!needsDesugaring) {
-      needsDesugaring = backportedMethodRewriter.needsDesugaring(method);
-    }
-  }
-
   private void registerInterfaceMethodRewriting(DexMethod method, Type invokeType) {
     if (!needsDesugaring) {
       needsDesugaring =
@@ -113,8 +92,6 @@
 
   @Override
   public void registerInvokeStatic(DexMethod method) {
-    registerTwrCloseResourceRewriting(method);
-    registerBackportedMethodRewriting(method);
     registerLibraryRetargeting(method, false);
     registerInterfaceMethodRewriting(method, STATIC);
     registerDesugaredLibraryAPIConverter(method);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
index 704ed92..998b47c 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
@@ -10,7 +10,6 @@
 import com.android.tools.r8.dex.ApplicationReader;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppInfo;
-import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.Code;
@@ -22,7 +21,7 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.MethodAccessFlags;
 import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.ir.conversion.IRConverter;
+import com.android.tools.r8.ir.desugar.backports.BackportedMethodDesugaringEventConsumer;
 import com.android.tools.r8.ir.desugar.backports.BackportedMethods;
 import com.android.tools.r8.ir.desugar.backports.BooleanMethodRewrites;
 import com.android.tools.r8.ir.desugar.backports.CollectionMethodGenerators;
@@ -36,42 +35,59 @@
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.InternalOptions;
-import com.android.tools.r8.utils.InternalOptions.DesugarState;
-import com.android.tools.r8.utils.StringDiagnostic;
 import com.android.tools.r8.utils.Timing;
+import com.google.common.collect.ImmutableList;
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.IdentityHashMap;
 import java.util.List;
-import java.util.ListIterator;
 import java.util.Map;
-import java.util.Queue;
-import java.util.concurrent.ConcurrentLinkedQueue;
-import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
 import java.util.function.Consumer;
 import org.objectweb.asm.Opcodes;
 
-public final class BackportedMethodRewriter {
+public final class BackportedMethodRewriter implements CfInstructionDesugaring {
 
   private final AppView<?> appView;
   private final RewritableMethods rewritableMethods;
-  private final boolean enabled;
-
-  private final Queue<ProgramMethod> synthesizedMethods = new ConcurrentLinkedQueue<>();
 
   public BackportedMethodRewriter(AppView<?> appView) {
+    assert appView.options().desugarState.isOn();
     this.appView = appView;
     this.rewritableMethods = new RewritableMethods(appView.options(), appView);
-    // Disable rewriting if there are no methods to rewrite or if the API level is higher than
-    // the highest known API level when the compiler is built. This ensures that when this is used
-    // by the Android Platform build (which normally use an API level of 10000) there will be
-    // no rewriting of backported methods. See b/147480264.
-    this.enabled =
-        appView.options().desugarState == DesugarState.ON
-            && !this.rewritableMethods.isEmpty()
-            && appView.options().minApiLevel <= AndroidApiLevel.LATEST.getLevel();
+  }
+
+  public boolean hasBackports() {
+    return !rewritableMethods.isEmpty();
+  }
+
+  @Override
+  public Collection<CfInstruction> desugarInstruction(
+      CfInstruction instruction,
+      FreshLocalProvider freshLocalProvider,
+      LocalStackAllocator localStackAllocator,
+      CfInstructionDesugaringEventConsumer eventConsumer,
+      ProgramMethod context,
+      MethodProcessingContext methodProcessingContext) {
+    if (!instruction.isInvoke()) {
+      return null;
+    }
+
+    CfInvoke invoke = instruction.asInvoke();
+    DexMethod invokedMethod = invoke.getMethod();
+    if (!needsDesugaring(invokedMethod)) {
+      return null;
+    }
+
+    return getMethodProviderOrNull(invokedMethod)
+        .rewriteInvoke(invoke, appView, eventConsumer, methodProcessingContext);
+  }
+
+  @Override
+  public boolean needsDesugaring(CfInstruction instruction, ProgramMethod context) {
+    return instruction.isInvoke() && needsDesugaring(instruction.asInvoke().getMethod());
   }
 
   public boolean needsDesugaring(DexMethod method) {
@@ -106,65 +122,6 @@
     BackportedMethods.registerSynthesizedCodeReferences(options.itemFactory);
   }
 
-  public boolean desugar(
-      ProgramMethod method,
-      AppInfoWithClassHierarchy appInfo,
-      MethodProcessingContext methodProcessingContext) {
-    return desugar(method, appInfo, methodProcessingContext, synthesizedMethods::add);
-  }
-
-  public boolean desugar(
-      ProgramMethod method,
-      AppInfoWithClassHierarchy appInfo,
-      MethodProcessingContext methodProcessingContext,
-      Consumer<ProgramMethod> consumer) {
-    if (!enabled) {
-      return false;
-    }
-    if (method.getDefinition().getCode().isDexCode()) {
-      appView
-          .options()
-          .reporter
-          .error(
-              new StringDiagnostic(
-                  "Unsupported attempt to desugar DEX code",
-                  method.getOrigin(),
-                  method.getPosition()));
-      return false;
-    }
-    CfCode code = method.getDefinition().getCode().asCfCode();
-    ListIterator<CfInstruction> iterator = code.getInstructions().listIterator();
-    boolean replaced = false;
-    while (iterator.hasNext()) {
-      CfInvoke invoke = iterator.next().asInvoke();
-      if (invoke == null) {
-        continue;
-      }
-      DexMethod invokedMethod = invoke.getMethod();
-      MethodProvider provider = getMethodProviderOrNull(invokedMethod);
-      if (provider != null) {
-        if (!replaced) {
-          // Create mutable instructions on first write.
-          ArrayList<CfInstruction> mutableInstructions = new ArrayList<>(code.getInstructions());
-          code.setInstructions(mutableInstructions);
-          iterator = mutableInstructions.listIterator(iterator.previousIndex());
-          iterator.next();
-        }
-        provider.rewriteInvoke(invoke, iterator, appInfo, consumer, methodProcessingContext);
-        replaced = true;
-      }
-    }
-    return replaced;
-  }
-
-  public void processSynthesizedClasses(IRConverter converter, ExecutorService executor)
-      throws ExecutionException {
-    while (!synthesizedMethods.isEmpty()) {
-      ArrayList<ProgramMethod> methods = new ArrayList<>(synthesizedMethods);
-      synthesizedMethods.clear();
-      converter.optimizeSynthesizedMethods(methods, executor);
-    }
-  }
 
   private MethodProvider getMethodProviderOrNull(DexMethod method) {
     DexMethod original = appView.graphLens().getOriginalMethodSignature(method);
@@ -212,7 +169,7 @@
       DexItemFactory factory = options.itemFactory;
 
       if (options.minApiLevel < AndroidApiLevel.K.getLevel()) {
-        initializeAndroidKMethodProviders(factory, appView);
+        initializeAndroidKMethodProviders(factory);
       }
       if (options.minApiLevel < AndroidApiLevel.N.getLevel()) {
         initializeAndroidNMethodProviders(factory);
@@ -253,7 +210,7 @@
       rewritable.keySet().forEach(consumer);
     }
 
-    private void initializeAndroidKMethodProviders(DexItemFactory factory, AppView<?> appView) {
+    private void initializeAndroidKMethodProviders(DexItemFactory factory) {
       // Byte
       DexType type = factory.boxedByteType;
       // int Byte.compare(byte a, byte b)
@@ -579,20 +536,19 @@
 
       // Math & StrictMath, which have some symmetric, binary-compatible APIs
       DexType[] mathTypes = {factory.mathType, factory.strictMathType};
-      for (int i = 0; i < mathTypes.length; i++) {
-        type = mathTypes[i];
+      for (DexType mathType : mathTypes) {
 
         // int {Math,StrictMath}.addExact(int, int)
         name = factory.createString("addExact");
         proto = factory.createProto(factory.intType, factory.intType, factory.intType);
-        method = factory.createMethod(type, proto, name);
+        method = factory.createMethod(mathType, proto, name);
         addProvider(
             new MethodGenerator(method, BackportedMethods::MathMethods_addExactInt, "addExactInt"));
 
         // long {Math,StrictMath}.addExact(long, long)
         name = factory.createString("addExact");
         proto = factory.createProto(factory.longType, factory.longType, factory.longType);
-        method = factory.createMethod(type, proto, name);
+        method = factory.createMethod(mathType, proto, name);
         addProvider(
             new MethodGenerator(
                 method, BackportedMethods::MathMethods_addExactLong, "addExactLong"));
@@ -600,14 +556,14 @@
         // int {Math,StrictMath}.floorDiv(int, int)
         name = factory.createString("floorDiv");
         proto = factory.createProto(factory.intType, factory.intType, factory.intType);
-        method = factory.createMethod(type, proto, name);
+        method = factory.createMethod(mathType, proto, name);
         addProvider(
             new MethodGenerator(method, BackportedMethods::MathMethods_floorDivInt, "floorDivInt"));
 
         // long {Math,StrictMath}.floorDiv(long, long)
         name = factory.createString("floorDiv");
         proto = factory.createProto(factory.longType, factory.longType, factory.longType);
-        method = factory.createMethod(type, proto, name);
+        method = factory.createMethod(mathType, proto, name);
         addProvider(
             new MethodGenerator(
                 method, BackportedMethods::MathMethods_floorDivLong, "floorDivLong"));
@@ -615,14 +571,14 @@
         // int {Math,StrictMath}.floorMod(int, int)
         name = factory.createString("floorMod");
         proto = factory.createProto(factory.intType, factory.intType, factory.intType);
-        method = factory.createMethod(type, proto, name);
+        method = factory.createMethod(mathType, proto, name);
         addProvider(
             new MethodGenerator(method, BackportedMethods::MathMethods_floorModInt, "floorModInt"));
 
         // long {Math,StrictMath}.floorMod(long, long)
         name = factory.createString("floorMod");
         proto = factory.createProto(factory.longType, factory.longType, factory.longType);
-        method = factory.createMethod(type, proto, name);
+        method = factory.createMethod(mathType, proto, name);
         addProvider(
             new MethodGenerator(
                 method, BackportedMethods::MathMethods_floorModLong, "floorModLong"));
@@ -630,7 +586,7 @@
         // int {Math,StrictMath}.multiplyExact(int, int)
         name = factory.createString("multiplyExact");
         proto = factory.createProto(factory.intType, factory.intType, factory.intType);
-        method = factory.createMethod(type, proto, name);
+        method = factory.createMethod(mathType, proto, name);
         addProvider(
             new MethodGenerator(
                 method, BackportedMethods::MathMethods_multiplyExactInt, "multiplyExactInt"));
@@ -638,7 +594,7 @@
         // long {Math,StrictMath}.multiplyExact(long, long)
         name = factory.createString("multiplyExact");
         proto = factory.createProto(factory.longType, factory.longType, factory.longType);
-        method = factory.createMethod(type, proto, name);
+        method = factory.createMethod(mathType, proto, name);
         addProvider(
             new MethodGenerator(
                 method, BackportedMethods::MathMethods_multiplyExactLong, "multiplyExactLong"));
@@ -646,7 +602,7 @@
         // double {Math,StrictMath}.nextDown(double)
         name = factory.createString("nextDown");
         proto = factory.createProto(factory.doubleType, factory.doubleType);
-        method = factory.createMethod(type, proto, name);
+        method = factory.createMethod(mathType, proto, name);
         addProvider(
             new MethodGenerator(
                 method, BackportedMethods::MathMethods_nextDownDouble, "nextDownDouble"));
@@ -654,7 +610,7 @@
         // float {Math,StrictMath}.nextDown(float)
         name = factory.createString("nextDown");
         proto = factory.createProto(factory.floatType, factory.floatType);
-        method = factory.createMethod(type, proto, name);
+        method = factory.createMethod(mathType, proto, name);
         addProvider(
             new MethodGenerator(
                 method, BackportedMethods::MathMethods_nextDownFloat, "nextDownFloat"));
@@ -662,7 +618,7 @@
         // int {Math,StrictMath}.subtractExact(int, int)
         name = factory.createString("subtractExact");
         proto = factory.createProto(factory.intType, factory.intType, factory.intType);
-        method = factory.createMethod(type, proto, name);
+        method = factory.createMethod(mathType, proto, name);
         addProvider(
             new MethodGenerator(
                 method, BackportedMethods::MathMethods_subtractExactInt, "subtractExactInt"));
@@ -670,7 +626,7 @@
         // long {Math,StrictMath}.subtractExact(long, long)
         name = factory.createString("subtractExact");
         proto = factory.createProto(factory.longType, factory.longType, factory.longType);
-        method = factory.createMethod(type, proto, name);
+        method = factory.createMethod(mathType, proto, name);
         addProvider(
             new MethodGenerator(
                 method, BackportedMethods::MathMethods_subtractExactLong, "subtractExactLong"));
@@ -678,7 +634,7 @@
         // int {Math,StrictMath}.toIntExact(long)
         name = factory.createString("toIntExact");
         proto = factory.createProto(factory.intType, factory.longType);
-        method = factory.createMethod(type, proto, name);
+        method = factory.createMethod(mathType, proto, name);
         addProvider(new MethodGenerator(method, BackportedMethods::MathMethods_toIntExact));
       }
 
@@ -1015,13 +971,12 @@
     private void initializeJava9MethodProviders(DexItemFactory factory) {
       // Math & StrictMath, which have some symmetric, binary-compatible APIs
       DexType[] mathTypes = {factory.mathType, factory.strictMathType};
-      for (int i = 0; i < mathTypes.length; i++) {
-        DexType type = mathTypes[i];
+      for (DexType mathType : mathTypes) {
 
         // long {Math,StrictMath}.multiplyExact(long, int)
         DexString name = factory.createString("multiplyExact");
         DexProto proto = factory.createProto(factory.longType, factory.longType, factory.intType);
-        DexMethod method = factory.createMethod(type, proto, name);
+        DexMethod method = factory.createMethod(mathType, proto, name);
         addProvider(
             new MethodGenerator(
                 method,
@@ -1031,19 +986,19 @@
         // long {Math,StrictMath}.multiplyFull(int, int)
         name = factory.createString("multiplyFull");
         proto = factory.createProto(factory.longType, factory.intType, factory.intType);
-        method = factory.createMethod(type, proto, name);
+        method = factory.createMethod(mathType, proto, name);
         addProvider(new MethodGenerator(method, BackportedMethods::MathMethods_multiplyFull));
 
         // long {Math,StrictMath}.multiplyHigh(long, long)
         name = factory.createString("multiplyHigh");
         proto = factory.createProto(factory.longType, factory.longType, factory.longType);
-        method = factory.createMethod(type, proto, name);
+        method = factory.createMethod(mathType, proto, name);
         addProvider(new MethodGenerator(method, BackportedMethods::MathMethods_multiplyHigh));
 
         // long {Math,StrictMath}.floorDiv(long, int)
         name = factory.createString("floorDiv");
         proto = factory.createProto(factory.longType, factory.longType, factory.intType);
-        method = factory.createMethod(type, proto, name);
+        method = factory.createMethod(mathType, proto, name);
         addProvider(
             new MethodGenerator(
                 method, BackportedMethods::MathMethods_floorDivLongInt, "floorDivLongInt"));
@@ -1051,7 +1006,7 @@
         // int {Math,StrictMath}.floorMod(long, int)
         name = factory.createString("floorMod");
         proto = factory.createProto(factory.intType, factory.longType, factory.intType);
-        method = factory.createMethod(type, proto, name);
+        method = factory.createMethod(mathType, proto, name);
         addProvider(
             new MethodGenerator(
                 method, BackportedMethods::MathMethods_floorModLongInt, "floorModLongInt"));
@@ -1349,11 +1304,10 @@
       this.method = method;
     }
 
-    public abstract void rewriteInvoke(
+    public abstract Collection<CfInstruction> rewriteInvoke(
         CfInvoke invoke,
-        ListIterator<CfInstruction> iterator,
-        AppInfoWithClassHierarchy appInfo,
-        Consumer<ProgramMethod> registerSynthesizedMethod,
+        AppView<?> appView,
+        BackportedMethodDesugaringEventConsumer eventConsumer,
         MethodProcessingContext methodProcessingContext);
   }
 
@@ -1367,13 +1321,12 @@
     }
 
     @Override
-    public void rewriteInvoke(
+    public Collection<CfInstruction> rewriteInvoke(
         CfInvoke invoke,
-        ListIterator<CfInstruction> iterator,
-        AppInfoWithClassHierarchy appInfo,
-        Consumer<ProgramMethod> registerSynthesizedMethod,
+        AppView<?> appView,
+        BackportedMethodDesugaringEventConsumer eventConsumer,
         MethodProcessingContext methodProcessingContext) {
-      rewriter.rewrite(invoke, iterator, appInfo.dexItemFactory());
+      return rewriter.rewrite(invoke, appView.dexItemFactory());
     }
   }
 
@@ -1393,32 +1346,29 @@
     }
 
     @Override
-    public void rewriteInvoke(
+    public Collection<CfInstruction> rewriteInvoke(
         CfInvoke invoke,
-        ListIterator<CfInstruction> iterator,
-        AppInfoWithClassHierarchy appInfo,
-        Consumer<ProgramMethod> registerSynthesizedMethod,
+        AppView<?> appView,
+        BackportedMethodDesugaringEventConsumer eventConsumer,
         MethodProcessingContext methodProcessingContext) {
-      ProgramMethod method = getSyntheticMethod(appInfo, methodProcessingContext);
-      registerSynthesizedMethod.accept(method);
-      iterator.remove();
-      iterator.add(new CfInvoke(Opcodes.INVOKESTATIC, method.getReference(), false));
+      ProgramMethod method = getSyntheticMethod(appView, methodProcessingContext);
+      eventConsumer.acceptBackportedMethod(method, methodProcessingContext.getMethodContext());
+      return ImmutableList.of(new CfInvoke(Opcodes.INVOKESTATIC, method.getReference(), false));
     }
 
     private ProgramMethod getSyntheticMethod(
-        AppInfoWithClassHierarchy appInfo, MethodProcessingContext methodProcessingContext) {
-      return appInfo
+        AppView<?> appView, MethodProcessingContext methodProcessingContext) {
+      return appView
           .getSyntheticItems()
           .createMethod(
               SyntheticNaming.SyntheticKind.BACKPORT,
               methodProcessingContext.createUniqueContext(),
-              appInfo.dexItemFactory(),
+              appView.dexItemFactory(),
               builder ->
                   builder
-                      .setProto(getProto(appInfo.dexItemFactory()))
+                      .setProto(getProto(appView.dexItemFactory()))
                       .setAccessFlags(MethodAccessFlags.createPublicStaticSynthetic())
-                      .setCode(
-                          methodSig -> generateTemplateMethod(appInfo.app().options, methodSig)));
+                      .setCode(methodSig -> generateTemplateMethod(appView.options(), methodSig)));
     }
 
     public DexProto getProto(DexItemFactory itemFactory) {
@@ -1459,10 +1409,8 @@
     CfInstruction rewriteSingle(CfInvoke invoke, DexItemFactory factory);
 
     // Convenience wrapper since most rewrites are to a single instruction.
-    default void rewrite(
-        CfInvoke invoke, ListIterator<CfInstruction> iterator, DexItemFactory factory) {
-      iterator.remove();
-      iterator.add(rewriteSingle(invoke, factory));
+    default Collection<CfInstruction> rewrite(CfInvoke invoke, DexItemFactory factory) {
+      return ImmutableList.of(rewriteSingle(invoke, factory));
     }
   }
 
@@ -1474,7 +1422,6 @@
     }
 
     @Override
-    public abstract void rewrite(
-        CfInvoke invoke, ListIterator<CfInstruction> iterator, DexItemFactory factory);
+    public abstract Collection<CfInstruction> rewrite(CfInvoke invoke, DexItemFactory factory);
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaring.java
index 22b1d92..b4cab05 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaring.java
@@ -19,6 +19,7 @@
   Collection<CfInstruction> desugarInstruction(
       CfInstruction instruction,
       FreshLocalProvider freshLocalProvider,
+      LocalStackAllocator localStackAllocator,
       CfInstructionDesugaringEventConsumer eventConsumer,
       ProgramMethod context,
       MethodProcessingContext methodProcessingContext);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java
index 4041efd..d765537 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java
@@ -10,12 +10,15 @@
 import com.android.tools.r8.graph.DexReference;
 import com.android.tools.r8.graph.ProgramField;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.conversion.ClassConverterResult;
 import com.android.tools.r8.ir.conversion.D8MethodProcessor;
+import com.android.tools.r8.ir.desugar.backports.BackportedMethodDesugaringEventConsumer;
 import com.android.tools.r8.ir.desugar.invokespecial.InvokeSpecialBridgeInfo;
 import com.android.tools.r8.ir.desugar.invokespecial.InvokeSpecialToSelfDesugaringEventConsumer;
 import com.android.tools.r8.ir.desugar.lambda.LambdaDeserializationMethodRemover;
 import com.android.tools.r8.ir.desugar.lambda.LambdaDesugaringEventConsumer;
 import com.android.tools.r8.ir.desugar.nest.NestBasedAccessDesugaringEventConsumer;
+import com.android.tools.r8.ir.desugar.twr.TwrCloseResourceDesugaringEventConsumer;
 import com.google.common.collect.Sets;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -24,6 +27,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.function.BiConsumer;
 import java.util.function.Consumer;
 
 /**
@@ -31,24 +35,34 @@
  * inserting of a new method).
  */
 public abstract class CfInstructionDesugaringEventConsumer
-    implements InvokeSpecialToSelfDesugaringEventConsumer,
+    implements BackportedMethodDesugaringEventConsumer,
+        InvokeSpecialToSelfDesugaringEventConsumer,
         LambdaDesugaringEventConsumer,
-        NestBasedAccessDesugaringEventConsumer {
+        NestBasedAccessDesugaringEventConsumer,
+        TwrCloseResourceDesugaringEventConsumer {
 
   public static D8CfInstructionDesugaringEventConsumer createForD8(
-      Consumer<LambdaClass> lambdaClassConsumer, D8MethodProcessor methodProcessor) {
-    return new D8CfInstructionDesugaringEventConsumer(lambdaClassConsumer, methodProcessor);
+      D8MethodProcessor methodProcessor) {
+    return new D8CfInstructionDesugaringEventConsumer(methodProcessor);
   }
 
   public static R8CfInstructionDesugaringEventConsumer createForR8(
-      AppView<? extends AppInfoWithClassHierarchy> appView) {
-    return new R8CfInstructionDesugaringEventConsumer(appView);
+      AppView<? extends AppInfoWithClassHierarchy> appView,
+      BiConsumer<LambdaClass, ProgramMethod> lambdaClassConsumer,
+      BiConsumer<ProgramMethod, ProgramMethod> twrCloseResourceMethodConsumer) {
+    return new R8CfInstructionDesugaringEventConsumer(
+        appView, lambdaClassConsumer, twrCloseResourceMethodConsumer);
   }
 
   public static CfInstructionDesugaringEventConsumer createForDesugaredCode() {
     return new CfInstructionDesugaringEventConsumer() {
 
       @Override
+      public void acceptBackportedMethod(ProgramMethod backportedMethod, ProgramMethod context) {
+        assert false;
+      }
+
+      @Override
       public void acceptInvokeSpecialBridgeInfo(InvokeSpecialBridgeInfo info) {
         assert false;
       }
@@ -72,25 +86,33 @@
       public void acceptNestMethodBridge(ProgramMethod target, ProgramMethod bridge) {
         assert false;
       }
+
+      @Override
+      public void acceptTwrCloseResourceMethod(ProgramMethod closeMethod, ProgramMethod context) {
+        assert false;
+      }
     };
   }
 
   public static class D8CfInstructionDesugaringEventConsumer
       extends CfInstructionDesugaringEventConsumer {
 
-    private final Consumer<LambdaClass> lambdaClassConsumer;
     private final D8MethodProcessor methodProcessor;
 
     private final Map<DexReference, InvokeSpecialBridgeInfo> pendingInvokeSpecialBridges =
         new LinkedHashMap<>();
+    private final List<LambdaClass> synthesizedLambdaClasses = new ArrayList<>();
 
-    private D8CfInstructionDesugaringEventConsumer(
-        Consumer<LambdaClass> lambdaClassConsumer, D8MethodProcessor methodProcessor) {
-      this.lambdaClassConsumer = lambdaClassConsumer;
+    private D8CfInstructionDesugaringEventConsumer(D8MethodProcessor methodProcessor) {
       this.methodProcessor = methodProcessor;
     }
 
     @Override
+    public void acceptBackportedMethod(ProgramMethod backportedMethod, ProgramMethod context) {
+      methodProcessor.scheduleMethodForProcessing(backportedMethod, this);
+    }
+
+    @Override
     public void acceptInvokeSpecialBridgeInfo(InvokeSpecialBridgeInfo info) {
       synchronized (pendingInvokeSpecialBridges) {
         assert !pendingInvokeSpecialBridges.containsKey(info.getNewDirectMethod().getReference());
@@ -100,7 +122,9 @@
 
     @Override
     public void acceptLambdaClass(LambdaClass lambdaClass, ProgramMethod context) {
-      lambdaClassConsumer.accept(lambdaClass);
+      synchronized (synthesizedLambdaClasses) {
+        synthesizedLambdaClasses.add(lambdaClass);
+      }
     }
 
     @Override
@@ -118,14 +142,21 @@
       methodProcessor.scheduleDesugaredMethodForProcessing(bridge);
     }
 
-    public List<ProgramMethod> finalizeDesugaring(AppView<?> appView) {
-      List<ProgramMethod> needsReprocessing = new ArrayList<>();
-      finalizeInvokeSpecialDesugaring(appView, needsReprocessing::add);
-      return needsReprocessing;
+    @Override
+    public void acceptTwrCloseResourceMethod(ProgramMethod closeMethod, ProgramMethod context) {
+      methodProcessor.scheduleDesugaredMethodForProcessing(closeMethod);
+    }
+
+    public List<ProgramMethod> finalizeDesugaring(
+        AppView<?> appView, ClassConverterResult.Builder classConverterResultBuilder) {
+      List<ProgramMethod> needsProcessing = new ArrayList<>();
+      finalizeInvokeSpecialDesugaring(appView, needsProcessing::add);
+      finalizeLambdaDesugaring(classConverterResultBuilder, needsProcessing::add);
+      return needsProcessing;
     }
 
     private void finalizeInvokeSpecialDesugaring(
-        AppView<?> appView, Consumer<ProgramMethod> needsReprocessing) {
+        AppView<?> appView, Consumer<ProgramMethod> needsProcessing) {
       // Fixup the code of the new private methods have that been synthesized.
       pendingInvokeSpecialBridges
           .values()
@@ -146,14 +177,26 @@
                 info.getVirtualMethod()
                     .getDefinition()
                     .setCode(info.getVirtualMethodCode(), appView);
-                needsReprocessing.accept(info.getVirtualMethod());
+                needsProcessing.accept(info.getVirtualMethod());
               });
 
       pendingInvokeSpecialBridges.clear();
     }
 
+    private void finalizeLambdaDesugaring(
+        ClassConverterResult.Builder classConverterResultBuilder,
+        Consumer<ProgramMethod> needsProcessing) {
+      for (LambdaClass lambdaClass : synthesizedLambdaClasses) {
+        lambdaClass.target.ensureAccessibilityIfNeeded(
+            classConverterResultBuilder, needsProcessing);
+        lambdaClass.getLambdaProgramClass().forEachProgramMethod(needsProcessing);
+      }
+      synthesizedLambdaClasses.clear();
+    }
+
     public boolean verifyNothingToFinalize() {
       assert pendingInvokeSpecialBridges.isEmpty();
+      assert synthesizedLambdaClasses.isEmpty();
       return true;
     }
   }
@@ -163,13 +206,28 @@
 
     private final AppView<? extends AppInfoWithClassHierarchy> appView;
 
+    // TODO(b/180091213): Remove these two consumers when synthesizing contexts are accessible from
+    //  synthetic items.
+    private final BiConsumer<LambdaClass, ProgramMethod> lambdaClassConsumer;
+    private final BiConsumer<ProgramMethod, ProgramMethod> twrCloseResourceMethodConsumer;
+
     private final Map<LambdaClass, ProgramMethod> synthesizedLambdaClasses =
         new IdentityHashMap<>();
     private final List<InvokeSpecialBridgeInfo> pendingInvokeSpecialBridges = new ArrayList<>();
 
     public R8CfInstructionDesugaringEventConsumer(
-        AppView<? extends AppInfoWithClassHierarchy> appView) {
+        AppView<? extends AppInfoWithClassHierarchy> appView,
+        BiConsumer<LambdaClass, ProgramMethod> lambdaClassConsumer,
+        BiConsumer<ProgramMethod, ProgramMethod> twrCloseResourceMethodConsumer) {
       this.appView = appView;
+      this.lambdaClassConsumer = lambdaClassConsumer;
+      this.twrCloseResourceMethodConsumer = twrCloseResourceMethodConsumer;
+    }
+
+    @Override
+    public void acceptBackportedMethod(ProgramMethod backportedMethod, ProgramMethod context) {
+      // Intentionally empty. The backported method will be hit by the tracing in R8 as if it was
+      // present in the input code, and thus nothing needs to be done.
     }
 
     @Override
@@ -184,6 +242,9 @@
       synchronized (synthesizedLambdaClasses) {
         synthesizedLambdaClasses.put(lambdaClass, context);
       }
+      // TODO(b/180091213): Remove the recording of the synthesizing context when this is accessible
+      //  from synthetic items.
+      lambdaClassConsumer.accept(lambdaClass, context);
     }
 
     @Override
@@ -204,6 +265,15 @@
       // in the input code, and thus nothing needs to be done.
     }
 
+    @Override
+    public void acceptTwrCloseResourceMethod(ProgramMethod closeMethod, ProgramMethod context) {
+      // Intentionally empty. The close method will be hit by the tracing in R8 as if they were
+      // present in the input code, and thus nothing needs to be done.
+      // TODO(b/180091213): Remove the recording of the synthesizing context when this is accessible
+      //  from synthetic items.
+      twrCloseResourceMethodConsumer.accept(closeMethod, context);
+    }
+
     public void finalizeDesugaring() {
       finalizeInvokeSpecialDesugaring();
       finalizeLambdaDesugaring();
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaMainMethodSourceCode.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaMainMethodSourceCode.java
index 30ea01c..d1cd87a 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaMainMethodSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaMainMethodSourceCode.java
@@ -236,11 +236,10 @@
       instructions.add(new CfLoad(valueType, maxLocals));
       maxLocals += valueType.requiredRegisters();
       DexType expectedParamType = implReceiverAndArgs.get(i + capturedValues);
-      maxStack =
-          Math.max(
-              maxStack,
-              prepareParameterValue(
-                  erasedParams[i], enforcedParams[i], expectedParamType, instructions, factory));
+      maxStack +=
+          valueType.requiredRegisters()
+              + prepareParameterValue(
+                  erasedParams[i], enforcedParams[i], expectedParamType, instructions, factory);
     }
 
     instructions.add(
@@ -260,15 +259,13 @@
     } else {
       // Either the new instance or the called-method result is on top of stack.
       assert constructorTarget || !methodToCallReturnType.isVoidType();
-      maxStack =
-          Math.max(
-              maxStack,
-              prepareReturnValue(
-                  erasedReturnType,
-                  enforcedReturnType,
-                  constructorTarget ? methodToCall.holder : methodToCallReturnType,
-                  instructions,
-                  factory));
+      maxStack +=
+          prepareReturnValue(
+              erasedReturnType,
+              enforcedReturnType,
+              constructorTarget ? methodToCall.holder : methodToCallReturnType,
+              instructions,
+              factory);
       instructions.add(new CfReturn(ValueType.fromDexType(enforcedReturnType)));
     }
 
@@ -363,9 +360,12 @@
       Builder<CfInstruction> instructions,
       DexItemFactory factory) {
     internalAdjustType(fromType, toType, returnType, instructions, factory);
-    return Math.max(
-        ValueType.fromDexType(fromType).requiredRegisters(),
-        ValueType.fromDexType(toType).requiredRegisters());
+    int inSize = ValueType.fromDexType(fromType).requiredRegisters();
+    int outSize = ValueType.fromDexType(toType).requiredRegisters();
+    if (outSize > inSize) {
+      return outSize - inSize;
+    }
+    return 0;
   }
 
   private static void internalAdjustType(
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LocalStackAllocator.java b/src/main/java/com/android/tools/r8/ir/desugar/LocalStackAllocator.java
new file mode 100644
index 0000000..8c83d4a
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LocalStackAllocator.java
@@ -0,0 +1,10 @@
+// Copyright (c) 2021, 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.desugar;
+
+public interface LocalStackAllocator {
+
+  void allocateLocalStack(int localStackHeight);
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java b/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
index c34e32c..5815053 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
@@ -16,6 +16,8 @@
 import com.android.tools.r8.ir.desugar.lambda.LambdaInstructionDesugaring;
 import com.android.tools.r8.ir.desugar.nest.D8NestBasedAccessDesugaring;
 import com.android.tools.r8.ir.desugar.nest.NestBasedAccessDesugaring;
+import com.android.tools.r8.ir.desugar.stringconcat.StringConcatInstructionDesugaring;
+import com.android.tools.r8.ir.desugar.twr.TwrCloseResourceInstructionDesugaring;
 import com.android.tools.r8.utils.IntBox;
 import com.android.tools.r8.utils.IteratorUtils;
 import com.android.tools.r8.utils.ListUtils;
@@ -39,6 +41,16 @@
     this.nestBasedAccessDesugaring = NestBasedAccessDesugaring.create(appView);
     desugarings.add(new LambdaInstructionDesugaring(appView));
     desugarings.add(new InvokeSpecialToSelfDesugaring(appView));
+    desugarings.add(new StringConcatInstructionDesugaring(appView));
+    if (appView.options().enableBackportedMethodRewriting()) {
+      BackportedMethodRewriter backportedMethodRewriter = new BackportedMethodRewriter(appView);
+      if (backportedMethodRewriter.hasBackports()) {
+        desugarings.add(backportedMethodRewriter);
+      }
+    }
+    if (appView.options().enableTryWithResourcesDesugaring()) {
+      desugarings.add(new TwrCloseResourceInstructionDesugaring(appView));
+    }
     if (nestBasedAccessDesugaring != null) {
       desugarings.add(nestBasedAccessDesugaring);
     }
@@ -86,6 +98,9 @@
     IntBox maxLocalsForCode = new IntBox(cfCode.getMaxLocals());
     IntBox maxLocalsForInstruction = new IntBox(cfCode.getMaxLocals());
 
+    IntBox maxStackForCode = new IntBox(cfCode.getMaxStack());
+    IntBox maxStackForInstruction = new IntBox(cfCode.getMaxStack());
+
     List<CfInstruction> desugaredInstructions =
         ListUtils.flatMap(
             cfCode.getInstructions(),
@@ -94,6 +109,7 @@
                   desugarInstruction(
                       instruction,
                       maxLocalsForInstruction::getAndIncrement,
+                      maxStackForInstruction::getAndIncrement,
                       eventConsumer,
                       method,
                       methodProcessingContext);
@@ -110,8 +126,10 @@
             null);
     if (desugaredInstructions != null) {
       assert maxLocalsForCode.get() >= cfCode.getMaxLocals();
+      assert maxStackForCode.get() >= cfCode.getMaxStack();
       cfCode.setInstructions(desugaredInstructions);
       cfCode.setMaxLocals(maxLocalsForCode.get());
+      cfCode.setMaxStack(maxStackForCode.get());
     } else {
       assert false : "Expected code to be desugared";
     }
@@ -120,6 +138,7 @@
   private Collection<CfInstruction> desugarInstruction(
       CfInstruction instruction,
       FreshLocalProvider freshLocalProvider,
+      LocalStackAllocator localStackAllocator,
       CfInstructionDesugaringEventConsumer eventConsumer,
       ProgramMethod context,
       MethodProcessingContext methodProcessingContext) {
@@ -129,7 +148,12 @@
       CfInstructionDesugaring desugaring = iterator.next();
       Collection<CfInstruction> replacement =
           desugaring.desugarInstruction(
-              instruction, freshLocalProvider, eventConsumer, context, methodProcessingContext);
+              instruction,
+              freshLocalProvider,
+              localStackAllocator,
+              eventConsumer,
+              context,
+              methodProcessingContext);
       if (replacement != null) {
         assert verifyNoOtherDesugaringNeeded(
             instruction, context, methodProcessingContext, iterator);
@@ -177,6 +201,9 @@
                           assert false;
                           return 0;
                         },
+                        localStackHeight -> {
+                          assert false;
+                        },
                         CfInstructionDesugaringEventConsumer.createForDesugaredCode(),
                         context,
                         methodProcessingContext)
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/StringConcatRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/StringConcatRewriter.java
deleted file mode 100644
index 514ee97..0000000
--- a/src/main/java/com/android/tools/r8/ir/desugar/StringConcatRewriter.java
+++ /dev/null
@@ -1,454 +0,0 @@
-// Copyright (c) 2017, 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.desugar;
-
-import static com.android.tools.r8.ir.analysis.type.Nullability.definitelyNotNull;
-
-import com.android.tools.r8.dex.Constants;
-import com.android.tools.r8.errors.CompilationError;
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexCallSite;
-import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexProto;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.DexValue;
-import com.android.tools.r8.graph.DexValue.DexValueString;
-import com.android.tools.r8.ir.analysis.type.TypeElement;
-import com.android.tools.r8.ir.code.BasicBlock;
-import com.android.tools.r8.ir.code.ConstString;
-import com.android.tools.r8.ir.code.IRCode;
-import com.android.tools.r8.ir.code.Instruction;
-import com.android.tools.r8.ir.code.InstructionListIterator;
-import com.android.tools.r8.ir.code.InvokeCustom;
-import com.android.tools.r8.ir.code.InvokeDirect;
-import com.android.tools.r8.ir.code.InvokeVirtual;
-import com.android.tools.r8.ir.code.NewInstance;
-import com.android.tools.r8.ir.code.Value;
-import com.google.common.collect.Lists;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.IdentityHashMap;
-import java.util.List;
-import java.util.ListIterator;
-import java.util.Map;
-
-/** String concatenation desugaring rewriter. */
-public class StringConcatRewriter {
-  private static final String CONCAT_FACTORY_TYPE_DESCR = "Ljava/lang/invoke/StringConcatFactory;";
-  private static final String CALLSITE_TYPE_DESCR = "Ljava/lang/invoke/CallSite;";
-  private static final String LOOKUP_TYPE_DESCR = "Ljava/lang/invoke/MethodHandles$Lookup;";
-  private static final String METHOD_TYPE_TYPE_DESCR = "Ljava/lang/invoke/MethodType;";
-
-  private static final String MAKE_CONCAT = "makeConcat";
-  private static final String MAKE_CONCAT_WITH_CONSTANTS = "makeConcatWithConstants";
-  private static final String TO_STRING = "toString";
-  private static final String APPEND = "append";
-
-  private final AppView<?> appView;
-  private final DexItemFactory factory;
-
-  private final DexMethod makeConcat;
-  private final DexMethod makeConcatWithConstants;
-
-  private final DexMethod stringBuilderInit;
-  private final DexMethod stringBuilderToString;
-
-  private final Map<DexType, DexMethod> paramTypeToAppendMethod = new IdentityHashMap<>();
-  private final DexMethod defaultAppendMethod;
-
-  public StringConcatRewriter(AppView<?> appView) {
-    this.appView = appView;
-    this.factory = appView.dexItemFactory();
-
-    DexType factoryType = factory.createType(CONCAT_FACTORY_TYPE_DESCR);
-    DexType callSiteType = factory.createType(CALLSITE_TYPE_DESCR);
-    DexType lookupType = factory.createType(LOOKUP_TYPE_DESCR);
-    DexType methodTypeType = factory.createType(METHOD_TYPE_TYPE_DESCR);
-
-    makeConcat = factory.createMethod(factoryType,
-        factory.createProto(callSiteType, lookupType, factory.stringType, methodTypeType),
-        factory.createString(MAKE_CONCAT));
-
-    makeConcatWithConstants = factory.createMethod(factoryType,
-        factory.createProto(callSiteType, lookupType, factory.stringType, methodTypeType,
-            factory.stringType, factory.objectArrayType),
-        factory.createString(MAKE_CONCAT_WITH_CONSTANTS));
-
-    stringBuilderInit = factory.createMethod(
-        factory.stringBuilderType, factory.createProto(factory.voidType),
-        factory.createString(Constants.INSTANCE_INITIALIZER_NAME));
-
-    stringBuilderToString = factory.createMethod(
-        factory.stringBuilderType, factory.createProto(factory.stringType),
-        factory.createString(TO_STRING));
-
-    // Mapping of type parameters to methods of StringBuilder.
-    DexType stringBuilderType = factory.stringBuilderType;
-    paramTypeToAppendMethod.put(factory.booleanType, factory.createMethod(
-        stringBuilderType, factory.createProto(stringBuilderType, factory.booleanType), APPEND));
-    paramTypeToAppendMethod.put(factory.charType, factory.createMethod(
-        stringBuilderType, factory.createProto(stringBuilderType, factory.charType), APPEND));
-    paramTypeToAppendMethod.put(factory.byteType, factory.createMethod(
-        stringBuilderType, factory.createProto(stringBuilderType, factory.intType), APPEND));
-    paramTypeToAppendMethod.put(factory.shortType, factory.createMethod(
-        stringBuilderType, factory.createProto(stringBuilderType, factory.intType), APPEND));
-    paramTypeToAppendMethod.put(factory.intType, factory.createMethod(
-        stringBuilderType, factory.createProto(stringBuilderType, factory.intType), APPEND));
-    paramTypeToAppendMethod.put(factory.longType, factory.createMethod(
-        stringBuilderType, factory.createProto(stringBuilderType, factory.longType), APPEND));
-    paramTypeToAppendMethod.put(factory.floatType, factory.createMethod(
-        stringBuilderType, factory.createProto(stringBuilderType, factory.floatType), APPEND));
-    paramTypeToAppendMethod.put(factory.doubleType, factory.createMethod(
-        stringBuilderType, factory.createProto(stringBuilderType, factory.doubleType), APPEND));
-    paramTypeToAppendMethod.put(factory.stringType, factory.createMethod(
-        stringBuilderType, factory.createProto(stringBuilderType, factory.stringType), APPEND));
-    defaultAppendMethod = factory.createMethod(
-        stringBuilderType, factory.createProto(stringBuilderType, factory.objectType), APPEND);
-  }
-
-  /**
-   * Find and desugar all string concatenations implemented via `invokedynamic` call
-   * to either of StringConcatFactory bootstrap methods.
-   */
-  public void desugarStringConcats(DexMethod method, IRCode code) {
-    ListIterator<BasicBlock> blocks = code.listIterator();
-    while (blocks.hasNext()) {
-      BasicBlock block = blocks.next();
-      InstructionListIterator instructions = block.listIterator(code);
-      while (instructions.hasNext()) {
-        Instruction instruction = instructions.next();
-        if (!instruction.isInvokeCustom()) {
-          continue;
-        }
-
-        InvokeCustom invokeCustom = instruction.asInvokeCustom();
-        DexCallSite callSite = invokeCustom.getCallSite();
-
-        // We are interested in bootstrap methods StringConcatFactory::makeConcat
-        // and StringConcatFactory::makeConcatWithConstants, both are static.
-        if (!callSite.bootstrapMethod.type.isInvokeStatic()) {
-          continue;
-        }
-
-        DexMethod bootstrapMethod = callSite.bootstrapMethod.asMethod();
-        // We rely on both rewrite methods called below performing their work in
-        // a way which keeps both `instructions` and `blocks` iterators in
-        // valid state so that we can continue iteration.
-        if (bootstrapMethod == this.makeConcat) {
-          rewriteMakeConcat(method, code, blocks, instructions, invokeCustom);
-        } else if (bootstrapMethod == this.makeConcatWithConstants) {
-          rewriteMakeConcatWithConstants(method, code, blocks, instructions, invokeCustom);
-        }
-      }
-    }
-  }
-
-  /**
-   * Rewrite concatenation with StringConcatFactory::makeConcat​(...). There is no
-   * format string (`recipe`), all arguments are just concatenated in order.
-   */
-  private void rewriteMakeConcat(DexMethod method, IRCode code, ListIterator<BasicBlock> blocks,
-      InstructionListIterator instructions, InvokeCustom invokeCustom) {
-    DexProto proto = invokeCustom.getCallSite().methodProto;
-    DexType[] parameters = proto.parameters.values;
-    int paramCount = parameters.length;
-    List<Value> arguments = invokeCustom.inValues();
-
-    // Signature of the callsite proto defines the effective types of the arguments.
-    if (paramCount != arguments.size()) {
-      throw error(method, "inconsistent arguments: expected " +
-          paramCount + ", actual " + arguments.size());
-    }
-
-    // Collect chunks.
-    ConcatBuilder builder = new ConcatBuilder(appView, code, blocks, instructions);
-    for (int i = 0; i < paramCount; i++) {
-      builder.addChunk(arguments.get(i),
-          paramTypeToAppendMethod.getOrDefault(parameters[i], defaultAppendMethod));
-    }
-
-    // Desugar the instruction.
-    builder.desugar();
-  }
-
-  /**
-   * Rewrite concatenation with StringConcatFactory::makeConcat​WithConstants(...).
-   * There is a format string (`recipe`) specifying where exactly the arguments are
-   * to be inserted into a template string `recipe`.
-   *
-   * NOTE: `makeConcat​WithConstants` also supports passing compilation time `constants`
-   * as bootstrap method arguments, but current version seems to only support String
-   * constants. This method does not support desugaring of `makeConcatWithConstants`
-   * with non-string constants provided as bootstrap method arguments.
-   */
-  private void rewriteMakeConcatWithConstants(
-      DexMethod method, IRCode code, ListIterator<BasicBlock> blocks,
-      InstructionListIterator instructions, InvokeCustom invokeCustom) {
-    DexCallSite callSite = invokeCustom.getCallSite();
-    DexProto proto = callSite.methodProto;
-    DexType[] parameters = proto.parameters.values;
-    int paramCount = parameters.length;
-    List<Value> callArgs = invokeCustom.inValues();
-    List<DexValue> bootstrapArgs = callSite.bootstrapArgs;
-
-    // Signature of the callsite proto defines the effective types of the arguments.
-    if (paramCount != callArgs.size()) {
-      throw error(method, "inconsistent arguments: expected " +
-          paramCount + ", actual " + callArgs.size());
-    }
-
-    // Get `recipe` string.
-    if (bootstrapArgs.size() == 0) {
-      throw error(method, "bootstrap method misses `recipe` argument");
-    }
-
-    // Constant arguments to `recipe`.
-    List<DexValue> constArgs = new ArrayList<>();
-    for (int i = 1; i < bootstrapArgs.size(); i++) {
-      constArgs.add(bootstrapArgs.get(i));
-    }
-
-    // Extract recipe.
-    DexValueString recipeValue = bootstrapArgs.get(0).asDexValueString();
-    if (recipeValue == null) {
-      throw error(method, "bootstrap method argument `recipe` must be a string");
-    }
-    String recipe = recipeValue.getValue().toString();
-
-    // Collect chunks and patch the instruction.
-    ConcatBuilder builder = new ConcatBuilder(appView, code, blocks, instructions);
-    StringBuilder acc = new StringBuilder();
-    int argIndex = 0;
-    int constArgIndex = 0;
-    int length = recipe.length();
-    for (int i = 0; i < length; i++) {
-      char c = recipe.charAt(i);
-      if (c == '\u0001') {
-        // Reference to an argument.
-        if (acc.length() > 0) {
-          builder.addChunk(acc.toString(), paramTypeToAppendMethod.get(factory.stringType));
-          acc.setLength(0);
-        }
-        if (argIndex >= paramCount) {
-          throw error(method, "too many argument references in `recipe`");
-        }
-        builder.addChunk(callArgs.get(argIndex),
-            paramTypeToAppendMethod.getOrDefault(parameters[argIndex], defaultAppendMethod));
-        argIndex++;
-
-      } else if (c == '\u0002') {
-        if (constArgIndex >= constArgs.size()) {
-          throw error(method, "too many constant references in `recipe`");
-        }
-
-        // Reference to a constant. Since it's a constant we just convert it to
-        // string and append to `acc`, this way we will avoid calling toString()
-        // on every call.
-        acc.append(convertToString(method, constArgs.get(constArgIndex++)));
-
-      } else {
-        acc.append(c);
-      }
-    }
-
-    if (argIndex != paramCount) {
-      throw error(method, "too few argument references in `recipe`, "
-          + "expected " + paramCount + ", referenced: " + argIndex);
-    }
-    if (constArgIndex != constArgs.size()) {
-      throw error(method, "too few constant references in `recipe`, "
-          + "expected " + constArgs.size() + ", referenced: " + constArgIndex);
-    }
-
-    // Final part.
-    if (acc.length() > 0) {
-      builder.addChunk(acc.toString(), paramTypeToAppendMethod.get(factory.stringType));
-    }
-
-    // Desugar the instruction.
-    builder.desugar();
-  }
-
-  private static String convertToString(DexMethod method, DexValue value) {
-    if (value.isDexValueString()) {
-      return value.asDexValueString().getValue().toString();
-    }
-    throw error(method,
-        "const arg referenced from `recipe` is not supported: " + value.getClass().getName());
-  }
-
-  private final class ConcatBuilder {
-    private final AppView<?> appView;
-    private final IRCode code;
-    private final ListIterator<BasicBlock> blocks;
-    private final InstructionListIterator instructions;
-    private final Instruction invokeCustom;
-    private final BasicBlock currentBlock;
-    private final List<Chunk> chunks = new ArrayList<>();
-
-    private ConcatBuilder(
-        AppView<?> appView,
-        IRCode code,
-        ListIterator<BasicBlock> blocks,
-        InstructionListIterator instructions) {
-      this.appView = appView;
-      this.code = code;
-      this.blocks = blocks;
-      this.instructions = instructions;
-
-      invokeCustom = instructions.peekPrevious();
-      assert invokeCustom.isInvokeCustom();
-      currentBlock = invokeCustom.getBlock();
-    }
-
-    private void appendInstruction(Instruction instruction) {
-      instruction.setPosition(invokeCustom.getPosition());
-      instructions.add(instruction);
-    }
-
-    final void addChunk(Value value, DexMethod method) {
-      chunks.add(new ArgumentChunk(value, method));
-    }
-
-    final void addChunk(String str, DexMethod method) {
-      chunks.add(new ConstantChunk(str, method));
-    }
-
-    /**
-     * Patch current `invoke-custom` instruction with:
-     * <pre>
-     *   prologue:
-     *      |   new-instance v0, StringBuilder
-     *      |   invoke-direct {v0}, void StringBuilder.<init>()
-     *
-     *   populate each chunk:
-     *      |   (optional) load the constant, e.g.: const-string v1, ""
-     *      |   invoke-virtual {v0, v1}, StringBuilder StringBuilder.append([type])
-     *
-     *   epilogue:
-     *      |   invoke-virtual {v0}, String StringBuilder.toString()
-     *
-     * </pre>
-     */
-    final void desugar() {
-      // Move the iterator before the invoke-custom we are about to patch.
-      instructions.previous();
-
-      // new-instance v0, StringBuilder
-      TypeElement stringBuilderTypeLattice =
-          TypeElement.fromDexType(factory.stringBuilderType, definitelyNotNull(), appView);
-      Value sbInstance = code.createValue(stringBuilderTypeLattice);
-      appendInstruction(new NewInstance(factory.stringBuilderType, sbInstance));
-
-      // invoke-direct {v0}, void StringBuilder.<init>()
-      appendInstruction(new InvokeDirect(stringBuilderInit,
-          null /* no return value */, Collections.singletonList(sbInstance)));
-
-      // Add calls to append(...) methods
-      for (Chunk chunk : chunks) {
-        chunk.addAppendCall(sbInstance);
-      }
-
-      // invoke-virtual {v0}, String StringBuilder.toString()
-      Instruction nextInstruction = instructions.next();
-      assert invokeCustom == nextInstruction;
-
-      // The value representing the string: we reuse the value from the
-      // original invoke-custom instruction, and thus all its usages.
-      Value concatValue = invokeCustom.outValue();
-      if (concatValue == null) {
-        // The out value might be empty in case it was optimized out.
-        concatValue = code.createValue(TypeElement.stringClassType(appView, definitelyNotNull()));
-      }
-
-      // Replace the instruction.
-      instructions.replaceCurrentInstruction(new InvokeVirtual(
-          stringBuilderToString, concatValue, Collections.singletonList(sbInstance)));
-
-      if (!currentBlock.hasCatchHandlers()) {
-        return;
-      }
-
-      // Since the block has handlers we should split the block at exception throwing
-      // instructions. Splitting blocks while adding instructions seems more complicated.
-      //
-      // NOTE: we collect new blocks first and copy catch handlers from the original
-      // one after all blocks are split. Copying handlers just after splitting involves
-      // extra complexity since split() method expects that the block being split is
-      // located right before the iterator point and new blocks created while copying
-      // handles break this expectation.
-      List<BasicBlock> newBlocks = new ArrayList<>();
-      InstructionListIterator it = currentBlock.listIterator(code);
-      while (it.hasNext()) {
-        Instruction instruction = it.next();
-        if (instruction.instructionTypeCanThrow() && it.hasNext()) {
-          // We split block in case we see throwing instruction which
-          // is not the last instruction of the block.
-          BasicBlock newBlock = it.split(code, blocks);
-          newBlocks.add(newBlock);
-          // Follow with the next block.
-          it = newBlock.listIterator(code);
-        }
-      }
-      // Copy catch handlers after all blocks are split.
-      for (BasicBlock newBlock : newBlocks) {
-        newBlock.copyCatchHandlers(code, blocks, currentBlock, appView.options());
-      }
-    }
-
-    private abstract class Chunk {
-      final DexMethod method;
-
-      Chunk(DexMethod method) {
-        this.method = method;
-      }
-
-      abstract Value getOrCreateValue();
-
-      final void addAppendCall(Value sbInstance) {
-        appendInstruction(new InvokeVirtual(
-            method, null /* don't care about return value */,
-            Lists.newArrayList(sbInstance, getOrCreateValue())));
-      }
-    }
-
-    private final class ArgumentChunk extends Chunk {
-      final Value value;
-
-      ArgumentChunk(Value value, DexMethod method) {
-        super(method);
-        this.value = value;
-      }
-
-      @Override
-      Value getOrCreateValue() {
-        return value;
-      }
-    }
-
-    private final class ConstantChunk extends Chunk {
-      final String str;
-
-      ConstantChunk(String str, DexMethod method) {
-        super(method);
-        this.str = str;
-      }
-
-      @Override
-      Value getOrCreateValue() {
-        Value value = code.createValue(TypeElement.stringClassType(appView, definitelyNotNull()));
-        appendInstruction(new ConstString(value, factory.createString(str)));
-        return value;
-      }
-    }
-  }
-
-  private static CompilationError error(DexMethod method, String message) {
-    return new CompilationError(
-        "String concatenation desugaring error (method: " +
-            method.qualifiedName() + "): " + message);
-  }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/TwrCloseResourceRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/TwrCloseResourceRewriter.java
deleted file mode 100644
index 69b4dc2..0000000
--- a/src/main/java/com/android/tools/r8/ir/desugar/TwrCloseResourceRewriter.java
+++ /dev/null
@@ -1,146 +0,0 @@
-// 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 com.android.tools.r8.ir.desugar;
-
-import com.android.tools.r8.cf.code.CfInstruction;
-import com.android.tools.r8.cf.code.CfInvoke;
-import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
-import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexProto;
-import com.android.tools.r8.graph.MethodAccessFlags;
-import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.ir.code.IRCode;
-import com.android.tools.r8.ir.code.InstructionListIterator;
-import com.android.tools.r8.ir.code.InvokeStatic;
-import com.android.tools.r8.ir.conversion.IRConverter;
-import com.android.tools.r8.ir.desugar.backports.BackportedMethods;
-import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
-import com.android.tools.r8.utils.InternalOptions;
-import com.android.tools.r8.utils.InternalOptions.DesugarState;
-import com.google.common.base.Suppliers;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.function.Consumer;
-import java.util.function.Supplier;
-import org.objectweb.asm.Opcodes;
-
-// Try with resources close-resource desugaring.
-//
-// Rewrites $closeResource methods synthesized by java compilers to work on older DEX runtimes.
-// All invocations to $closeResource methods are rewritten to target a compiler generated version
-// that is correct on older DEX runtimes where not all types implement AutoClosable as expected.
-//
-// Note that we don't remove $closeResource(...) synthesized by java compiler, relying on
-// tree shaking to remove them since now they should not be referenced.
-// TODO(b/177401708): D8 does not tree shake so we should remove the now unused method.
-public final class TwrCloseResourceRewriter {
-
-  private final AppView<?> appView;
-  private final DexProto twrCloseResourceProto;
-  private final List<ProgramMethod> synthesizedMethods = new ArrayList<>();
-
-  public static boolean enableTwrCloseResourceDesugaring(InternalOptions options) {
-    return options.desugarState == DesugarState.ON
-        && options.enableTryWithResourcesDesugaring()
-        && !options.canUseTwrCloseResourceMethod();
-  }
-
-  public TwrCloseResourceRewriter(AppView<?> appView) {
-    this.appView = appView;
-    DexItemFactory dexItemFactory = appView.dexItemFactory();
-    twrCloseResourceProto =
-        dexItemFactory.createProto(
-            dexItemFactory.voidType, dexItemFactory.throwableType, dexItemFactory.objectType);
-  }
-
-  public int rewriteCf(
-      ProgramMethod method,
-      Consumer<ProgramMethod> newMethodCallback,
-      MethodProcessingContext methodProcessingContext) {
-    CfCode code = method.getDefinition().getCode().asCfCode();
-    List<CfInstruction> instructions = code.getInstructions();
-    Supplier<List<CfInstruction>> lazyNewInstructions =
-        Suppliers.memoize(() -> new ArrayList<>(instructions));
-    int replaced = 0;
-    int newInstructionDelta = 0;
-    for (int i = 0; i < instructions.size(); i++) {
-      CfInvoke invoke = instructions.get(i).asInvoke();
-      if (invoke == null
-          || invoke.getOpcode() != Opcodes.INVOKESTATIC
-          || !isTwrCloseResourceMethod(invoke.getMethod(), appView.dexItemFactory())) {
-        continue;
-      }
-      // Synthesize a new method.
-      ProgramMethod closeMethod = createSyntheticCloseResourceMethod(methodProcessingContext);
-      newMethodCallback.accept(closeMethod);
-      // Rewrite the invoke to the new synthetic.
-      int newInstructionIndex = i + newInstructionDelta;
-      lazyNewInstructions
-          .get()
-          .set(
-              newInstructionIndex,
-              new CfInvoke(Opcodes.INVOKESTATIC, closeMethod.getReference(), false));
-      ++replaced;
-    }
-    if (replaced > 0) {
-      code.setInstructions(lazyNewInstructions.get());
-    }
-    return replaced;
-  }
-
-  // Rewrites calls to $closeResource() method. Can be invoked concurrently.
-  public void rewriteIR(IRCode code, MethodProcessingContext methodProcessingContext) {
-    InstructionListIterator iterator = code.instructionListIterator();
-    while (iterator.hasNext()) {
-      InvokeStatic invoke = iterator.next().asInvokeStatic();
-      if (invoke == null
-          || !isTwrCloseResourceMethod(invoke.getInvokedMethod(), appView.dexItemFactory())) {
-        continue;
-      }
-
-      // Replace with a call to a synthetic utility.
-      assert invoke.outValue() == null;
-      assert invoke.inValues().size() == 2;
-      ProgramMethod closeResourceMethod =
-          createSyntheticCloseResourceMethod(methodProcessingContext);
-      InvokeStatic newInvoke =
-          new InvokeStatic(closeResourceMethod.getReference(), null, invoke.inValues());
-      iterator.replaceCurrentInstruction(newInvoke);
-      synchronized (synthesizedMethods) {
-        synthesizedMethods.add(closeResourceMethod);
-      }
-    }
-  }
-
-  public static boolean isTwrCloseResourceMethod(DexMethod method, DexItemFactory factory) {
-    return method.name == factory.twrCloseResourceMethodName
-        && method.proto == factory.twrCloseResourceMethodProto;
-  }
-
-  private ProgramMethod createSyntheticCloseResourceMethod(
-      MethodProcessingContext methodProcessingContext) {
-    return appView
-        .getSyntheticItems()
-        .createMethod(
-            SyntheticKind.TWR_CLOSE_RESOURCE,
-            methodProcessingContext.createUniqueContext(),
-            appView.dexItemFactory(),
-            methodBuilder ->
-                methodBuilder
-                    .setAccessFlags(MethodAccessFlags.createPublicStaticSynthetic())
-                    .setProto(twrCloseResourceProto)
-                    .setCode(
-                        m ->
-                            BackportedMethods.CloseResourceMethod_closeResourceImpl(
-                                appView.options(), m)));
-  }
-
-  public void processSynthesizedMethods(IRConverter converter) {
-    synthesizedMethods.forEach(converter::optimizeSynthesizedMethod);
-  }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethodDesugaringEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethodDesugaringEventConsumer.java
new file mode 100644
index 0000000..c62501f
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethodDesugaringEventConsumer.java
@@ -0,0 +1,12 @@
+// Copyright (c) 2021, 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.desugar.backports;
+
+import com.android.tools.r8.graph.ProgramMethod;
+
+public interface BackportedMethodDesugaringEventConsumer {
+
+  void acceptBackportedMethod(ProgramMethod backportedMethod, ProgramMethod context);
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/backports/NumericMethodRewrites.java b/src/main/java/com/android/tools/r8/ir/desugar/backports/NumericMethodRewrites.java
index 050aefa..51949c9 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/backports/NumericMethodRewrites.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/backports/NumericMethodRewrites.java
@@ -8,7 +8,8 @@
 import com.android.tools.r8.ir.code.NumericType;
 import com.android.tools.r8.ir.desugar.BackportedMethodRewriter.FullMethodInvokeRewriter;
 import com.android.tools.r8.ir.desugar.BackportedMethodRewriter.MethodInvokeRewriter;
-import java.util.ListIterator;
+import java.util.Collection;
+import java.util.Collections;
 import org.objectweb.asm.Opcodes;
 
 public final class NumericMethodRewrites {
@@ -33,10 +34,9 @@
   public static MethodInvokeRewriter rewriteAsIdentity() {
     return new FullMethodInvokeRewriter() {
       @Override
-      public void rewrite(
-          CfInvoke invoke, ListIterator<CfInstruction> iterator, DexItemFactory factory) {
+      public Collection<CfInstruction> rewrite(CfInvoke invoke, DexItemFactory factory) {
         // The invoke consumes the stack value and pushes another assumed to be the same.
-        iterator.remove();
+        return Collections.emptyList();
       }
     };
   }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/backports/ObjectsMethodRewrites.java b/src/main/java/com/android/tools/r8/ir/desugar/backports/ObjectsMethodRewrites.java
index 69253be..f8ab4a7 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/backports/ObjectsMethodRewrites.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/backports/ObjectsMethodRewrites.java
@@ -12,7 +12,8 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.desugar.BackportedMethodRewriter.FullMethodInvokeRewriter;
 import com.android.tools.r8.ir.desugar.BackportedMethodRewriter.MethodInvokeRewriter;
-import java.util.ListIterator;
+import com.google.common.collect.ImmutableList;
+import java.util.Collection;
 import org.objectweb.asm.Opcodes;
 
 public final class ObjectsMethodRewrites {
@@ -31,13 +32,12 @@
     return new FullMethodInvokeRewriter() {
 
       @Override
-      public void rewrite(
-          CfInvoke invoke, ListIterator<CfInstruction> iterator, DexItemFactory factory) {
-        iterator.remove();
+      public Collection<CfInstruction> rewrite(CfInvoke invoke, DexItemFactory factory) {
         // requireNonNull returns the operand, so dup top-of-stack, do getClass and pop the class.
-        iterator.add(new CfStackInstruction(Opcode.Dup));
-        iterator.add(new CfInvoke(Opcodes.INVOKEVIRTUAL, factory.objectMembers.getClass, false));
-        iterator.add(new CfStackInstruction(Opcode.Pop));
+        return ImmutableList.of(
+            new CfStackInstruction(Opcode.Dup),
+            new CfInvoke(Opcodes.INVOKEVIRTUAL, factory.objectMembers.getClass, false),
+            new CfStackInstruction(Opcode.Pop));
       }
     };
   }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/invokespecial/InvokeSpecialToSelfDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/invokespecial/InvokeSpecialToSelfDesugaring.java
index a4f4b9b..0b9c80e 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/invokespecial/InvokeSpecialToSelfDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/invokespecial/InvokeSpecialToSelfDesugaring.java
@@ -17,6 +17,7 @@
 import com.android.tools.r8.ir.desugar.CfInstructionDesugaring;
 import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
 import com.android.tools.r8.ir.desugar.FreshLocalProvider;
+import com.android.tools.r8.ir.desugar.LocalStackAllocator;
 import com.android.tools.r8.ir.synthetic.ForwardMethodBuilder;
 import com.google.common.collect.ImmutableList;
 import java.util.Collection;
@@ -68,6 +69,7 @@
   public Collection<CfInstruction> desugarInstruction(
       CfInstruction instruction,
       FreshLocalProvider freshLocalProvider,
+      LocalStackAllocator localStackAllocator,
       CfInstructionDesugaringEventConsumer eventConsumer,
       ProgramMethod context,
       MethodProcessingContext methodProcessingContext) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/lambda/D8LambdaDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/lambda/D8LambdaDesugaring.java
index 2d89fce..24c179e 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/lambda/D8LambdaDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/lambda/D8LambdaDesugaring.java
@@ -8,37 +8,11 @@
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.EnclosingMethodAttribute;
-import com.android.tools.r8.ir.conversion.ClassConverterResult;
-import com.android.tools.r8.ir.conversion.D8MethodProcessor;
-import com.android.tools.r8.utils.collections.ProgramMethodSet;
-import java.util.IdentityHashMap;
 import java.util.Map;
-import java.util.concurrent.ExecutionException;
 
 public class D8LambdaDesugaring {
 
-  public static void synthesizeAccessibilityBridgesForLambdaClasses(
-      AppView<?> appView,
-      ClassConverterResult classConverterResult,
-      D8MethodProcessor methodProcessor)
-      throws ExecutionException {
-    Map<DexMethod, DexMethod> forcefullyMovedLambdaMethods = new IdentityHashMap<>();
-    ProgramMethodSet seenAccessibilityBridges = ProgramMethodSet.createConcurrent();
-    classConverterResult.forEachSynthesizedLambdaClassWithDeterministicOrdering(
-        lambdaClass -> {
-          // Collect the accessibility bridges that require processing. Note that we cannot schedule
-          // the methods for processing directly here, since that would lead to concurrent IR
-          // processing meanwhile we update the program (insert bridges on existing classes).
-          lambdaClass.target.ensureAccessibilityIfNeeded(
-              forcefullyMovedLambdaMethods::put, seenAccessibilityBridges::add);
-        });
-    methodProcessor
-        .scheduleDesugaredMethodsForProcessing(seenAccessibilityBridges)
-        .awaitMethodProcessing();
-    rewriteEnclosingMethodAttributes(appView, forcefullyMovedLambdaMethods);
-  }
-
-  private static void rewriteEnclosingMethodAttributes(
+  public static void rewriteEnclosingLambdaMethodAttributes(
       AppView<?> appView, Map<DexMethod, DexMethod> forcefullyMovedLambdaMethods) {
     if (forcefullyMovedLambdaMethods.isEmpty()) {
       return;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/lambda/LambdaInstructionDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/lambda/LambdaInstructionDesugaring.java
index 54477eb..34dda4e 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/lambda/LambdaInstructionDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/lambda/LambdaInstructionDesugaring.java
@@ -24,6 +24,7 @@
 import com.android.tools.r8.ir.desugar.FreshLocalProvider;
 import com.android.tools.r8.ir.desugar.LambdaClass;
 import com.android.tools.r8.ir.desugar.LambdaDescriptor;
+import com.android.tools.r8.ir.desugar.LocalStackAllocator;
 import com.android.tools.r8.synthesis.SyntheticNaming;
 import com.android.tools.r8.utils.Box;
 import com.google.common.collect.ImmutableList;
@@ -44,6 +45,7 @@
   public Collection<CfInstruction> desugarInstruction(
       CfInstruction instruction,
       FreshLocalProvider freshLocalProvider,
+      LocalStackAllocator localStackAllocator,
       CfInstructionDesugaringEventConsumer eventConsumer,
       ProgramMethod context,
       MethodProcessingContext methodProcessingContext) {
@@ -51,6 +53,7 @@
       return desugarInvokeDynamicInstruction(
           instruction.asInvokeDynamic(),
           freshLocalProvider,
+          localStackAllocator,
           eventConsumer,
           context,
           methodProcessingContext);
@@ -61,6 +64,7 @@
   private Collection<CfInstruction> desugarInvokeDynamicInstruction(
       CfInvokeDynamic invoke,
       FreshLocalProvider freshLocalProvider,
+      LocalStackAllocator localStackAllocator,
       LambdaDesugaringEventConsumer eventConsumer,
       ProgramMethod context,
       MethodProcessingContext methodProcessingContext) {
@@ -89,6 +93,13 @@
           replacement.addLast(new CfLoad(valueType, freshLocal));
         });
     replacement.add(new CfInvoke(Opcodes.INVOKESPECIAL, lambdaClass.constructor, false));
+
+    // Coming into the original invoke-dynamic instruction, we have N arguments on the stack. We pop
+    // the N arguments from the stack, and then add a new-instance and dup it. With those two new
+    // elements on the stack, we load all the N arguments back onto the stack. At this point, we
+    // have the original N arguments on the stack plus the 2 new stack elements.
+    localStackAllocator.allocateLocalStack(2);
+
     return replacement;
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/nest/NestBasedAccessDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/nest/NestBasedAccessDesugaring.java
index af0a140..cec4cb1 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/nest/NestBasedAccessDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/nest/NestBasedAccessDesugaring.java
@@ -32,6 +32,7 @@
 import com.android.tools.r8.ir.desugar.CfInstructionDesugaring;
 import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
 import com.android.tools.r8.ir.desugar.FreshLocalProvider;
+import com.android.tools.r8.ir.desugar.LocalStackAllocator;
 import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.google.common.collect.ImmutableList;
@@ -146,6 +147,7 @@
   public Collection<CfInstruction> desugarInstruction(
       CfInstruction instruction,
       FreshLocalProvider freshLocalProvider,
+      LocalStackAllocator localStackAllocator,
       CfInstructionDesugaringEventConsumer eventConsumer,
       ProgramMethod context,
       MethodProcessingContext methodProcessingContext) {
@@ -153,7 +155,8 @@
       return desugarFieldInstruction(instruction.asFieldInstruction(), context, eventConsumer);
     }
     if (instruction.isInvoke()) {
-      return desugarInvokeInstruction(instruction.asInvoke(), context, eventConsumer);
+      return desugarInvokeInstruction(
+          instruction.asInvoke(), localStackAllocator, context, eventConsumer);
     }
     return null;
   }
@@ -178,6 +181,7 @@
 
   private List<CfInstruction> desugarInvokeInstruction(
       CfInvoke invoke,
+      LocalStackAllocator localStackAllocator,
       ProgramMethod context,
       NestBasedAccessDesugaringEventConsumer eventConsumer) {
     DexMethod invokedMethod = invoke.getMethod();
@@ -197,6 +201,8 @@
     DexMethod bridge = ensureMethodBridge(target, eventConsumer);
     if (target.getDefinition().isInstanceInitializer()) {
       assert !invoke.isInterface();
+      // Ensure room on the stack for the extra null argument.
+      localStackAllocator.allocateLocalStack(1);
       return ImmutableList.of(
           new CfConstNull(), new CfInvoke(Opcodes.INVOKESPECIAL, bridge, false));
     }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/stringconcat/StringConcatInstructionDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/stringconcat/StringConcatInstructionDesugaring.java
new file mode 100644
index 0000000..cae3e54
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/stringconcat/StringConcatInstructionDesugaring.java
@@ -0,0 +1,419 @@
+// Copyright (c) 2021, 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.desugar.stringconcat;
+
+import com.android.tools.r8.cf.code.CfConstString;
+import com.android.tools.r8.cf.code.CfInstruction;
+import com.android.tools.r8.cf.code.CfInvoke;
+import com.android.tools.r8.cf.code.CfInvokeDynamic;
+import com.android.tools.r8.cf.code.CfLoad;
+import com.android.tools.r8.cf.code.CfNew;
+import com.android.tools.r8.cf.code.CfStackInstruction;
+import com.android.tools.r8.cf.code.CfStackInstruction.Opcode;
+import com.android.tools.r8.cf.code.CfStore;
+import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
+import com.android.tools.r8.errors.CompilationError;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexCallSite;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexItemFactory.StringBuildingMethods;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexProto;
+import com.android.tools.r8.graph.DexString;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.DexTypeList;
+import com.android.tools.r8.graph.DexValue;
+import com.android.tools.r8.graph.DexValue.DexValueString;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.code.ValueType;
+import com.android.tools.r8.ir.desugar.CfInstructionDesugaring;
+import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
+import com.android.tools.r8.ir.desugar.FreshLocalProvider;
+import com.android.tools.r8.ir.desugar.LocalStackAllocator;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.IteratorUtils;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Deque;
+import java.util.IdentityHashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import org.objectweb.asm.Opcodes;
+
+/** String concatenation desugaring rewriter. */
+public class StringConcatInstructionDesugaring implements CfInstructionDesugaring {
+
+  private final DexItemFactory factory;
+  private final StringBuildingMethods stringBuilderMethods;
+
+  private final Map<DexType, DexMethod> paramTypeToAppendMethod = new IdentityHashMap<>();
+
+  public StringConcatInstructionDesugaring(AppView<?> appView) {
+    this.factory = appView.dexItemFactory();
+    this.stringBuilderMethods = factory.stringBuilderMethods;
+
+    // Mapping of type parameters to methods of StringBuilder.
+    paramTypeToAppendMethod.put(factory.booleanType, stringBuilderMethods.appendBoolean);
+    paramTypeToAppendMethod.put(factory.charType, stringBuilderMethods.appendChar);
+    paramTypeToAppendMethod.put(factory.byteType, stringBuilderMethods.appendInt);
+    paramTypeToAppendMethod.put(factory.shortType, stringBuilderMethods.appendInt);
+    paramTypeToAppendMethod.put(factory.intType, stringBuilderMethods.appendInt);
+    paramTypeToAppendMethod.put(factory.longType, stringBuilderMethods.appendLong);
+    paramTypeToAppendMethod.put(factory.floatType, stringBuilderMethods.appendFloat);
+    paramTypeToAppendMethod.put(factory.doubleType, stringBuilderMethods.appendDouble);
+    paramTypeToAppendMethod.put(factory.stringType, stringBuilderMethods.appendString);
+  }
+
+  @Override
+  public Collection<CfInstruction> desugarInstruction(
+      CfInstruction instruction,
+      FreshLocalProvider freshLocalProvider,
+      LocalStackAllocator localStackAllocator,
+      CfInstructionDesugaringEventConsumer eventConsumer,
+      ProgramMethod context,
+      MethodProcessingContext methodProcessingContext) {
+    if (instruction.isInvokeDynamic()) {
+      // We are interested in bootstrap methods StringConcatFactory::makeConcat
+      // and StringConcatFactory::makeConcatWthConstants, both are static.
+      CfInvokeDynamic invoke = instruction.asInvokeDynamic();
+      DexCallSite callSite = invoke.getCallSite();
+      if (callSite.bootstrapMethod.type.isInvokeStatic()) {
+        DexMethod bootstrapMethod = callSite.bootstrapMethod.asMethod();
+        if (bootstrapMethod == factory.stringConcatFactoryMembers.makeConcat) {
+          return desugarMakeConcat(invoke, freshLocalProvider, localStackAllocator);
+        }
+        if (bootstrapMethod == factory.stringConcatFactoryMembers.makeConcatWithConstants) {
+          return desugarMakeConcatWithConstants(
+              invoke, freshLocalProvider, localStackAllocator, context);
+        }
+      }
+    }
+    return null;
+  }
+
+  private Collection<CfInstruction> desugarMakeConcat(
+      CfInvokeDynamic invoke,
+      FreshLocalProvider freshLocalProvider,
+      LocalStackAllocator localStackAllocator) {
+    DexProto proto = invoke.getCallSite().methodProto;
+    DexType[] parameters = proto.parameters.values;
+
+    // Collect chunks.
+    ConcatBuilder builder = new ConcatBuilder();
+    for (DexType parameter : parameters) {
+      ValueType valueType = ValueType.fromDexType(parameter);
+      builder.addChunk(
+          new ArgumentChunk(
+              paramTypeToAppendMethod.getOrDefault(parameter, stringBuilderMethods.appendObject),
+              freshLocalProvider.getFreshLocal(valueType.requiredRegisters())));
+    }
+
+    // Desugar the instruction.
+    return builder.desugar(localStackAllocator);
+  }
+
+  private Collection<CfInstruction> desugarMakeConcatWithConstants(
+      CfInvokeDynamic invoke,
+      FreshLocalProvider freshLocalProvider,
+      LocalStackAllocator localStackAllocator,
+      ProgramMethod context) {
+    DexCallSite callSite = invoke.getCallSite();
+    DexProto proto = callSite.methodProto;
+    DexTypeList parameters = proto.getParameters();
+    List<DexValue> bootstrapArgs = callSite.bootstrapArgs;
+
+    // Get `recipe` string.
+    if (bootstrapArgs.isEmpty()) {
+      throw error(context, "bootstrap method misses `recipe` argument");
+    }
+
+    // Extract recipe.
+    DexValueString recipeValue = bootstrapArgs.get(0).asDexValueString();
+    if (recipeValue == null) {
+      throw error(context, "bootstrap method argument `recipe` must be a string");
+    }
+    String recipe = recipeValue.getValue().toString();
+
+    // Constant arguments to `recipe`.
+    List<DexValue> constantArguments = new ArrayList<>();
+    for (int i = 1; i < bootstrapArgs.size(); i++) {
+      constantArguments.add(bootstrapArgs.get(i));
+    }
+
+    // Collect chunks and patch the instruction.
+    ConcatBuilder builder = new ConcatBuilder();
+    StringBuilder acc = new StringBuilder();
+    int length = recipe.length();
+    Iterator<DexValue> constantArgumentsIterator = constantArguments.iterator();
+    Iterator<DexType> parameterIterator = parameters.iterator();
+    for (int i = 0; i < length; i++) {
+      char c = recipe.charAt(i);
+      if (c == '\u0001') {
+        // Reference to an argument, so we need to flush the accumulated string.
+        if (acc.length() > 0) {
+          DexString stringConstant = factory.createString(acc.toString());
+          builder.addChunk(
+              new ConstantChunk(paramTypeToAppendMethod.get(factory.stringType), stringConstant));
+          acc.setLength(0);
+        }
+        if (!parameterIterator.hasNext()) {
+          throw error(context, "too many argument references in `recipe`");
+        }
+        DexType parameter = parameterIterator.next();
+        ValueType valueType = ValueType.fromDexType(parameter);
+        builder.addChunk(
+            new ArgumentChunk(
+                paramTypeToAppendMethod.getOrDefault(parameter, stringBuilderMethods.appendObject),
+                freshLocalProvider.getFreshLocal(valueType.requiredRegisters())));
+      } else if (c == '\u0002') {
+        // Reference to a constant. Since it's a constant we just convert it to string and append to
+        // `acc`, this way we will avoid calling toString() on every call.
+        if (!constantArgumentsIterator.hasNext()) {
+          throw error(context, "too many constant references in `recipe`");
+        }
+        acc.append(convertToString(constantArgumentsIterator.next(), context));
+      } else {
+        acc.append(c);
+      }
+    }
+
+    if (parameterIterator.hasNext()) {
+      throw error(
+          context,
+          "too few argument references in `recipe`, "
+              + "expected "
+              + parameters.size()
+              + ", referenced: "
+              + (parameters.size() - IteratorUtils.countRemaining(parameterIterator)));
+    }
+
+    if (constantArgumentsIterator.hasNext()) {
+      throw error(
+          context,
+          "too few constant references in `recipe`, "
+              + "expected "
+              + constantArguments.size()
+              + ", referenced: "
+              + (constantArguments.size()
+                  - IteratorUtils.countRemaining(constantArgumentsIterator)));
+    }
+
+    // Final part.
+    if (acc.length() > 0) {
+      DexString stringConstant = factory.createString(acc.toString());
+      builder.addChunk(
+          new ConstantChunk(paramTypeToAppendMethod.get(factory.stringType), stringConstant));
+    }
+
+    // Desugar the instruction.
+    return builder.desugar(localStackAllocator);
+  }
+
+  @Override
+  public boolean needsDesugaring(CfInstruction instruction, ProgramMethod context) {
+    return instruction.isInvokeDynamic()
+        && needsDesugaring(instruction.asInvokeDynamic().getCallSite());
+  }
+
+  private boolean needsDesugaring(DexCallSite callSite) {
+    // We are interested in bootstrap methods StringConcatFactory::makeConcat
+    // and StringConcatFactory::makeConcatWithConstants, both are static.
+    if (callSite.bootstrapMethod.type.isInvokeStatic()) {
+      DexMethod bootstrapMethod = callSite.bootstrapMethod.asMethod();
+      return bootstrapMethod == factory.stringConcatFactoryMembers.makeConcat
+          || bootstrapMethod == factory.stringConcatFactoryMembers.makeConcatWithConstants;
+    }
+    return false;
+  }
+
+  private static String convertToString(DexValue value, ProgramMethod context) {
+    if (value.isDexValueString()) {
+      return value.asDexValueString().getValue().toString();
+    }
+    throw error(
+        context,
+        "const arg referenced from `recipe` is not supported: " + value.getClass().getName());
+  }
+
+  private final class ConcatBuilder {
+
+    private final List<Chunk> chunks = new ArrayList<>();
+
+    private ArgumentChunk biggestArgumentChunk = null;
+    private ConstantChunk firstConstantChunk = null;
+    private int argumentChunksStackSize = 0;
+
+    ConcatBuilder() {}
+
+    void addChunk(ArgumentChunk chunk) {
+      chunks.add(chunk);
+      argumentChunksStackSize += chunk.getValueType().requiredRegisters();
+      if (biggestArgumentChunk == null
+          || chunk.getValueType().requiredRegisters()
+              > biggestArgumentChunk.getValueType().requiredRegisters()) {
+        biggestArgumentChunk = chunk;
+      }
+    }
+
+    void addChunk(ConstantChunk chunk) {
+      chunks.add(chunk);
+      if (firstConstantChunk == null) {
+        firstConstantChunk = chunk;
+      }
+    }
+
+    /**
+     * Patch current `invoke-custom` instruction with:
+     *
+     * <pre>
+     *   prologue:
+     *      |   new-instance v0, StringBuilder
+     *      |   invoke-direct {v0}, void StringBuilder.<init>()
+     *
+     *   populate each chunk:
+     *      |   (optional) load the constant, e.g.: const-string v1, ""
+     *      |   invoke-virtual {v0, v1}, StringBuilder StringBuilder.append([type])
+     *
+     *   epilogue:
+     *      |   invoke-virtual {v0}, String StringBuilder.toString()
+     *
+     * </pre>
+     */
+    final Collection<CfInstruction> desugar(LocalStackAllocator localStackAllocator) {
+      Deque<CfInstruction> replacement = new ArrayDeque<>();
+      for (Chunk chunk : chunks) {
+        if (chunk.isArgumentChunk()) {
+          ArgumentChunk argumentChunk = chunk.asArgumentChunk();
+          replacement.addFirst(
+              new CfStore(argumentChunk.getValueType(), argumentChunk.getVariableIndex()));
+        }
+      }
+      replacement.add(new CfNew(factory.stringBuilderType));
+      replacement.add(new CfStackInstruction(Opcode.Dup));
+      replacement.add(
+          new CfInvoke(Opcodes.INVOKESPECIAL, stringBuilderMethods.defaultConstructor, false));
+      for (Chunk chunk : chunks) {
+        if (chunk.isArgumentChunk()) {
+          ArgumentChunk argumentChunk = chunk.asArgumentChunk();
+          replacement.add(
+              new CfLoad(argumentChunk.getValueType(), argumentChunk.getVariableIndex()));
+        } else {
+          assert chunk.isConstantChunk();
+          replacement.add(new CfConstString(chunk.asConstantChunk().getStringConstant()));
+        }
+        replacement.add(new CfInvoke(Opcodes.INVOKEVIRTUAL, chunk.method, false));
+      }
+      replacement.add(new CfInvoke(Opcodes.INVOKEVIRTUAL, stringBuilderMethods.toString, false));
+
+      // Coming into the original invoke-dynamic instruction, we have N arguments on the stack. We
+      // then pop the N arguments from the stack, allocate a new-instance on the stack, and dup it,
+      // to initialize the instance. We then one-by-one load the arguments and call append(). We
+      // therefore need a local stack of size 3 if there is a wide argument, and otherwise a local
+      // stack of size 2.
+      int maxLocalStackSizeAfterStores =
+          2
+              + BooleanUtils.intValue(
+                  biggestArgumentChunk != null
+                      && biggestArgumentChunk.getValueType().requiredRegisters() == 2);
+      if (maxLocalStackSizeAfterStores > argumentChunksStackSize) {
+        localStackAllocator.allocateLocalStack(
+            maxLocalStackSizeAfterStores - argumentChunksStackSize);
+      }
+      return replacement;
+    }
+  }
+
+  private abstract static class Chunk {
+
+    private final DexMethod method;
+
+    Chunk(DexMethod method) {
+      this.method = method;
+    }
+
+    public DexMethod getMethod() {
+      return method;
+    }
+
+    public ValueType getValueType() {
+      assert method.getProto().getArity() == 1;
+      return ValueType.fromDexType(method.getParameter(0));
+    }
+
+    public boolean isArgumentChunk() {
+      return false;
+    }
+
+    public ArgumentChunk asArgumentChunk() {
+      return null;
+    }
+
+    public boolean isConstantChunk() {
+      return false;
+    }
+
+    public ConstantChunk asConstantChunk() {
+      return null;
+    }
+  }
+
+  private static final class ArgumentChunk extends Chunk {
+
+    private final int variableIndex;
+
+    ArgumentChunk(DexMethod method, int variableIndex) {
+      super(method);
+      this.variableIndex = variableIndex;
+    }
+
+    public int getVariableIndex() {
+      return variableIndex;
+    }
+
+    @Override
+    public boolean isArgumentChunk() {
+      return true;
+    }
+
+    @Override
+    public ArgumentChunk asArgumentChunk() {
+      return this;
+    }
+  }
+
+  private static final class ConstantChunk extends Chunk {
+
+    private final DexString stringConstant;
+
+    ConstantChunk(DexMethod method, DexString stringConstant) {
+      super(method);
+      this.stringConstant = stringConstant;
+    }
+
+    public DexString getStringConstant() {
+      return stringConstant;
+    }
+
+    @Override
+    public boolean isConstantChunk() {
+      return true;
+    }
+
+    @Override
+    public ConstantChunk asConstantChunk() {
+      return this;
+    }
+  }
+
+  private static CompilationError error(ProgramMethod context, String message) {
+    return new CompilationError(
+        "String concatenation desugaring error (method: "
+            + context.toSourceString()
+            + "): "
+            + message);
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/twr/TwrCloseResourceDesugaringEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/twr/TwrCloseResourceDesugaringEventConsumer.java
new file mode 100644
index 0000000..1311da0
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/twr/TwrCloseResourceDesugaringEventConsumer.java
@@ -0,0 +1,12 @@
+// Copyright (c) 2021, 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.desugar.twr;
+
+import com.android.tools.r8.graph.ProgramMethod;
+
+public interface TwrCloseResourceDesugaringEventConsumer {
+
+  void acceptTwrCloseResourceMethod(ProgramMethod closeMethod, ProgramMethod context);
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/twr/TwrCloseResourceInstructionDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/twr/TwrCloseResourceInstructionDesugaring.java
new file mode 100644
index 0000000..076c9b3
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/twr/TwrCloseResourceInstructionDesugaring.java
@@ -0,0 +1,94 @@
+// Copyright (c) 2021, 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.desugar.twr;
+
+import com.android.tools.r8.cf.code.CfInstruction;
+import com.android.tools.r8.cf.code.CfInvoke;
+import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexProto;
+import com.android.tools.r8.graph.MethodAccessFlags;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.desugar.CfInstructionDesugaring;
+import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
+import com.android.tools.r8.ir.desugar.FreshLocalProvider;
+import com.android.tools.r8.ir.desugar.LocalStackAllocator;
+import com.android.tools.r8.ir.desugar.backports.BackportedMethods;
+import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
+import com.google.common.collect.ImmutableList;
+import java.util.Collection;
+import org.objectweb.asm.Opcodes;
+
+public class TwrCloseResourceInstructionDesugaring implements CfInstructionDesugaring {
+
+  private final AppView<?> appView;
+  private final DexItemFactory dexItemFactory;
+  private final DexProto twrCloseResourceProto;
+
+  public TwrCloseResourceInstructionDesugaring(AppView<?> appView) {
+    this.appView = appView;
+    this.dexItemFactory = appView.dexItemFactory();
+    this.twrCloseResourceProto =
+        dexItemFactory.createProto(
+            dexItemFactory.voidType, dexItemFactory.throwableType, dexItemFactory.objectType);
+  }
+
+  @Override
+  public Collection<CfInstruction> desugarInstruction(
+      CfInstruction instruction,
+      FreshLocalProvider freshLocalProvider,
+      LocalStackAllocator localStackAllocator,
+      CfInstructionDesugaringEventConsumer eventConsumer,
+      ProgramMethod context,
+      MethodProcessingContext methodProcessingContext) {
+    if (!instruction.isInvokeStatic()) {
+      return null;
+    }
+
+    CfInvoke invoke = instruction.asInvoke();
+    DexMethod invokedMethod = invoke.getMethod();
+    if (!isTwrCloseResourceMethod(invokedMethod)) {
+      return null;
+    }
+
+    // Synthesize a new method.
+    ProgramMethod closeMethod = createSyntheticCloseResourceMethod(methodProcessingContext);
+    eventConsumer.acceptTwrCloseResourceMethod(closeMethod, context);
+
+    // Rewrite the invoke to the new synthetic.
+    return ImmutableList.of(new CfInvoke(Opcodes.INVOKESTATIC, closeMethod.getReference(), false));
+  }
+
+  private ProgramMethod createSyntheticCloseResourceMethod(
+      MethodProcessingContext methodProcessingContext) {
+    return appView
+        .getSyntheticItems()
+        .createMethod(
+            SyntheticKind.TWR_CLOSE_RESOURCE,
+            methodProcessingContext.createUniqueContext(),
+            appView.dexItemFactory(),
+            methodBuilder ->
+                methodBuilder
+                    .setAccessFlags(MethodAccessFlags.createPublicStaticSynthetic())
+                    .setProto(twrCloseResourceProto)
+                    .setCode(
+                        m ->
+                            BackportedMethods.CloseResourceMethod_closeResourceImpl(
+                                appView.options(), m)));
+  }
+
+  @Override
+  public boolean needsDesugaring(CfInstruction instruction, ProgramMethod context) {
+    return instruction.isInvokeStatic()
+        && isTwrCloseResourceMethod(instruction.asInvoke().getMethod());
+  }
+
+  private boolean isTwrCloseResourceMethod(DexMethod method) {
+    return method.name == dexItemFactory.twrCloseResourceMethodName
+        && method.proto == dexItemFactory.twrCloseResourceMethodProto;
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
index 3aaba06..7432e43 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
@@ -1248,10 +1248,29 @@
     // Collect basic blocks that check nullability of the parameter.
     Set<BasicBlock> nullCheckedBlocks = Sets.newIdentityHashSet();
     for (Instruction user : value.aliasedUsers()) {
-      if (user.isAssumeWithNonNullAssumption()
-          || user.throwsNpeIfValueIsNull(value, appView, code.context())) {
+      if (user.isAssumeWithNonNullAssumption()) {
+        // We don't allow assume instructions after throwing instructions, thus this block is either
+        // non-throwing or the assume instruction is before the throwing instruction.
+        assert !user.getBlock().hasCatchHandlers()
+            || user.getBlock().getInstructions().stream()
+                    .filter(
+                        instruction -> instruction == user || instruction.instructionTypeCanThrow())
+                    .findFirst()
+                    .get()
+                == user;
         nullCheckedBlocks.add(user.getBlock());
+        continue;
       }
+
+      if (user.throwsNpeIfValueIsNull(value, appView, code.context())) {
+        if (user.getBlock().hasCatchHandlers()) {
+          nullCheckedBlocks.addAll(user.getBlock().getNormalSuccessors());
+        } else {
+          nullCheckedBlocks.add(user.getBlock());
+        }
+        continue;
+      }
+
       if (user.isIf()
           && user.asIf().isZeroTest()
           && (user.asIf().getType() == If.Type.EQ || user.asIf().getType() == If.Type.NE)) {
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 2f7edb2..0d7fe26 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -22,6 +22,9 @@
 import com.android.tools.r8.experimental.graphinfo.GraphConsumer;
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.ClassDefinition;
+import com.android.tools.r8.graph.ClasspathOrLibraryClass;
+import com.android.tools.r8.graph.ClasspathOrLibraryDefinition;
 import com.android.tools.r8.graph.DexAnnotation;
 import com.android.tools.r8.graph.DexAnnotationSet;
 import com.android.tools.r8.graph.DexApplication;
@@ -85,13 +88,12 @@
 import com.android.tools.r8.ir.code.InvokeMethod;
 import com.android.tools.r8.ir.code.InvokeVirtual;
 import com.android.tools.r8.ir.code.Value;
-import com.android.tools.r8.ir.desugar.BackportedMethodRewriter;
 import com.android.tools.r8.ir.desugar.CfInstructionDesugaringCollection;
 import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
 import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer.R8CfInstructionDesugaringEventConsumer;
 import com.android.tools.r8.ir.desugar.DesugaredLibraryAPIConverter;
+import com.android.tools.r8.ir.desugar.LambdaClass;
 import com.android.tools.r8.ir.desugar.LambdaDescriptor;
-import com.android.tools.r8.ir.desugar.TwrCloseResourceRewriter;
 import com.android.tools.r8.kotlin.KotlinMetadataEnqueuerExtension;
 import com.android.tools.r8.logging.Log;
 import com.android.tools.r8.naming.identifiernamestring.IdentifierNameStringLookupResult;
@@ -108,9 +110,9 @@
 import com.android.tools.r8.shaking.RootSetUtils.RootSet;
 import com.android.tools.r8.shaking.RootSetUtils.RootSetBuilder;
 import com.android.tools.r8.shaking.ScopedDexMethodSet.AddMethodIfMoreVisibleResult;
+import com.android.tools.r8.synthesis.SyntheticItems.SynthesizingContextOracle;
 import com.android.tools.r8.utils.Action;
 import com.android.tools.r8.utils.InternalOptions;
-import com.android.tools.r8.utils.InternalOptions.DesugarState;
 import com.android.tools.r8.utils.IteratorUtils;
 import com.android.tools.r8.utils.MethodSignatureEquivalence;
 import com.android.tools.r8.utils.OptionalBool;
@@ -249,6 +251,13 @@
   private final Map<DexProgramClass, ProgramFieldSet> reachableInstanceFields =
       Maps.newIdentityHashMap();
 
+  // TODO(b/180091213): Remove when supported by synthetic items.
+  /**
+   * The synthesizing contexts for classes synthesized by lambda desugaring and twr close resource
+   * desugaring.
+   */
+  private final Map<DexProgramClass, ProgramMethod> synthesizingContexts = new IdentityHashMap<>();
+
   /**
    * Set of types that are mentioned in the program. We at least need an empty abstract class item
    * for these.
@@ -278,7 +287,7 @@
    *
    * <p>Used to build a new app of just referenced types and avoid duplicate tracing.
    */
-  private final Set<DexClass> liveNonProgramTypes = Sets.newIdentityHashSet();
+  private final Set<ClasspathOrLibraryClass> liveNonProgramTypes = Sets.newIdentityHashSet();
 
   /** Set of reachable proto types that will be dead code eliminated. */
   private final Set<DexProgramClass> deadProtoTypeCandidates = Sets.newIdentityHashSet();
@@ -382,13 +391,7 @@
   private final GraphReporter graphReporter;
 
   private final CfInstructionDesugaringCollection desugaring;
-
-  private final BackportedMethodRewriter backportRewriter;
-  private final TwrCloseResourceRewriter twrCloseResourceRewriter;
-
   private final DesugaredLibraryConversionWrapperAnalysis desugaredLibraryWrapperAnalysis;
-  private final Map<DexMethod, ProgramMethod> methodsWithBackports = new IdentityHashMap<>();
-  private final Map<DexMethod, ProgramMethod> methodsWithTwrCloseResource = new IdentityHashMap<>();
   private final ProgramMethodSet pendingDesugaring = ProgramMethodSet.create();
 
   Enqueuer(
@@ -435,12 +438,6 @@
         mode.isInitialTreeShaking()
             ? CfInstructionDesugaringCollection.create(appView)
             : CfInstructionDesugaringCollection.empty();
-    backportRewriter =
-        options.desugarState == DesugarState.ON ? new BackportedMethodRewriter(appView) : null;
-    twrCloseResourceRewriter =
-        TwrCloseResourceRewriter.enableTwrCloseResourceDesugaring(options)
-            ? new TwrCloseResourceRewriter(appView)
-            : null;
 
     objectAllocationInfoCollection =
         ObjectAllocationInfoCollectionImpl.builder(mode.isInitialTreeShaking(), graphReporter);
@@ -539,7 +536,8 @@
     if (clazz == null) {
       ignoreMissingClass(type);
     } else if (clazz.isNotProgramClass()) {
-      addLiveNonProgramType(clazz);
+      addLiveNonProgramType(
+          clazz.asClasspathOrLibraryClass(), this::ignoreMissingClasspathOrLibraryClass);
     }
   }
 
@@ -568,13 +566,13 @@
     definitionFor(type, context, missingClassConsumer);
   }
 
-  private void recordMethodReference(DexMethod method, ProgramDefinition context) {
+  private void recordMethodReference(DexMethod method, ProgramDerivedContext context) {
     recordMethodReference(method, context, this::reportMissingClass);
   }
 
   private void recordMethodReference(
       DexMethod method,
-      ProgramDefinition context,
+      ProgramDerivedContext context,
       BiConsumer<DexType, ProgramDerivedContext> missingClassConsumer) {
     recordTypeReference(method.holder, context, missingClassConsumer);
     recordTypeReference(method.proto.returnType, context, missingClassConsumer);
@@ -617,7 +615,10 @@
       return null;
     }
     if (clazz.isNotProgramClass()) {
-      addLiveNonProgramType(clazz);
+      addLiveNonProgramType(
+          clazz.asClasspathOrLibraryClass(),
+          (missingType, derivedContext) ->
+              reportMissingClass(missingType, derivedContext.asProgramDerivedContext(context)));
     }
     return clazz;
   }
@@ -626,58 +627,66 @@
     return keepInfo.isPinned(type, appInfo);
   }
 
-  private void addLiveNonProgramType(DexClass clazz) {
-    assert clazz.isNotProgramClass();
-    // Fast path to avoid the worklist when the class is already seen.
-    if (!liveNonProgramTypes.add(clazz)) {
-      return;
-    }
-    Deque<DexClass> worklist = new ArrayDeque<>();
-    worklist.addLast(clazz);
-    while (!worklist.isEmpty()) {
-      DexClass definition = worklist.removeFirst();
-      processNewLiveNonProgramType(definition, worklist);
+  private void addLiveNonProgramType(
+      ClasspathOrLibraryClass clazz,
+      BiConsumer<DexType, ClasspathOrLibraryDefinition> missingClassConsumer) {
+    WorkList<ClasspathOrLibraryClass> worklist =
+        WorkList.newIdentityWorkList(clazz, liveNonProgramTypes);
+    while (worklist.hasNext()) {
+      ClasspathOrLibraryClass definition = worklist.next();
+      processNewLiveNonProgramType(definition, worklist, missingClassConsumer);
     }
   }
 
-  private void processNewLiveNonProgramType(DexClass clazz, Deque<DexClass> worklist) {
-    assert clazz.isNotProgramClass();
+  private void processNewLiveNonProgramType(
+      ClasspathOrLibraryClass clazz,
+      WorkList<ClasspathOrLibraryClass> worklist,
+      BiConsumer<DexType, ClasspathOrLibraryDefinition> missingClassConsumer) {
     if (clazz.isLibraryClass()) {
       // TODO(b/149201735): This likely needs to apply to classpath too.
       ensureMethodsContinueToWidenAccess(clazz);
       // Only libraries must not derive program. Classpath classes can, assuming correct keep rules.
       warnIfLibraryTypeInheritsFromProgramType(clazz.asLibraryClass());
     }
-    for (DexEncodedField field : clazz.fields()) {
-      addNonProgramClassToWorklist(field.field.type, worklist);
-    }
-    for (DexEncodedMethod method : clazz.methods()) {
-      addNonProgramClassToWorklist(method.method.proto.returnType, worklist);
-      for (DexType param : method.method.proto.parameters.values) {
-        addNonProgramClassToWorklist(param, worklist);
-      }
-    }
+    clazz.forEachClassField(
+        field ->
+            addNonProgramClassToWorklist(
+                field.getType(),
+                field.asClasspathOrLibraryDefinition(),
+                worklist,
+                missingClassConsumer));
+    clazz.forEachClassMethod(
+        method -> {
+          ClasspathOrLibraryDefinition derivedContext = method.asClasspathOrLibraryDefinition();
+          addNonProgramClassToWorklist(
+              method.getReturnType(), derivedContext, worklist, missingClassConsumer);
+          for (DexType parameter : method.getParameters()) {
+            addNonProgramClassToWorklist(parameter, derivedContext, worklist, missingClassConsumer);
+          }
+        });
     for (DexType supertype : clazz.allImmediateSupertypes()) {
-      addNonProgramClassToWorklist(supertype, worklist);
+      addNonProgramClassToWorklist(
+          supertype, clazz.asClasspathOrLibraryDefinition(), worklist, missingClassConsumer);
     }
   }
 
-  private void addNonProgramClassToWorklist(DexType type, Deque<DexClass> worklist) {
+  private void addNonProgramClassToWorklist(
+      DexType type,
+      ClasspathOrLibraryDefinition context,
+      WorkList<ClasspathOrLibraryClass> worklist,
+      BiConsumer<DexType, ClasspathOrLibraryDefinition> missingClassConsumer) {
     if (type.isArrayType()) {
       type = type.toBaseType(appView.dexItemFactory());
     }
     if (!type.isClassType()) {
       return;
     }
-    DexClass definition = appView.definitionFor(type);
-    if (definition == null) {
-      reportMissingClassWithoutContext(type);
-      return;
+    DexClass clazz = appView.definitionFor(type);
+    if (clazz == null) {
+      missingClassConsumer.accept(type, context);
+    } else if (!clazz.isProgramClass()) {
+      worklist.addIfNotSeen(clazz.asClasspathOrLibraryClass());
     }
-    if (definition.isProgramClass() || !liveNonProgramTypes.add(definition)) {
-      return;
-    }
-    worklist.addLast(definition);
   }
 
   private DexProgramClass getProgramClassOrNull(DexType type, ProgramDefinition context) {
@@ -1207,9 +1216,6 @@
 
   private void traceInvokeDirect(
       DexMethod invokedMethod, ProgramMethod context, KeepReason reason) {
-    if (registerBackportInvoke(invokedMethod, context)) {
-      return;
-    }
     if (!registerMethodWithTargetAndContext(
         methodAccessInfoCollection::registerInvokeDirectInContext, invokedMethod, context)) {
       return;
@@ -1231,10 +1237,6 @@
 
   private void traceInvokeInterface(
       DexMethod method, ProgramMethod context, KeepReason keepReason) {
-    if (registerBackportInvoke(method, context)) {
-      return;
-    }
-
     if (!registerMethodWithTargetAndContext(
         methodAccessInfoCollection::registerInvokeInterfaceInContext, method, context)) {
       return;
@@ -1254,32 +1256,8 @@
     traceInvokeStatic(invokedMethod, context, KeepReason.invokedFromLambdaCreatedIn(context));
   }
 
-  private boolean registerBackportInvoke(DexMethod invokedMethod, ProgramMethod context) {
-    if (backportRewriter != null && backportRewriter.needsDesugaring(invokedMethod)) {
-      methodsWithBackports.putIfAbsent(context.getReference(), context);
-      return true;
-    }
-    return false;
-  }
-
-  private boolean registerCloseResource(DexMethod invokedMethod, ProgramMethod context) {
-    if (twrCloseResourceRewriter != null
-        && TwrCloseResourceRewriter.isTwrCloseResourceMethod(
-            invokedMethod, appView.dexItemFactory())) {
-      methodsWithTwrCloseResource.putIfAbsent(context.getReference(), context);
-      return true;
-    }
-    return false;
-  }
-
   private void traceInvokeStatic(
       DexMethod invokedMethod, ProgramMethod context, KeepReason reason) {
-    if (registerBackportInvoke(invokedMethod, context)) {
-      return;
-    }
-    if (registerCloseResource(invokedMethod, context)) {
-      return;
-    }
     DexItemFactory dexItemFactory = appView.dexItemFactory();
     if (dexItemFactory.classMethods.isReflectiveClassLookup(invokedMethod)
         || dexItemFactory.atomicFieldUpdaterMethods.isFieldUpdater(invokedMethod)) {
@@ -1311,9 +1289,6 @@
   }
 
   void traceInvokeSuper(DexMethod invokedMethod, ProgramMethod context) {
-    if (registerBackportInvoke(invokedMethod, context)) {
-      return;
-    }
     // We have to revisit super invokes based on the context they are found in. The same
     // method descriptor will hit different targets, depending on the context it is used in.
     DexMethod actualTarget = getInvokeSuperTarget(invokedMethod, context);
@@ -1338,10 +1313,6 @@
 
   private void traceInvokeVirtual(
       DexMethod invokedMethod, ProgramMethod context, KeepReason reason) {
-    if (registerBackportInvoke(invokedMethod, context)) {
-      return;
-    }
-
     if (invokedMethod == appView.dexItemFactory().classMethods.newInstance
         || invokedMethod == appView.dexItemFactory().constructorMethods.newInstance) {
       pendingReflectiveUses.add(context);
@@ -1836,11 +1807,12 @@
     analyses.forEach(analysis -> analysis.processNewlyLiveClass(clazz, workList));
   }
 
-  private void ensureMethodsContinueToWidenAccess(DexClass clazz) {
+  private void ensureMethodsContinueToWidenAccess(ClassDefinition clazz) {
     assert !clazz.isProgramClass();
     ScopedDexMethodSet seen =
-        scopedMethodsForLiveTypes.computeIfAbsent(clazz.type, ignore -> new ScopedDexMethodSet());
-    clazz.virtualMethods().forEach(seen::addMethodIfMoreVisible);
+        scopedMethodsForLiveTypes.computeIfAbsent(
+            clazz.getType(), ignore -> new ScopedDexMethodSet());
+    clazz.getMethodCollection().forEachVirtualMethod(seen::addMethodIfMoreVisible);
   }
 
   private void ensureMethodsContinueToWidenAccess(
@@ -1983,11 +1955,15 @@
   private SingleResolutionResult resolveMethod(
       DexMethod method, ProgramDefinition context, KeepReason reason, boolean interfaceInvoke) {
     // Record the references in case they are not program types.
-    recordMethodReference(method, context);
     ResolutionResult resolutionResult = appInfo.resolveMethod(method, interfaceInvoke);
-    if (resolutionResult.isFailedResolution()) {
+    if (resolutionResult.isSingleResolution()) {
+      recordMethodReference(
+          method, resolutionResult.getResolutionPair().asProgramDerivedContext(context));
+    } else {
+      assert resolutionResult.isFailedResolution();
       markFailedMethodResolutionTargets(
           method, resolutionResult.asFailedResolution(), context, reason);
+      recordMethodReference(method, context);
     }
     return resolutionResult.asSingleResolution();
   }
@@ -2230,6 +2206,15 @@
     ignoreMissingClass(clazz);
   }
 
+  private void ignoreMissingClasspathOrLibraryClass(DexType clazz) {
+    ignoreMissingClass(clazz);
+  }
+
+  private void ignoreMissingClasspathOrLibraryClass(
+      DexType clazz, ClasspathOrLibraryDefinition context) {
+    ignoreMissingClasspathOrLibraryClass(clazz);
+  }
+
   private void reportMissingClass(DexType clazz, ProgramDerivedContext context) {
     assert !mode.isFinalTreeShaking()
             || missingClassesBuilder.wasAlreadyMissing(clazz)
@@ -2238,19 +2223,23 @@
             // TODO(b/157107464): See if we can clean this up.
             || (initialPrunedTypes != null && initialPrunedTypes.contains(clazz))
         : "Unexpected missing class `" + clazz.toSourceString() + "`";
-    missingClassesBuilder.addNewMissingClass(clazz, context);
-  }
-
-  @Deprecated
-  private void reportMissingClassWithoutContext(DexType clazz) {
-    assert !mode.isFinalTreeShaking()
-            || missingClassesBuilder.wasAlreadyMissing(clazz)
-            || appView.dexItemFactory().isPossiblyCompilerSynthesizedType(clazz)
-            || initialDeadProtoTypes.contains(clazz)
-            // TODO(b/157107464): See if we can clean this up.
-            || (initialPrunedTypes != null && initialPrunedTypes.contains(clazz))
-        : "Unexpected missing class `" + clazz.toSourceString() + "`";
-    missingClassesBuilder.legacyAddNewMissingClass(clazz);
+    // Do not report missing classes from D8/R8 synthesized methods on non-synthetic classes (for
+    // example, lambda accessibility bridges).
+    // TODO(b/180376674): Clean this up. Ideally the D8/R8 synthesized methods would be synthesized
+    //  using synthetic items, such that the synthetic items infrastructure would track the
+    //  synthesizing contexts for these methods as well. That way, this would just work without any
+    //  special handling because the mapping to the synthesizing contexts would also work for these
+    //  synthetic methods.
+    if (context.isProgramContext()
+        && context.getContext().isMethod()
+        && context.getContext().asMethod().getDefinition().isD8R8Synthesized()
+        && !appView
+            .getSyntheticItems()
+            .isSyntheticClass(context.getContext().asProgramDefinition().getContextClass())) {
+      missingClassesBuilder.ignoreNewMissingClass(clazz);
+    } else {
+      missingClassesBuilder.addNewMissingClass(clazz, context);
+    }
   }
 
   /**
@@ -3175,8 +3164,6 @@
     desugar(additions);
     synthesizeInterfaceMethodBridges(additions);
     synthesizeLibraryConversionWrappers(additions);
-    synthesizeBackports(additions);
-    synthesizeTwrCloseResource(additions);
     if (additions.isEmpty()) {
       return;
     }
@@ -3202,7 +3189,10 @@
       return;
     }
     R8CfInstructionDesugaringEventConsumer desugaringEventConsumer =
-        CfInstructionDesugaringEventConsumer.createForR8(appView);
+        CfInstructionDesugaringEventConsumer.createForR8(
+            appView,
+            this::recordLambdaSynthesizingContext,
+            this::recordTwrCloseResourceMethodSynthesizingContext);
     ThreadUtils.processItems(
         pendingDesugaring,
         method ->
@@ -3213,6 +3203,19 @@
     pendingDesugaring.clear();
   }
 
+  private void recordLambdaSynthesizingContext(LambdaClass lambdaClass, ProgramMethod context) {
+    synchronized (synthesizingContexts) {
+      synthesizingContexts.put(lambdaClass.getLambdaProgramClass(), context);
+    }
+  }
+
+  private void recordTwrCloseResourceMethodSynthesizingContext(
+      ProgramMethod closeMethod, ProgramMethod context) {
+    synchronized (synthesizingContexts) {
+      synthesizingContexts.put(closeMethod.getHolder(), context);
+    }
+  }
+
   private void synthesizeInterfaceMethodBridges(SyntheticAdditions additions) {
     for (ProgramMethod bridge : syntheticInterfaceMethodBridges.values()) {
       DexProgramClass holder = bridge.getHolder();
@@ -3223,20 +3226,6 @@
     syntheticInterfaceMethodBridges.clear();
   }
 
-  private void synthesizeBackports(SyntheticAdditions additions) {
-    for (ProgramMethod method : methodsWithBackports.values()) {
-      backportRewriter.desugar(
-          method, appInfo, additions.getMethodContext(method), additions::addLiveMethod);
-    }
-  }
-
-  private void synthesizeTwrCloseResource(SyntheticAdditions additions) {
-    for (ProgramMethod method : methodsWithTwrCloseResource.values()) {
-      twrCloseResourceRewriter.rewriteCf(
-          method, additions::addLiveMethod, additions.getMethodContext(method));
-    }
-  }
-
   private void finalizeLibraryMethodOverrideInformation() {
     for (DexProgramClass liveType : liveTypes.getItems()) {
       for (DexEncodedMethod method : liveType.virtualMethods()) {
@@ -3285,7 +3274,7 @@
     // Rebuild a new app only containing referenced types.
     Set<DexLibraryClass> libraryClasses = Sets.newIdentityHashSet();
     Set<DexClasspathClass> classpathClasses = Sets.newIdentityHashSet();
-    for (DexClass clazz : liveNonProgramTypes) {
+    for (ClasspathOrLibraryClass clazz : liveNonProgramTypes) {
       if (clazz.isLibraryClass()) {
         libraryClasses.add(clazz.asLibraryClass());
       } else if (clazz.isClasspathClass()) {
@@ -3305,6 +3294,13 @@
     // Verify the references on the pruned application after type synthesis.
     assert verifyReferences(app);
 
+    SynthesizingContextOracle lambdaSynthesizingContextOracle =
+        syntheticClass -> {
+          ProgramMethod lambdaSynthesisContext = synthesizingContexts.get(syntheticClass);
+          return lambdaSynthesisContext != null
+              ? ImmutableSet.of(lambdaSynthesisContext.getReference())
+              : ImmutableSet.of(syntheticClass.getType());
+        };
     AppInfoWithLiveness appInfoWithLiveness =
         new AppInfoWithLiveness(
             appInfo.getSyntheticItems().commit(app),
@@ -3312,7 +3308,10 @@
             appInfo.getMainDexInfo(),
             deadProtoTypes,
             appView.testing().enableExperimentalMissingClassesReporting
-                ? missingClassesBuilder.reportMissingClasses(appView)
+                ? (mode.isInitialTreeShaking()
+                    ? missingClassesBuilder.reportMissingClasses(
+                        appView, lambdaSynthesizingContextOracle)
+                    : missingClassesBuilder.assertNoMissingClasses(appView))
                 : missingClassesBuilder.ignoreMissingClasses(),
             SetUtils.mapIdentityHashSet(liveTypes.getItems(), DexProgramClass::getType),
             Enqueuer.toDescriptorSet(targetedMethods.getItems()),
@@ -3818,7 +3817,7 @@
   }
 
   private void markMethodAsTargeted(ProgramMethod method, KeepReason reason) {
-    if (!targetedMethods.add(method, reason)) {
+    if (!addTargetedMethod(method, reason)) {
       // Already targeted.
       return;
     }
@@ -4218,7 +4217,7 @@
         continue;
       }
 
-      DexProgramClass clazz = getProgramClassOrNull(type, method);
+      DexProgramClass clazz = getProgramClassOrNullFromReflectiveAccess(type, method);
       if (clazz != null && clazz.isInterface()) {
         // Add this interface to the set of pinned items to ensure that we do not merge the
         // interface into its unique subtype, if any.
diff --git a/src/main/java/com/android/tools/r8/shaking/MissingClasses.java b/src/main/java/com/android/tools/r8/shaking/MissingClasses.java
index aa49727..3670701 100644
--- a/src/main/java/com/android/tools/r8/shaking/MissingClasses.java
+++ b/src/main/java/com/android/tools/r8/shaking/MissingClasses.java
@@ -7,24 +7,32 @@
 import static com.android.tools.r8.ir.desugar.DesugaredLibraryAPIConverter.DESCRIPTOR_VIVIFIED_PREFIX;
 import static com.android.tools.r8.ir.desugar.DesugaredLibraryRetargeter.getRetargetPackageAndClassPrefixDescriptor;
 import static com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.EMULATE_LIBRARY_CLASS_NAME_SUFFIX;
+import static com.android.tools.r8.utils.collections.IdentityHashSetFromMap.newProgramDerivedContextSet;
 
 import com.android.tools.r8.diagnostic.MissingDefinitionsDiagnostic;
+import com.android.tools.r8.diagnostic.internal.MissingClassInfoImpl;
+import com.android.tools.r8.diagnostic.internal.MissingDefinitionContextUtils;
 import com.android.tools.r8.diagnostic.internal.MissingDefinitionsDiagnosticImpl;
 import com.android.tools.r8.errors.dontwarn.DontWarnConfiguration;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexReference;
 import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.ProgramDerivedContext;
+import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.synthesis.CommittedItems;
+import com.android.tools.r8.synthesis.SyntheticItems.SynthesizingContextOracle;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.SetUtils;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Sets;
 import java.util.Collection;
 import java.util.IdentityHashMap;
+import java.util.Iterator;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Set;
 import java.util.function.Predicate;
 
@@ -62,7 +70,8 @@
   public static class Builder {
 
     private final Set<DexType> alreadyMissingClasses;
-    private final Map<DexType, Set<DexReference>> newMissingClasses = new IdentityHashMap<>();
+    private final Map<DexType, Set<ProgramDerivedContext>> newMissingClasses =
+        new IdentityHashMap<>();
 
     // Set of missing types that are not to be reported as missing. This does not hide reports
     // if the same type is in newMissingClasses in which case it is reported regardless.
@@ -81,16 +90,15 @@
       assert context.getContext().getContextType() != type;
       if (!alreadyMissingClasses.contains(type)) {
         newMissingClasses
-            .computeIfAbsent(type, ignore -> Sets.newIdentityHashSet())
-            .add(context.getContext().getReference());
+            .computeIfAbsent(type, ignore -> newProgramDerivedContextSet())
+            .add(context);
       }
     }
 
     public void legacyAddNewMissingClass(DexType type) {
       if (!alreadyMissingClasses.contains(type)) {
-        // The legacy reporting is context insensitive, so therefore we use the missing classes
-        // themselves as contexts.
-        newMissingClasses.computeIfAbsent(type, ignore -> Sets.newIdentityHashSet()).add(type);
+        // The legacy reporting is context insensitive, so we just use an empty set of contexts.
+        newMissingClasses.computeIfAbsent(type, ignore -> newProgramDerivedContextSet());
       }
     }
 
@@ -105,7 +113,9 @@
     }
 
     public boolean contains(DexType type) {
-      return alreadyMissingClasses.contains(type) || newMissingClasses.containsKey(type);
+      return alreadyMissingClasses.contains(type)
+          || newMissingClasses.containsKey(type)
+          || newIgnoredMissingClasses.contains(type);
     }
 
     Builder removeAlreadyMissingClasses(Iterable<DexType> types) {
@@ -115,34 +125,120 @@
       return this;
     }
 
+    public MissingClasses assertNoMissingClasses(AppView<?> appView) {
+      assert getMissingClassesToBeReported(appView, clazz -> ImmutableSet.of(clazz.getType()))
+          .isEmpty();
+      return build();
+    }
+
     @Deprecated
     public MissingClasses ignoreMissingClasses() {
       return build();
     }
 
     public MissingClasses reportMissingClasses(AppView<?> appView) {
-      InternalOptions options = appView.options();
-      Map<DexType, Set<DexReference>> missingClassesToBeReported =
-          getMissingClassesToBeReported(appView);
+      return reportMissingClasses(appView, clazz -> ImmutableSet.of(clazz.getType()));
+    }
+
+    public MissingClasses reportMissingClasses(
+        AppView<?> appView, SynthesizingContextOracle synthesizingContextOracle) {
+      Map<DexType, Set<ProgramDerivedContext>> missingClassesToBeReported =
+          getMissingClassesToBeReported(appView, synthesizingContextOracle);
       if (!missingClassesToBeReported.isEmpty()) {
-        MissingDefinitionsDiagnostic diagnostic =
-            MissingDefinitionsDiagnosticImpl.builder()
-                .addMissingClasses(missingClassesToBeReported)
-                .setFatal(!options.ignoreMissingClasses)
-                .build();
-        if (options.ignoreMissingClasses) {
-          options.reporter.warning(diagnostic);
+        MissingDefinitionsDiagnostic diagnostic = createDiagnostic(missingClassesToBeReported);
+        if (appView.options().ignoreMissingClasses) {
+          appView.reporter().warning(diagnostic);
         } else {
-          throw options.reporter.fatalError(diagnostic);
+          throw appView.reporter().fatalError(diagnostic);
         }
       }
       return build();
     }
 
-    private Map<DexType, Set<DexReference>> getMissingClassesToBeReported(AppView<?> appView) {
+    private MissingDefinitionsDiagnostic createDiagnostic(
+        Map<DexType, Set<ProgramDerivedContext>> missingClassesToBeReported) {
+      MissingDefinitionsDiagnosticImpl.Builder diagnosticBuilder =
+          MissingDefinitionsDiagnosticImpl.builder();
+      missingClassesToBeReported.forEach(
+          (missingClass, programDerivedContexts) -> {
+            MissingClassInfoImpl.Builder missingClassInfoBuilder =
+                MissingClassInfoImpl.builder().setClass(missingClass.asClassReference());
+            for (ProgramDerivedContext programDerivedContext : programDerivedContexts) {
+              missingClassInfoBuilder.addReferencedFromContext(
+                  MissingDefinitionContextUtils.create(programDerivedContext));
+            }
+            diagnosticBuilder.addMissingDefinitionInfo(missingClassInfoBuilder.build());
+          });
+      return diagnosticBuilder.build();
+    }
+
+    private void rewriteMissingClassContexts(
+        AppView<?> appView, SynthesizingContextOracle synthesizingContextOracle) {
+      Iterator<Entry<DexType, Set<ProgramDerivedContext>>> newMissingClassesIterator =
+          newMissingClasses.entrySet().iterator();
+      while (newMissingClassesIterator.hasNext()) {
+        Entry<DexType, Set<ProgramDerivedContext>> entry = newMissingClassesIterator.next();
+        entry.setValue(
+            rewriteMissingClassContextsForSingleMissingClass(
+                appView, entry.getValue(), synthesizingContextOracle));
+      }
+    }
+
+    private static Set<ProgramDerivedContext> rewriteMissingClassContextsForSingleMissingClass(
+        AppView<?> appView,
+        Set<ProgramDerivedContext> contexts,
+        SynthesizingContextOracle synthesizingContextOracle) {
+      if (contexts.isEmpty()) {
+        // Legacy reporting does not have any contexts.
+        return contexts;
+      }
+
+      Set<ProgramDerivedContext> rewrittenContexts = newProgramDerivedContextSet();
+      for (ProgramDerivedContext context : contexts) {
+        if (!context.isProgramContext()) {
+          rewrittenContexts.add(context);
+          continue;
+        }
+
+        DexProgramClass clazz = context.getContext().asProgramDefinition().getContextClass();
+        if (!appView.getSyntheticItems().isSyntheticClass(clazz)) {
+          rewrittenContexts.add(context);
+          continue;
+        }
+
+        // Rewrite the synthetic context to its synthesizing contexts.
+        Set<DexReference> synthesizingContextReferences =
+            appView.getSyntheticItems().getSynthesizingContexts(clazz, synthesizingContextOracle);
+        assert synthesizingContextReferences != null;
+        assert !synthesizingContextReferences.isEmpty();
+        for (DexReference synthesizingContextReference : synthesizingContextReferences) {
+          if (synthesizingContextReference.isDexMethod()) {
+            DexProgramClass holder =
+                appView
+                    .definitionFor(synthesizingContextReference.getContextType())
+                    .asProgramClass();
+            ProgramMethod synthesizingContext =
+                holder.lookupProgramMethod(synthesizingContextReference.asDexMethod());
+            assert synthesizingContext != null;
+            rewrittenContexts.add(synthesizingContext);
+          } else {
+            assert false
+                : "Unexpected synthesizing context: "
+                    + synthesizingContextReference.toSourceString();
+          }
+        }
+      }
+      return rewrittenContexts;
+    }
+
+    private Map<DexType, Set<ProgramDerivedContext>> getMissingClassesToBeReported(
+        AppView<?> appView, SynthesizingContextOracle synthesizingContextOracle) {
+      // Rewrite synthetic program contexts into their synthesizing contexts, to avoid reporting
+      // any synthetic contexts.
+      rewriteMissingClassContexts(appView, synthesizingContextOracle);
       Predicate<DexType> allowedMissingClassesPredicate =
           getIsAllowedMissingClassesPredicate(appView);
-      Map<DexType, Set<DexReference>> missingClassesToBeReported =
+      Map<DexType, Set<ProgramDerivedContext>> missingClassesToBeReported =
           new IdentityHashMap<>(newMissingClasses.size());
       newMissingClasses.forEach(
           (missingClass, contexts) -> {
@@ -151,10 +247,20 @@
               return;
             }
 
+            // TODO(b/175543745): This is a legacy reported missing class; remove once no longer
+            //  supported.
+            if (contexts.isEmpty()) {
+              missingClassesToBeReported.put(missingClass, contexts);
+              return;
+            }
+
             // Remove all contexts that are matched by a -dontwarn rule (a missing class should not
             // be reported if it os only referenced from contexts that are matched by a -dontwarn).
             contexts.removeIf(
-                context -> appView.getDontWarnConfiguration().matches(context.getContextType()));
+                context ->
+                    appView
+                        .getDontWarnConfiguration()
+                        .matches(context.getContext().getContextType()));
 
             // If there are any contexts not matched by a -dontwarn rule, then report.
             if (!contexts.isEmpty()) {
@@ -184,12 +290,9 @@
               dexItemFactory.annotationSynthesizedClass,
               dexItemFactory.annotationSynthesizedClassMap,
               dexItemFactory.annotationThrows,
-              dexItemFactory.serializedLambdaType,
-              // TODO(b/176133674) StringConcatFactory is backported, but the class is reported as
-              //  missing because the enqueuer runs prior to backporting and thus sees the
-              //  non-desugared code.
-              dexItemFactory.stringConcatFactoryType)
-          .addAll(dexItemFactory.getConversionTypes())
+              dexItemFactory.serializedLambdaType)
+          .addAll(dexItemFactory.getJavaConversionTypes())
+          .addAll(dexItemFactory.getJ$ConversionTypes())
           .build();
     }
 
diff --git a/src/main/java/com/android/tools/r8/synthesis/SynthesizingContext.java b/src/main/java/com/android/tools/r8/synthesis/SynthesizingContext.java
index 1067e93..82f3204 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SynthesizingContext.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SynthesizingContext.java
@@ -8,15 +8,12 @@
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens;
 import com.android.tools.r8.graph.ProgramDefinition;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.shaking.MainDexInfo;
-import com.android.tools.r8.synthesis.SyntheticNaming.Phase;
-import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
 import java.util.Comparator;
 import java.util.Set;
 
@@ -63,33 +60,6 @@
     return new SynthesizingContext(synthesizingContextType, clazz.type, clazz.origin);
   }
 
-  static SynthesizingContext fromSyntheticContextChange(
-      SyntheticKind kind,
-      DexType syntheticType,
-      SynthesizingContext oldContext,
-      DexItemFactory factory) {
-    String descriptor = syntheticType.toDescriptorString();
-    DexType newContext;
-    if (kind.isFixedSuffixSynthetic) {
-      int i = descriptor.lastIndexOf(kind.descriptor);
-      if (i < 0 || descriptor.length() != i + kind.descriptor.length() + 1) {
-        assert false : "Unexpected fixed synthetic with invalid suffix: " + syntheticType;
-        return null;
-      }
-      newContext = factory.createType(descriptor.substring(0, i) + ";");
-    } else {
-      int i = descriptor.indexOf(SyntheticNaming.getPhaseSeparator(Phase.INTERNAL));
-      if (i <= 0) {
-        assert false : "Unexpected synthetic without internal separator: " + syntheticType;
-        return null;
-      }
-      newContext = factory.createType(descriptor.substring(0, i) + ";");
-    }
-    return newContext == oldContext.getSynthesizingContextType()
-        ? oldContext
-        : new SynthesizingContext(newContext, newContext, oldContext.inputContextOrigin);
-  }
-
   private SynthesizingContext(
       DexType synthesizingContextType, DexType inputContextType, Origin inputContextOrigin) {
     this.synthesizingContextType = synthesizingContextType;
@@ -127,10 +97,10 @@
   }
 
   void registerPrefixRewriting(DexType hygienicType, AppView<?> appView) {
-    assert hygienicType.toSourceString().startsWith(synthesizingContextType.toSourceString());
     if (!appView.options().isDesugaredLibraryCompilation()) {
       return;
     }
+    assert hygienicType.toSourceString().startsWith(synthesizingContextType.toSourceString());
     DexType rewrittenContext =
         appView
             .options()
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticClassReference.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticClassReference.java
index 25142ee..69f87fe 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticClassReference.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticClassReference.java
@@ -30,4 +30,9 @@
   DexType getHolder() {
     return type;
   }
+
+  @Override
+  DexType getReference() {
+    return type;
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticClasspathClassReference.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticClasspathClassReference.java
index 5b9ba3c..72beb13 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticClasspathClassReference.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticClasspathClassReference.java
@@ -34,9 +34,12 @@
   }
 
   @Override
-  SyntheticClasspathClassReference rewrite(NonIdentityGraphLens lens) {
+  SyntheticClasspathClassReference internalRewrite(
+      SynthesizingContext rewrittenContext, NonIdentityGraphLens lens) {
     assert type == lens.lookupType(type)
         : "Unexpected classpath rewrite of type " + type.toSourceString();
+    assert getContext() == rewrittenContext
+        : "Unexpected classpath rewrite of context type " + getContext();
     return this;
   }
 }
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticDefinition.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticDefinition.java
index 239e7d0..9520d57 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticDefinition.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticDefinition.java
@@ -59,12 +59,21 @@
     return context;
   }
 
+  final String getPrefixForExternalSyntheticType() {
+    return SyntheticNaming.getPrefixForExternalSyntheticType(getKind(), getHolder().getType());
+  }
+
   public abstract C getHolder();
 
   final HashCode computeHash(
       RepresentativeMap map, boolean intermediate, ClassToFeatureSplitMap classToFeatureSplitMap) {
     Hasher hasher = Hashing.murmur3_128().newHasher();
-    if (intermediate || getKind().isFixedSuffixSynthetic) {
+    if (getKind().isFixedSuffixSynthetic) {
+      // Fixed synthetics are non-shareable. Its unique type is used as the hash key.
+      getHolder().getType().hash(hasher);
+      return hasher.hash();
+    }
+    if (intermediate) {
       // If in intermediate mode, include the context type as sharing is restricted to within a
       // single context.
       getContext().getSynthesizingContextType().hashWithTypeEquivalence(hasher, map);
@@ -95,7 +104,13 @@
       boolean includeContext,
       GraphLens graphLens,
       ClassToFeatureSplitMap classToFeatureSplitMap) {
-    if (includeContext || getKind().isFixedSuffixSynthetic) {
+    DexType thisType = getHolder().getType();
+    DexType otherType = other.getHolder().getType();
+    if (getKind().isFixedSuffixSynthetic) {
+      // Fixed synthetics are non-shareable. Ordered by their unique type.
+      return thisType.compareTo(otherType);
+    }
+    if (includeContext) {
       int order = getContext().compareTo(other.getContext());
       if (order != 0) {
         return order;
@@ -113,8 +128,6 @@
         return order;
       }
     }
-    DexType thisType = getHolder().getType();
-    DexType otherType = other.getHolder().getType();
     RepresentativeMap map = null;
     // If the synthetics have been moved include the original types in the equivalence.
     if (graphLens.isNonIdentityLens()) {
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 741831e..60dca8f 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java
@@ -265,7 +265,7 @@
         ImmutableMap.builder();
     List<DexProgramClass> finalSyntheticProgramDefinitions = new ArrayList<>();
     {
-      Map<DexType, NumberGenerator> generators = new IdentityHashMap<>();
+      Map<String, NumberGenerator> generators = new HashMap<>();
       application =
           buildLensAndProgram(
               appView,
@@ -317,7 +317,7 @@
       Map<DexType, EquivalenceGroup<D>> computeEquivalences(
           AppView<?> appView,
           ImmutableCollection<R> references,
-          Map<DexType, NumberGenerator> generators) {
+          Map<String, NumberGenerator> generators) {
     boolean intermediate = appView.options().intermediate;
     Map<DexType, D> definitions = lookupDefinitions(appView, references);
     ClassToFeatureSplitMap classToFeatureSplitMap =
@@ -662,11 +662,11 @@
   private <T extends SyntheticDefinition<?, T, ?>>
       Map<DexType, EquivalenceGroup<T>> computeActualEquivalences(
           Collection<List<T>> potentialEquivalences,
-          Map<DexType, NumberGenerator> generators,
+          Map<String, NumberGenerator> generators,
           AppView<?> appView,
           boolean intermediate,
           ClassToFeatureSplitMap classToFeatureSplitMap) {
-    Map<DexType, List<EquivalenceGroup<T>>> groupsPerContext = new IdentityHashMap<>();
+    Map<String, List<EquivalenceGroup<T>>> groupsPerPrefix = new HashMap<>();
     potentialEquivalences.forEach(
         members -> {
           List<List<T>> groups =
@@ -677,17 +677,16 @@
             // The representative is required to be the first element of the group.
             group.remove(representative);
             group.add(0, representative);
-            groupsPerContext
+            groupsPerPrefix
                 .computeIfAbsent(
-                    representative.getContext().getSynthesizingContextType(),
-                    k -> new ArrayList<>())
+                    representative.getPrefixForExternalSyntheticType(), k -> new ArrayList<>())
                 .add(new EquivalenceGroup<>(representative, group));
           }
         });
 
     Map<DexType, EquivalenceGroup<T>> equivalences = new IdentityHashMap<>();
-    groupsPerContext.forEach(
-        (context, groups) -> {
+    groupsPerPrefix.forEach(
+        (externalSyntheticTypePrefix, groups) -> {
           // Sort the equivalence groups that go into 'context' including the context type of the
           // representative which is equal to 'context' here (see assert below).
           groups.sort(
@@ -695,14 +694,18 @@
                   a.compareToIncludingContext(b, appView.graphLens(), classToFeatureSplitMap));
           for (int i = 0; i < groups.size(); i++) {
             EquivalenceGroup<T> group = groups.get(i);
-            assert group.getRepresentative().getContext().getSynthesizingContextType() == context;
+            assert group
+                .getRepresentative()
+                .getPrefixForExternalSyntheticType()
+                .equals(externalSyntheticTypePrefix);
             // Two equivalence groups in same context type must be distinct otherwise the assignment
             // of the synthetic name will be non-deterministic between the two.
             assert i == 0
                 || checkGroupsAreDistinct(
                     groups.get(i - 1), group, appView.graphLens(), classToFeatureSplitMap);
             SyntheticKind kind = group.members.get(0).getKind();
-            DexType representativeType = createExternalType(kind, context, generators, appView);
+            DexType representativeType =
+                createExternalType(kind, externalSyntheticTypePrefix, generators, appView);
             equivalences.put(representativeType, group);
           }
         });
@@ -752,7 +755,7 @@
     T smallest = members.get(0);
     for (int i = 1; i < members.size(); i++) {
       T next = members.get(i);
-      if (next.compareTo(smallest, true, graphLens, classToFeatureSplitMap) < 0) {
+      if (next.toReference().getReference().compareTo(smallest.toReference().getReference()) < 0) {
         smallest = next;
       }
     }
@@ -761,20 +764,20 @@
 
   private DexType createExternalType(
       SyntheticKind kind,
-      DexType representativeContext,
-      Map<DexType, NumberGenerator> generators,
+      String externalSyntheticTypePrefix,
+      Map<String, NumberGenerator> generators,
       AppView<?> appView) {
     DexItemFactory factory = appView.dexItemFactory();
     if (kind.isFixedSuffixSynthetic) {
-      return SyntheticNaming.createExternalType(kind, representativeContext, "", factory);
+      return SyntheticNaming.createExternalType(kind, externalSyntheticTypePrefix, "", factory);
     }
     NumberGenerator generator =
-        generators.computeIfAbsent(representativeContext, k -> new NumberGenerator());
+        generators.computeIfAbsent(externalSyntheticTypePrefix, k -> new NumberGenerator());
     DexType externalType;
     do {
       externalType =
           SyntheticNaming.createExternalType(
-              kind, representativeContext, Integer.toString(generator.next()), factory);
+              kind, externalSyntheticTypePrefix, Integer.toString(generator.next()), factory);
       DexClass clazz = appView.appInfo().definitionForWithoutExistenceAssert(externalType);
       if (clazz != null && isNotSyntheticType(clazz.type)) {
         assert options.testing.allowConflictingSyntheticTypes
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
index 73b61b3..8263f40 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
@@ -217,9 +217,14 @@
 
   // TODO(b/180091213): Implement this and remove client provided the oracle.
   public Set<DexReference> getSynthesizingContexts(
-      DexProgramClass clazz, Function<DexProgramClass, Set<DexReference>> oracle) {
+      DexProgramClass clazz, SynthesizingContextOracle oracle) {
     assert isSyntheticClass(clazz);
-    return oracle.apply(clazz);
+    return oracle.getSynthesizingContexts(clazz);
+  }
+
+  public interface SynthesizingContextOracle {
+
+    Set<DexReference> getSynthesizingContexts(DexProgramClass clazz);
   }
 
   // The compiler should not inspect the kind of a synthetic, so this provided only as a assertion
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodReference.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodReference.java
index 930443a..fd63ea2 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodReference.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodReference.java
@@ -34,6 +34,11 @@
   }
 
   @Override
+  DexMethod getReference() {
+    return method;
+  }
+
+  @Override
   SyntheticMethodDefinition lookupDefinition(Function<DexType, DexClass> definitions) {
     DexClass clazz = definitions.apply(method.holder);
     if (clazz == null) {
@@ -47,7 +52,8 @@
   }
 
   @Override
-  SyntheticMethodReference rewrite(NonIdentityGraphLens lens) {
+  SyntheticMethodReference internalRewrite(
+      SynthesizingContext rewrittenContext, NonIdentityGraphLens lens) {
     DexMethod rewritten = lens.lookupMethod(method);
     // If the reference has been non-trivially rewritten the compiler has changed it and it can no
     // longer be considered a synthetic. The context may or may not have changed.
@@ -58,20 +64,10 @@
       assert SyntheticNaming.verifyNotInternalSynthetic(rewritten.holder);
       return null;
     }
-    SynthesizingContext context = getContext().rewrite(lens);
-    if (context == getContext() && rewritten == method) {
+    if (rewrittenContext == getContext() && rewritten == method) {
       return this;
     }
-    // Ensure that if a synthetic moves its context moves consistently.
-    if (method != rewritten) {
-      context =
-          SynthesizingContext.fromSyntheticContextChange(
-              getKind(), rewritten.holder, context, lens.dexItemFactory());
-      if (context == null) {
-        return null;
-      }
-    }
-    return new SyntheticMethodReference(getKind(), context, rewritten);
+    return new SyntheticMethodReference(getKind(), rewrittenContext, rewritten);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java
index 63772a2..25e59ae 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.synthesis;
 
+import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.references.ClassReference;
@@ -62,24 +63,32 @@
     }
   }
 
+  private static final String SYNTHETIC_CLASS_SEPARATOR = "-$$";
   /**
    * The internal synthetic class separator is only used for representing synthetic items during
    * compilation. In particular, this separator must never be used to write synthetic classes to the
    * final compilation result.
    */
-  private static final String INTERNAL_SYNTHETIC_CLASS_SEPARATOR = "-$$InternalSynthetic";
+  private static final String INTERNAL_SYNTHETIC_CLASS_SEPARATOR =
+      SYNTHETIC_CLASS_SEPARATOR + "InternalSynthetic";
   /**
    * The external synthetic class separator is used when writing classes. It may appear in types
    * during compilation as the output of a compilation may be the input to another.
    */
-  private static final String EXTERNAL_SYNTHETIC_CLASS_SEPARATOR = "-$$ExternalSynthetic";
+  private static final String EXTERNAL_SYNTHETIC_CLASS_SEPARATOR =
+      SYNTHETIC_CLASS_SEPARATOR + "ExternalSynthetic";
   /** Method prefix when generating synthetic methods in a class. */
   static final String INTERNAL_SYNTHETIC_METHOD_PREFIX = "m";
 
-  // TODO(b/158159959): Remove usage of name-based identification.
-  public static boolean isSyntheticName(String typeName) {
-    return typeName.contains(INTERNAL_SYNTHETIC_CLASS_SEPARATOR)
-        || typeName.contains(EXTERNAL_SYNTHETIC_CLASS_SEPARATOR);
+  static String getPrefixForExternalSyntheticType(SyntheticKind kind, DexType type) {
+    String binaryName = type.toBinaryName();
+    int index =
+        binaryName.lastIndexOf(
+            kind.isFixedSuffixSynthetic ? kind.descriptor : SYNTHETIC_CLASS_SEPARATOR);
+    if (index < 0) {
+      throw new Unreachable("Unexpected failure to compute an synthetic prefix");
+    }
+    return binaryName.substring(0, index);
   }
 
   public static DexType createFixedType(
@@ -100,12 +109,12 @@
   }
 
   static DexType createExternalType(
-      SyntheticKind kind, DexType context, String id, DexItemFactory factory) {
+      SyntheticKind kind, String externalSyntheticTypePrefix, String id, DexItemFactory factory) {
     assert kind.isFixedSuffixSynthetic == id.isEmpty();
     return createType(
         kind.isFixedSuffixSynthetic ? "" : EXTERNAL_SYNTHETIC_CLASS_SEPARATOR,
         kind,
-        context,
+        externalSyntheticTypePrefix,
         id,
         factory);
   }
@@ -115,10 +124,19 @@
     return factory.createType(createDescriptor(separator, kind, context.getInternalName(), id));
   }
 
+  private static DexType createType(
+      String separator,
+      SyntheticKind kind,
+      String externalSyntheticTypePrefix,
+      String id,
+      DexItemFactory factory) {
+    return factory.createType(createDescriptor(separator, kind, externalSyntheticTypePrefix, id));
+  }
+
   private static String createDescriptor(
-      String separator, SyntheticKind kind, String context, String id) {
+      String separator, SyntheticKind kind, String externalSyntheticTypePrefix, String id) {
     return DescriptorUtils.getDescriptorFromClassBinaryName(
-        context + separator + kind.descriptor + id);
+        externalSyntheticTypePrefix + separator + kind.descriptor + id);
   }
 
   public static boolean verifyNotInternalSynthetic(DexType type) {
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticProgramClassReference.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticProgramClassReference.java
index 7e798e0..5a17b04 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticProgramClassReference.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticProgramClassReference.java
@@ -36,7 +36,8 @@
   }
 
   @Override
-  SyntheticProgramClassReference rewrite(NonIdentityGraphLens lens) {
+  SyntheticProgramClassReference internalRewrite(
+      SynthesizingContext rewrittenContext, NonIdentityGraphLens lens) {
     DexType rewritten = lens.lookupType(type);
     // If the reference has been non-trivially rewritten the compiler has changed it and it can no
     // longer be considered a synthetic. The context may or may not have changed.
@@ -46,20 +47,10 @@
       assert SyntheticNaming.verifyNotInternalSynthetic(rewritten);
       return null;
     }
-    SynthesizingContext context = getContext().rewrite(lens);
-    if (context == getContext() && rewritten == type) {
+    if (rewrittenContext == getContext() && rewritten == type) {
       return this;
     }
-    // Ensure that if a synthetic moves its context moves consistently.
-    if (type != rewritten) {
-      context =
-          SynthesizingContext.fromSyntheticContextChange(
-              getKind(), rewritten, context, lens.dexItemFactory());
-      if (context == null) {
-        return null;
-      }
-    }
-    return new SyntheticProgramClassReference(getKind(), context, rewritten);
+    return new SyntheticProgramClassReference(getKind(), rewrittenContext, rewritten);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticReference.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticReference.java
index 1a2d2fb..ddb28f7 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticReference.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticReference.java
@@ -4,6 +4,7 @@
 package com.android.tools.r8.synthesis;
 
 import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexReference;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens;
 import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
@@ -20,13 +21,13 @@
     C extends DexClass> {
 
   private final SyntheticKind kind;
-  private final SynthesizingContext context;
+  private final SynthesizingContext rewrittenContext;
 
   SyntheticReference(SyntheticKind kind, SynthesizingContext context) {
     assert kind != null;
     assert context != null;
     this.kind = kind;
-    this.context = context;
+    this.rewrittenContext = context;
   }
 
   abstract D lookupDefinition(Function<DexType, DexClass> definitions);
@@ -36,10 +37,17 @@
   }
 
   final SynthesizingContext getContext() {
-    return context;
+    return rewrittenContext;
   }
 
   abstract DexType getHolder();
 
-  abstract R rewrite(NonIdentityGraphLens lens);
+  abstract DexReference getReference();
+
+  final R rewrite(NonIdentityGraphLens lens) {
+    SynthesizingContext rewrittenContext = getContext().rewrite(lens);
+    return internalRewrite(rewrittenContext, lens);
+  }
+
+  abstract R internalRewrite(SynthesizingContext rewrittenContext, NonIdentityGraphLens lens);
 }
diff --git a/src/main/java/com/android/tools/r8/utils/Box.java b/src/main/java/com/android/tools/r8/utils/Box.java
index 77be1c9..de67cf6 100644
--- a/src/main/java/com/android/tools/r8/utils/Box.java
+++ b/src/main/java/com/android/tools/r8/utils/Box.java
@@ -4,6 +4,8 @@
 
 package com.android.tools.r8.utils;
 
+import java.util.Comparator;
+import java.util.Objects;
 import java.util.function.Supplier;
 
 public class Box<T> {
@@ -31,6 +33,12 @@
     this.value = value;
   }
 
+  public void setMin(T element, Comparator<T> comparator) {
+    if (!isSet() || comparator.compare(element, get()) < 0) {
+      set(element);
+    }
+  }
+
   public boolean isSet() {
     return value != null;
   }
@@ -40,4 +48,18 @@
     value = newValue;
     return oldValue;
   }
+
+  @Override
+  public boolean equals(Object object) {
+    if (object == null || getClass() != object.getClass()) {
+      return false;
+    }
+    Box<?> box = (Box<?>) object;
+    return Objects.equals(value, box.value);
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hashCode(value);
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/utils/ClassReferenceUtils.java b/src/main/java/com/android/tools/r8/utils/ClassReferenceUtils.java
new file mode 100644
index 0000000..171344e
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/ClassReferenceUtils.java
@@ -0,0 +1,22 @@
+// 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.utils;
+
+import com.android.tools.r8.references.ClassReference;
+import java.util.Comparator;
+
+public class ClassReferenceUtils {
+
+  private static final Comparator<ClassReference> COMPARATOR =
+      Comparator.comparing(ClassReference::getDescriptor);
+
+  public static int compare(ClassReference classReference, ClassReference other) {
+    return getClassReferenceComparator().compare(classReference, other);
+  }
+
+  public static Comparator<ClassReference> getClassReferenceComparator() {
+    return COMPARATOR;
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/utils/CompareResult.java b/src/main/java/com/android/tools/r8/utils/CompareResult.java
new file mode 100644
index 0000000..a3a04a1
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/CompareResult.java
@@ -0,0 +1,42 @@
+// Copyright (c) 2021, 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.utils;
+
+import java.util.Comparator;
+
+public enum CompareResult {
+  LESS_THAN(-1),
+  EQUAL(0),
+  GREATER_THAN(1);
+
+  private int comparisonResult;
+
+  CompareResult(int comparisonResult) {
+    this.comparisonResult = comparisonResult;
+  }
+
+  public int getComparisonResult() {
+    return comparisonResult;
+  }
+
+  public boolean isEqual() {
+    return this == EQUAL;
+  }
+
+  public static <T extends Comparable<T>> CompareResult compare(T element, T other) {
+    return fromComparisonResult(element.compareTo(other));
+  }
+
+  public static <T> CompareResult compare(T element, T other, Comparator<T> comparator) {
+    return fromComparisonResult(comparator.compare(element, other));
+  }
+
+  public static CompareResult fromComparisonResult(int comparisonResult) {
+    if (comparisonResult < 0) {
+      return CompareResult.LESS_THAN;
+    }
+    return comparisonResult == 0 ? CompareResult.EQUAL : CompareResult.GREATER_THAN;
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/utils/FieldReferenceUtils.java b/src/main/java/com/android/tools/r8/utils/FieldReferenceUtils.java
index cb26884..ebf7821 100644
--- a/src/main/java/com/android/tools/r8/utils/FieldReferenceUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/FieldReferenceUtils.java
@@ -4,10 +4,47 @@
 
 package com.android.tools.r8.utils;
 
+import static com.android.tools.r8.utils.ClassReferenceUtils.getClassReferenceComparator;
+import static com.android.tools.r8.utils.TypeReferenceUtils.getTypeReferenceComparator;
+
 import com.android.tools.r8.references.FieldReference;
+import com.android.tools.r8.references.Reference;
+import java.util.Comparator;
 
 public class FieldReferenceUtils {
 
+  private static final Comparator<FieldReference> COMPARATOR =
+      (field, other) -> {
+        CompareResult holderClassCompareResult =
+            CompareResult.compare(
+                field.getHolderClass(), other.getHolderClass(), getClassReferenceComparator());
+        if (!holderClassCompareResult.isEqual()) {
+          return holderClassCompareResult.getComparisonResult();
+        }
+        CompareResult fieldNameCompareResult =
+            CompareResult.compare(field.getFieldName(), other.getFieldName());
+        if (!fieldNameCompareResult.isEqual()) {
+          return fieldNameCompareResult.getComparisonResult();
+        }
+        return getTypeReferenceComparator().compare(field.getFieldType(), other.getFieldType());
+      };
+
+  public static int compare(FieldReference fieldReference, FieldReference other) {
+    return getFieldReferenceComparator().compare(fieldReference, other);
+  }
+
+  public static FieldReference fieldFromField(Class<?> clazz, String name) {
+    try {
+      return Reference.fieldFromField(clazz.getDeclaredField(name));
+    } catch (NoSuchFieldException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  public static Comparator<FieldReference> getFieldReferenceComparator() {
+    return COMPARATOR;
+  }
+
   public static String toSourceString(FieldReference fieldReference) {
     return fieldReference.getFieldType().getTypeName()
         + " "
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index d515b20..b60a0e3 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -1291,7 +1291,7 @@
     public boolean alwaysUsePessimisticRegisterAllocation = false;
     public boolean enableCheckCastAndInstanceOfRemoval = true;
     public boolean enableDeadSwitchCaseElimination = true;
-    public boolean enableExperimentalMissingClassesReporting = false;
+    public boolean enableExperimentalMissingClassesReporting = true;
     public boolean enableInvokeSuperToInvokeVirtualRewriting = true;
     public boolean enableSwitchToIfRewriting = true;
     public boolean enableEnumUnboxingDebugLogs = false;
@@ -1465,12 +1465,20 @@
     return !isDesugaring() || hasMinApi(AndroidApiLevel.K);
   }
 
+  public boolean enableBackportedMethodRewriting() {
+    // Disable rewriting if there are no methods to rewrite or if the API level is higher than
+    // the highest known API level when the compiler is built. This ensures that when this is used
+    // by the Android Platform build (which normally use an API level of 10000) there will be
+    // no rewriting of backported methods. See b/147480264.
+    return desugarState.isOn() && minApiLevel <= AndroidApiLevel.LATEST.getLevel();
+  }
+
   public boolean enableTryWithResourcesDesugaring() {
     switch (tryWithResourcesDesugaring) {
       case Off:
         return false;
       case Auto:
-        return !canUseSuppressedExceptions();
+        return desugarState.isOn() && !canUseTwrCloseResourceMethod();
     }
     throw new Unreachable();
   }
@@ -1508,7 +1516,7 @@
   }
 
   public boolean canUseJavaUtilObjects() {
-    return (isGeneratingClassFiles() && !cfToCfDesugar) || hasMinApi(AndroidApiLevel.K);
+    return !isDesugaring() || hasMinApi(AndroidApiLevel.K);
   }
 
   public boolean canUseRequireNonNull() {
@@ -1516,11 +1524,11 @@
   }
 
   public boolean canUseSuppressedExceptions() {
-    return (isGeneratingClassFiles() && !cfToCfDesugar) || hasMinApi(AndroidApiLevel.K);
+    return !isDesugaring() || hasMinApi(AndroidApiLevel.K);
   }
 
   public boolean canUseAssertionErrorTwoArgumentConstructor() {
-    return (isGeneratingClassFiles() && !cfToCfDesugar) || hasMinApi(AndroidApiLevel.K);
+    return !isDesugaring() || hasMinApi(AndroidApiLevel.K);
   }
 
   public CfVersion classFileVersionAfterDesugaring(CfVersion version) {
@@ -1539,7 +1547,7 @@
   //
   // https://android.googlesource.com/platform/libcore/+/refs/heads/ics-mr1/luni/src/main/java/java/lang/AssertionError.java#56
   public boolean canInitCauseAfterAssertionErrorObjectConstructor() {
-    return (isGeneratingClassFiles() && !cfToCfDesugar) || hasMinApi(AndroidApiLevel.J);
+    return !isDesugaring() || hasMinApi(AndroidApiLevel.J);
   }
 
   // Dalvik x86-atom backend had a bug that made it crash on filled-new-array instructions for
diff --git a/src/main/java/com/android/tools/r8/utils/IteratorUtils.java b/src/main/java/com/android/tools/r8/utils/IteratorUtils.java
index 35f950a..93b7e4a 100644
--- a/src/main/java/com/android/tools/r8/utils/IteratorUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/IteratorUtils.java
@@ -16,6 +16,12 @@
 
 public class IteratorUtils {
 
+  public static <T> int countRemaining(Iterator<T> iterator) {
+    IntBox counter = new IntBox();
+    iterator.forEachRemaining(ignore -> counter.increment());
+    return counter.get();
+  }
+
   public static <T, S extends T> Iterator<S> filter(
       Iterator<? extends T> iterator, Predicate<T> predicate) {
     return new Iterator<S>() {
diff --git a/src/main/java/com/android/tools/r8/utils/MethodReferenceUtils.java b/src/main/java/com/android/tools/r8/utils/MethodReferenceUtils.java
index e76f21a..4d36fb9 100644
--- a/src/main/java/com/android/tools/r8/utils/MethodReferenceUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/MethodReferenceUtils.java
@@ -4,21 +4,80 @@
 
 package com.android.tools.r8.utils;
 
+import static com.android.tools.r8.utils.ClassReferenceUtils.getClassReferenceComparator;
+import static com.android.tools.r8.utils.TypeReferenceUtils.getTypeReferenceComparator;
+
 import com.android.tools.r8.references.ArrayReference;
 import com.android.tools.r8.references.ClassReference;
 import com.android.tools.r8.references.MethodReference;
 import com.android.tools.r8.references.Reference;
 import com.android.tools.r8.references.TypeReference;
 import com.google.common.collect.ImmutableList;
+import java.util.Comparator;
 import java.util.Iterator;
 
 public class MethodReferenceUtils {
 
+  private static final Comparator<MethodReference> COMPARATOR =
+      (method, other) -> {
+        CompareResult holderClassCompareResult =
+            CompareResult.compare(
+                method.getHolderClass(), other.getHolderClass(), getClassReferenceComparator());
+        if (!holderClassCompareResult.isEqual()) {
+          return holderClassCompareResult.getComparisonResult();
+        }
+        CompareResult methodNameCompareResult =
+            CompareResult.compare(method.getMethodName(), other.getMethodName());
+        if (!methodNameCompareResult.isEqual()) {
+          return methodNameCompareResult.getComparisonResult();
+        }
+        CompareResult returnTypeCompareResult =
+            CompareResult.compare(
+                method.getReturnType(), other.getReturnType(), getTypeReferenceComparator());
+        if (!returnTypeCompareResult.isEqual()) {
+          return returnTypeCompareResult.getComparisonResult();
+        }
+        for (int i = 0;
+            i < Math.min(method.getFormalTypes().size(), other.getFormalTypes().size());
+            i++) {
+          CompareResult formalTypeCompareResult =
+              CompareResult.compare(
+                  method.getFormalTypes().get(i),
+                  other.getFormalTypes().get(i),
+                  getTypeReferenceComparator());
+          if (!formalTypeCompareResult.isEqual()) {
+            return formalTypeCompareResult.getComparisonResult();
+          }
+        }
+        return method.getFormalTypes().size() - other.getFormalTypes().size();
+      };
+
+  public static int compare(MethodReference methodReference, MethodReference other) {
+    return getMethodReferenceComparator().compare(methodReference, other);
+  }
+
+  public static Comparator<MethodReference> getMethodReferenceComparator() {
+    return COMPARATOR;
+  }
+
+  public static MethodReference mainMethod(Class<?> clazz) {
+    return mainMethod(Reference.classFromClass(clazz));
+  }
+
   public static MethodReference mainMethod(ClassReference type) {
     ArrayReference stringArrayType = Reference.array(Reference.classFromClass(String.class), 1);
     return Reference.method(type, "main", ImmutableList.of(stringArrayType), null);
   }
 
+  public static MethodReference methodFromMethod(
+      Class<?> clazz, String name, Class<?>... parameterTypes) {
+    try {
+      return Reference.methodFromMethod(clazz.getDeclaredMethod(name, parameterTypes));
+    } catch (NoSuchMethodException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
   public static String toSourceStringWithoutHolderAndReturnType(MethodReference methodReference) {
     return toSourceString(methodReference, false, false);
   }
diff --git a/src/main/java/com/android/tools/r8/utils/TypeReferenceUtils.java b/src/main/java/com/android/tools/r8/utils/TypeReferenceUtils.java
new file mode 100644
index 0000000..76e6f33
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/TypeReferenceUtils.java
@@ -0,0 +1,27 @@
+// 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.utils;
+
+import com.android.tools.r8.references.TypeReference;
+import java.util.Comparator;
+
+public class TypeReferenceUtils {
+
+  private static final Comparator<TypeReference> COMPARATOR =
+      (type, other) -> {
+        // Handle null inputs (void).
+        if (type == null) {
+          return -1;
+        }
+        if (other == null) {
+          return 1;
+        }
+        return type.getDescriptor().compareTo(other.getDescriptor());
+      };
+
+  public static Comparator<TypeReference> getTypeReferenceComparator() {
+    return COMPARATOR;
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/utils/WorkList.java b/src/main/java/com/android/tools/r8/utils/WorkList.java
index 8ee6e30..e5fb33f 100644
--- a/src/main/java/com/android/tools/r8/utils/WorkList.java
+++ b/src/main/java/com/android/tools/r8/utils/WorkList.java
@@ -36,6 +36,12 @@
     return workList;
   }
 
+  public static <T> WorkList<T> newIdentityWorkList(T item, Set<T> seen) {
+    WorkList<T> workList = new WorkList<>(seen);
+    workList.addIfNotSeen(item);
+    return workList;
+  }
+
   public static <T> WorkList<T> newIdentityWorkList(Iterable<T> items) {
     WorkList<T> workList = new WorkList<>(EqualityTest.IDENTITY);
     workList.addIfNotSeen(items);
@@ -43,11 +49,11 @@
   }
 
   private WorkList(EqualityTest equalityTest) {
-    if (equalityTest == EqualityTest.HASH) {
-      seen = new HashSet<>();
-    } else {
-      seen = Sets.newIdentityHashSet();
-    }
+    this(equalityTest == EqualityTest.HASH ? new HashSet<>() : Sets.newIdentityHashSet());
+  }
+
+  private WorkList(Set<T> seen) {
+    this.seen = seen;
   }
 
   public void addAllIgnoringSeenSet(Iterable<T> items) {
diff --git a/src/main/java/com/android/tools/r8/utils/collections/IdentityHashSetFromMap.java b/src/main/java/com/android/tools/r8/utils/collections/IdentityHashSetFromMap.java
new file mode 100644
index 0000000..0322582
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/collections/IdentityHashSetFromMap.java
@@ -0,0 +1,115 @@
+// Copyright (c) 2021, 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.utils.collections;
+
+import com.android.tools.r8.graph.ProgramDerivedContext;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.IdentityHashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Function;
+
+public class IdentityHashSetFromMap<K, V> implements Set<V> {
+
+  private final Map<K, V> backing = new IdentityHashMap<>();
+  private final Function<V, K> valueToKeyMapping;
+
+  public IdentityHashSetFromMap(Function<V, K> valueToKeyMapping) {
+    this.valueToKeyMapping = valueToKeyMapping;
+  }
+
+  public static Set<ProgramDerivedContext> newProgramDerivedContextSet() {
+    return new IdentityHashSetFromMap<>(context -> context.getContext().getReference());
+  }
+
+  @Override
+  public int size() {
+    return backing.size();
+  }
+
+  @Override
+  public boolean isEmpty() {
+    return backing.isEmpty();
+  }
+
+  @SuppressWarnings("unchecked")
+  @Override
+  public boolean contains(Object o) {
+    return backing.containsKey(valueToKeyMapping.apply((V) o));
+  }
+
+  @Override
+  public Iterator<V> iterator() {
+    return backing.values().iterator();
+  }
+
+  @Override
+  public Object[] toArray() {
+    return backing.values().toArray();
+  }
+
+  @Override
+  public <T> T[] toArray(T[] ts) {
+    return backing.values().toArray(ts);
+  }
+
+  @Override
+  public boolean add(V v) {
+    return backing.put(valueToKeyMapping.apply(v), v) == null;
+  }
+
+  @SuppressWarnings("unchecked")
+  @Override
+  public boolean remove(Object o) {
+    return backing.remove(valueToKeyMapping.apply((V) o)) != null;
+  }
+
+  @Override
+  public boolean containsAll(Collection<?> collection) {
+    return backing.values().containsAll(collection);
+  }
+
+  @Override
+  public boolean addAll(Collection<? extends V> collection) {
+    boolean changed = false;
+    for (V element : collection) {
+      changed |= add(element);
+    }
+    return changed;
+  }
+
+  @SuppressWarnings("unchecked")
+  @Override
+  public boolean retainAll(Collection<?> collection) {
+    Collection<Object> found = new ArrayList<>(collection.size());
+    for (Object element : collection) {
+      if (contains(element)) {
+        found.add(element);
+      }
+    }
+    if (found.size() < size()) {
+      clear();
+      addAll((Collection<V>) found);
+      return true;
+    }
+    return false;
+  }
+
+  @Override
+  public boolean removeAll(Collection<?> collection) {
+    boolean changed = false;
+    for (Object element : collection) {
+      changed |= remove(element);
+    }
+    return changed;
+  }
+
+  @Override
+  public void clear() {
+    backing.clear();
+  }
+}
diff --git a/src/main/keep.txt b/src/main/keep.txt
index 24d0fbc..f3e6dd4 100644
--- a/src/main/keep.txt
+++ b/src/main/keep.txt
@@ -28,6 +28,4 @@
 -keep public class com.android.tools.r8.compatproguard.CompatProguard { public static void main(java.lang.String[]); }
 
 # TODO(b/176783536): Avoid need to use -dontwarn.
--dontwarn com.google.errorprone.annotations.**
--dontwarn com.google.j2objc.annotations.*
--dontwarn javax.annotation.Nullable
+-include dontwarn.txt
diff --git a/src/test/examples/staticinlining/AlwaysInline.java b/src/test/examples/staticinlining/AlwaysInline.java
new file mode 100644
index 0000000..2bdb704
--- /dev/null
+++ b/src/test/examples/staticinlining/AlwaysInline.java
@@ -0,0 +1,10 @@
+// Copyright (c) 2017, 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 staticinlining;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+@Target({ElementType.METHOD})
+public @interface AlwaysInline {}
diff --git a/src/test/examples/staticinlining/Sub1.java b/src/test/examples/staticinlining/Sub1.java
index 2e06601..5904684 100644
--- a/src/test/examples/staticinlining/Sub1.java
+++ b/src/test/examples/staticinlining/Sub1.java
@@ -4,8 +4,6 @@
 
 package staticinlining;
 
-import inlining.AlwaysInline;
-
 public class Sub1 extends SuperClass {
 
   @AlwaysInline
diff --git a/src/test/examples/staticinlining/Sub2.java b/src/test/examples/staticinlining/Sub2.java
index e253f79..54528e9 100644
--- a/src/test/examples/staticinlining/Sub2.java
+++ b/src/test/examples/staticinlining/Sub2.java
@@ -18,5 +18,4 @@
     System.out.println("Do not inline me 9");
     System.out.println("Do not inline me 10");
   }
-
 }
diff --git a/src/test/examples/staticinlining/keep-rules.txt b/src/test/examples/staticinlining/keep-rules.txt
index 1de091f..eb98fbe 100644
--- a/src/test/examples/staticinlining/keep-rules.txt
+++ b/src/test/examples/staticinlining/keep-rules.txt
@@ -9,5 +9,5 @@
 }
 
 -alwaysinline class * {
-  @inlining.AlwaysInline <methods>;
+  @staticinlining.AlwaysInline <methods>;
 }
diff --git a/src/test/ignorewarnings.rules b/src/test/ignorewarnings.rules
new file mode 100644
index 0000000..f7766e0
--- /dev/null
+++ b/src/test/ignorewarnings.rules
@@ -0,0 +1 @@
+-ignorewarnings
diff --git a/src/test/java/com/android/tools/r8/JctfTestSpecifications.java b/src/test/java/com/android/tools/r8/JctfTestSpecifications.java
index 899093a..2d21521 100644
--- a/src/test/java/com/android/tools/r8/JctfTestSpecifications.java
+++ b/src/test/java/com/android/tools/r8/JctfTestSpecifications.java
@@ -1831,6 +1831,28 @@
           .put("lang.ref.WeakReference.get.WeakReference_get_A01", cf())
           .build(); // end of flakyWhenRun
 
+  public static final Set<String> hasMissingClasses =
+      ImmutableSet.of(
+          "lang.RuntimePermission.Class.RuntimePermission_class_A01",
+          "lang.RuntimePermission.Class.RuntimePermission_class_A03",
+          "lang.RuntimePermission.Class.RuntimePermission_class_A04",
+          "lang.RuntimePermission.Class.RuntimePermission_class_A05",
+          "lang.RuntimePermission.Class.RuntimePermission_class_A06",
+          "lang.RuntimePermission.Class.RuntimePermission_class_A07",
+          "lang.RuntimePermission.Class.RuntimePermission_class_A08",
+          "lang.RuntimePermission.Class.RuntimePermission_class_A09",
+          "lang.RuntimePermission.Class.RuntimePermission_class_A11",
+          "lang.RuntimePermission.Class.RuntimePermission_class_A12",
+          "lang.RuntimePermission.Class.RuntimePermission_class_A14",
+          "lang.RuntimePermission.Class.RuntimePermission_class_A15",
+          "lang.RuntimePermission.Class.RuntimePermission_class_A19",
+          "lang.RuntimePermission.Class.RuntimePermission_class_A20",
+          "lang.RuntimePermission.Class.RuntimePermission_class_A21",
+          "lang.RuntimePermission.Class.RuntimePermission_class_A22",
+          "lang.RuntimePermission.Class.RuntimePermission_class_A24",
+          "lang.RuntimePermission.Class.RuntimePermission_class_A25",
+          "lang.reflect.Proxy.serialization.Proxy_serialization_A02");
+
   public static final Multimap<String, TestCondition> timeoutsWhenRun =
       new ImmutableListMultimap.Builder<String, TestCondition>()
           .put("lang.Thread.interrupt.Thread_interrupt_A01", anyDexVm())
@@ -1956,7 +1978,7 @@
 
   public static final Set<String> compilationFailsWithAsmMethodTooLarge = ImmutableSet.of();
 
-  private static final boolean testMatch(
+  private static boolean testMatch(
       Multimap<String, TestCondition> testConditions,
       String name,
       CompilerUnderTest compilerUnderTest,
@@ -1971,7 +1993,7 @@
     return false;
   }
 
-  public static final <T> T getExpectedOutcome(
+  public static <T> T getExpectedOutcome(
       String name,
       CompilerUnderTest compilerUnderTest,
       Runtime runtime,
diff --git a/src/test/java/com/android/tools/r8/Jdk11TestUtils.java b/src/test/java/com/android/tools/r8/Jdk11TestUtils.java
new file mode 100644
index 0000000..26da974
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/Jdk11TestUtils.java
@@ -0,0 +1,33 @@
+// Copyright (c) 2021, 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;
+
+import static com.android.tools.r8.TestRuntime.getCheckedInJdk8;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import org.junit.Assume;
+import org.junit.rules.TemporaryFolder;
+
+public class Jdk11TestUtils {
+
+  public static ThrowableConsumer<R8FullTestBuilder> addJdk11LibraryFiles(
+      TemporaryFolder temporaryFolder) {
+    return builder -> builder.addLibraryFiles(getJdk11LibraryFiles(temporaryFolder));
+  }
+
+  public static Path[] getJdk11LibraryFiles(TemporaryFolder temp) throws IOException {
+    Assume.assumeFalse(ToolHelper.isWindows());
+    // TODO(b/180553597): Add JDK-11 runtime jar instead. As a temporary solution we use the JDK-8
+    //  runtime with additional stubs.
+    Path stubs =
+        JavaCompilerTool.create(getCheckedInJdk8(), temp)
+            .addSourceFiles(Paths.get("src", "test", "javaStubs", "StringConcatFactory.java"))
+            .addSourceFiles(Paths.get("src", "test", "javaStubs", "VarHandle.java"))
+            .compile();
+    return new Path[] {stubs, ToolHelper.getJava8RuntimeJar()};
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/Jdk9TestUtils.java b/src/test/java/com/android/tools/r8/Jdk9TestUtils.java
new file mode 100644
index 0000000..891ba09
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/Jdk9TestUtils.java
@@ -0,0 +1,33 @@
+// Copyright (c) 2021, 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;
+
+import static com.android.tools.r8.TestRuntime.getCheckedInJdk8;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import org.junit.Assume;
+import org.junit.rules.TemporaryFolder;
+
+public class Jdk9TestUtils {
+
+  public static ThrowableConsumer<R8FullTestBuilder> addJdk9LibraryFiles(
+      TemporaryFolder temporaryFolder) {
+    return builder -> builder.addLibraryFiles(getJdk9LibraryFiles(temporaryFolder));
+  }
+
+  public static Path[] getJdk9LibraryFiles(TemporaryFolder temp) throws IOException {
+    Assume.assumeFalse(ToolHelper.isWindows());
+    // TODO(b/180553597): Add JDK-9 runtime jar instead. As a temporary solution we use the JDK-8
+    //  runtime with additional stubs.
+    Path stubs =
+        JavaCompilerTool.create(getCheckedInJdk8(), temp)
+            .addSourceFiles(Paths.get("src", "test", "javaStubs", "StringConcatFactory.java"))
+            .addSourceFiles(Paths.get("src", "test", "javaStubs", "VarHandle.java"))
+            .compile();
+    return new Path[] {stubs, ToolHelper.getJava8RuntimeJar()};
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/KotlinCompilerTool.java b/src/test/java/com/android/tools/r8/KotlinCompilerTool.java
index 8e94e5e..f19059b 100644
--- a/src/test/java/com/android/tools/r8/KotlinCompilerTool.java
+++ b/src/test/java/com/android/tools/r8/KotlinCompilerTool.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8;
 
+import static com.android.tools.r8.ToolHelper.getKotlinC_1_4_20;
 import static com.android.tools.r8.ToolHelper.isWindows;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
@@ -60,6 +61,10 @@
       this.name = name;
     }
 
+    public static KotlinCompiler latest() {
+      return getKotlinC_1_4_20();
+    }
+
     public Path getCompiler() {
       return compiler;
     }
diff --git a/src/test/java/com/android/tools/r8/MarkersTest.java b/src/test/java/com/android/tools/r8/MarkersTest.java
index 6e99dc4..bad77b5 100644
--- a/src/test/java/com/android/tools/r8/MarkersTest.java
+++ b/src/test/java/com/android/tools/r8/MarkersTest.java
@@ -45,13 +45,12 @@
         BooleanUtils.values());
   }
 
-  private final TestParameters parameters;
   private final CompilationMode compilationMode;
   private final boolean shrinkDesugaredLibrary;
 
   public MarkersTest(
       TestParameters parameters, CompilationMode compilationMode, boolean shrinkDesugaredLibrary) {
-    this.parameters = parameters;
+    assert parameters.isNoneRuntime();
     this.compilationMode = compilationMode;
     this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
   }
diff --git a/src/test/java/com/android/tools/r8/R8CFRunExamplesJava9Test.java b/src/test/java/com/android/tools/r8/R8CFRunExamplesJava9Test.java
index de47d8a..1d45cb1 100644
--- a/src/test/java/com/android/tools/r8/R8CFRunExamplesJava9Test.java
+++ b/src/test/java/com/android/tools/r8/R8CFRunExamplesJava9Test.java
@@ -50,8 +50,7 @@
       for (UnaryOperator<R8Command.Builder> transformation : builderTransformations) {
         builder = transformation.apply(builder);
       }
-      // TODO(b/124041175): We should not be linking against the Java 8 runtime for Java 9 inputs.
-      builder.addLibraryFiles(ToolHelper.getJava8RuntimeJar());
+      builder.addLibraryFiles(Jdk9TestUtils.getJdk9LibraryFiles(temp));
       R8Command command =
           builder.addProgramFiles(inputFile).setOutput(out, OutputMode.ClassFile).build();
       ToolHelper.runR8(command, this::combinedOptionConsumer);
diff --git a/src/test/java/com/android/tools/r8/R8IgnoreMissingClassesTest.java b/src/test/java/com/android/tools/r8/R8IgnoreMissingClassesTest.java
index 83bc302..5a510c0 100644
--- a/src/test/java/com/android/tools/r8/R8IgnoreMissingClassesTest.java
+++ b/src/test/java/com/android/tools/r8/R8IgnoreMissingClassesTest.java
@@ -19,6 +19,7 @@
   private R8Command.Builder config() {
     return R8Command.builder()
         .addProgramFiles(EXAMPLE)
+        .setDisableTreeShaking(true)
         .setMinApiLevel(MIN_API.getLevel())
         .setProgramConsumer(DexIndexedConsumer.emptyConsumer());
   }
diff --git a/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java b/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
index f3cbda6..4b095bb 100644
--- a/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
@@ -1195,17 +1195,38 @@
       "435-new-instance"
   );
 
-  private static List<String> hasMissingClasses = ImmutableList.of(
-      "091-override-package-private-method",
-      "003-omnibus-opcodes",
-      "608-checker-unresolved-lse",
-      "529-checker-unresolved",
-      "803-no-super",
-      "127-checker-secondarydex",
-      "952-invoke-custom-kinds",
-      // Depends on java.lang.invoke.Transformers, which is hidden.
-      "958-methodhandle-stackframe"
-  );
+  private static List<String> hasMissingClasses =
+      ImmutableList.of(
+          "003-omnibus-opcodes",
+          "004-UnsafeTest",
+          "004-checker-UnsafeTest18",
+          "005-annotations",
+          "067-preemptive-unpark",
+          "071-dexfile-map-clean",
+          "091-override-package-private-method",
+          "111-unresolvable-exception",
+          "124-missing-classes",
+          "127-checker-secondarydex",
+          "138-duplicate-classes-check2",
+          "140-field-packing",
+          "143-string-value",
+          "151-OpenFileLimit",
+          "435-new-instance",
+          "528-long-hint",
+          "529-checker-unresolved",
+          "555-UnsafeGetLong-regression",
+          "585-inline-unresolved",
+          "606-erroneous-class",
+          "608-checker-unresolved-lse",
+          "659-unpadded-array",
+          "706-checker-scheduler",
+          "709-checker-varhandles",
+          "803-no-super",
+          "912-classes",
+          "952-invoke-custom-kinds",
+          // Depends on java.lang.invoke.Transformers, which is hidden.
+          "958-methodhandle-stackframe",
+          "1338-gc-no-los");
 
   private static Map<String, List<String>> keepRules =
       ImmutableMap.of(
@@ -1352,6 +1373,7 @@
         boolean skipRun,
         boolean failsOnRun,
         boolean disableInlining,
+        boolean hasMissingClasses,
         DexVm dexVm) {
       this(
           name,
@@ -1368,7 +1390,7 @@
           false,
           disableInlining,
           true, // Disable class inlining for JCTF tests.
-          false,
+          hasMissingClasses,
           true, // Disable desugaring for JCTF tests.
           ImmutableList.of(),
           null);
@@ -1380,7 +1402,8 @@
         File directory,
         boolean skipRun,
         boolean failsOnRun,
-        boolean disableInlining) {
+        boolean disableInlining,
+        boolean hasMissingClasses) {
       this(
           name,
           dexTool,
@@ -1396,7 +1419,7 @@
           false,
           disableInlining,
           true, // Disable class inlining for JCTF tests.
-          false,
+          hasMissingClasses,
           true, // Disable desugaring for JCTF tests.
           ImmutableList.of(),
           null);
@@ -1917,6 +1940,7 @@
                 || outcome == JctfTestSpecifications.Outcome.FLAKY_WHEN_RUN,
             outcome == JctfTestSpecifications.Outcome.FAILS_WHEN_RUN,
             noInlining,
+            JctfTestSpecifications.hasMissingClasses.contains(name),
             dexVm);
   }
 
@@ -1930,7 +1954,8 @@
             outcome == JctfTestSpecifications.Outcome.TIMEOUTS_WHEN_RUN
                 || outcome == JctfTestSpecifications.Outcome.FLAKY_WHEN_RUN,
             outcome == JctfTestSpecifications.Outcome.FAILS_WHEN_RUN,
-            noInlining);
+            noInlining,
+            JctfTestSpecifications.hasMissingClasses.contains(name));
   }
 
   private static Runtime getRuntime(TestRuntime vm) {
diff --git a/src/test/java/com/android/tools/r8/R8RunExamplesCommon.java b/src/test/java/com/android/tools/r8/R8RunExamplesCommon.java
index e13ddd2..b247acf 100644
--- a/src/test/java/com/android/tools/r8/R8RunExamplesCommon.java
+++ b/src/test/java/com/android/tools/r8/R8RunExamplesCommon.java
@@ -103,7 +103,7 @@
     }
   }
 
-  private R8Command.Builder addInputFile(R8Command.Builder builder) {
+  public R8Command.Builder addInputFile(R8Command.Builder builder) {
     if (input == Input.DX) {
       // If input is DEX code, use the tool helper to add the DEX sources as R8 disallows them.
       ToolHelper.getAppBuilder(builder).addProgramFiles(getOriginalDexFile());
@@ -151,7 +151,7 @@
                   .addLibraryFiles(
                       output == Output.CF
                           ? ToolHelper.getJava8RuntimeJar()
-                          : ToolHelper.getDefaultAndroidJar())
+                          : ToolHelper.getMostRecentAndroidJar())
                   .setOutput(getOutputFile(), outputMode)
                   .setMode(mode)
                   .setDisableTreeShaking(true)
diff --git a/src/test/java/com/android/tools/r8/R8RunExamplesJava9Test.java b/src/test/java/com/android/tools/r8/R8RunExamplesJava9Test.java
index 11035f5..7c3a605 100644
--- a/src/test/java/com/android/tools/r8/R8RunExamplesJava9Test.java
+++ b/src/test/java/com/android/tools/r8/R8RunExamplesJava9Test.java
@@ -9,6 +9,7 @@
 import com.google.common.collect.ImmutableList;
 import java.nio.file.Path;
 import java.util.function.UnaryOperator;
+import org.junit.Test;
 
 public class R8RunExamplesJava9Test extends RunExamplesJava9Test<R8Command.Builder> {
 
@@ -55,4 +56,16 @@
   R8TestRunner test(String testName, String packageName, String mainClass) {
     return new R8TestRunner(testName, packageName, mainClass);
   }
+
+  @Test
+  public void varHandle() throws Throwable {
+    test("varhandle", "varhandle", "VarHandleTests")
+        .withBuilderTransformation(
+            builder ->
+                builder.addProguardConfiguration(
+                    ImmutableList.of("-dontwarn java.lang.invoke.VarHandle"), Origin.unknown()))
+        .withMinApiLevel(AndroidApiLevel.P.getLevel())
+        .withKeepAll()
+        .run();
+  }
 }
diff --git a/src/test/java/com/android/tools/r8/R8RunExamplesKotlinTest.java b/src/test/java/com/android/tools/r8/R8RunExamplesKotlinTest.java
index 0690fa9..74dfeb4 100644
--- a/src/test/java/com/android/tools/r8/R8RunExamplesKotlinTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunExamplesKotlinTest.java
@@ -3,6 +3,8 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8;
 
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.R8Command.Builder;
 import com.android.tools.r8.R8RunArtTestsTest.CompilerUnderTest;
 import com.android.tools.r8.utils.InternalOptions;
 import java.util.ArrayList;
@@ -21,10 +23,6 @@
   @Override
   protected void configure(InternalOptions options) {
     super.configure(options);
-    if (output == Output.CF) {
-      // Class inliner is not supported with CF backend yet.
-      options.enableClassInlining = false;
-    }
   }
 
   @Parameters(name = "{0}_{1}_{2}_{3}_{5}_{6}")
@@ -50,6 +48,12 @@
   }
 
   @Override
+  public Builder addInputFile(Builder builder) {
+    return super.addInputFile(builder)
+        .addProgramFiles(ToolHelper.getKotlinAnnotationJar(KotlinCompiler.latest()));
+  }
+
+  @Override
   protected String getExampleDir() {
     return ToolHelper.EXAMPLES_KOTLIN_BUILD_DIR;
   }
diff --git a/src/test/java/com/android/tools/r8/R8RunExamplesTest.java b/src/test/java/com/android/tools/r8/R8RunExamplesTest.java
index 04ff03f..d8a62da 100644
--- a/src/test/java/com/android/tools/r8/R8RunExamplesTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunExamplesTest.java
@@ -160,9 +160,6 @@
   @Override
   protected Set<String> getFailingCompileDxToDex() {
     return new ImmutableSet.Builder<String>()
-        .add("regress_72361252.Test") // requires desugar
-        .add("regress_70703087.Test") // requires desugar
-        .add("regress_70737019.Test") // requires desugar
         .build();
   }
 
diff --git a/src/test/java/com/android/tools/r8/R8TestCompileResult.java b/src/test/java/com/android/tools/r8/R8TestCompileResult.java
index c9834f8..a1a5f88 100644
--- a/src/test/java/com/android/tools/r8/R8TestCompileResult.java
+++ b/src/test/java/com/android/tools/r8/R8TestCompileResult.java
@@ -179,6 +179,12 @@
     return proguardMap;
   }
 
+  public R8TestCompileResult inspectProguardMap(ThrowableConsumer<String> consumer)
+      throws Throwable {
+    consumer.accept(getProguardMap());
+    return this;
+  }
+
   public Path writeProguardMap() throws IOException {
     Path file = state.getNewTempFolder().resolve("out.zip");
     writeProguardMap(file);
diff --git a/src/test/java/com/android/tools/r8/RunExamplesAndroidOTest.java b/src/test/java/com/android/tools/r8/RunExamplesAndroidOTest.java
index b7bb5d2..2773cf1 100644
--- a/src/test/java/com/android/tools/r8/RunExamplesAndroidOTest.java
+++ b/src/test/java/com/android/tools/r8/RunExamplesAndroidOTest.java
@@ -7,6 +7,7 @@
 import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
 import static com.android.tools.r8.utils.FileUtils.ZIP_EXTENSION;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
 
 import com.android.tools.r8.ToolHelper.DexVm;
@@ -426,10 +427,9 @@
 
   @Test
   public void repeatAnnotations() throws Throwable {
-    // No need to specify minSdk as repeat annotations are handled by javac and we do not have
-    // to do anything to support them. The library methods to access them just have to be in
-    // the system.
+    // java.lang.annotation.Repeatable is introduced in Android N.
     test("repeat_annotations", "repeat_annotations", "RepeatAnnotations")
+        .withAndroidJar(AndroidApiLevel.N)
         .withKeepAll()
         .run();
   }
@@ -437,6 +437,7 @@
   @Test
   public void testTryWithResources() throws Throwable {
     test("try-with-resources-simplified", "trywithresources", "TryWithResourcesNotDesugaredTests")
+        .withAndroidJar(AndroidApiLevel.K)
         .withTryWithResourcesDesugaring(OffOrAuto.Off)
         .withKeepAll()
         .run();
@@ -445,11 +446,13 @@
   @Test
   public void testTryWithResourcesDesugared() throws Throwable {
     test("try-with-resources-simplified", "trywithresources", "TryWithResourcesDesugaredTests")
+        .withAndroidJar(AndroidApiLevel.K)
         .withTryWithResourcesDesugaring(OffOrAuto.Auto)
-        .withInstructionCheck(InstructionSubject::isInvoke,
+        .withInstructionCheck(
+            InstructionSubject::isInvoke,
             (InvokeInstructionSubject invoke) -> {
-              Assert.assertFalse(invoke.invokedMethod().name.toString().equals("addSuppressed"));
-              Assert.assertFalse(invoke.invokedMethod().name.toString().equals("getSuppressed"));
+              assertNotEquals("addSuppressed", invoke.invokedMethod().name.toString());
+              assertNotEquals("getSuppressed", invoke.invokedMethod().name.toString());
             })
         .withKeepAll()
         .run();
diff --git a/src/test/java/com/android/tools/r8/RunExamplesJava9Test.java b/src/test/java/com/android/tools/r8/RunExamplesJava9Test.java
index 9f20f9e..7f1940e 100644
--- a/src/test/java/com/android/tools/r8/RunExamplesJava9Test.java
+++ b/src/test/java/com/android/tools/r8/RunExamplesJava9Test.java
@@ -48,8 +48,6 @@
     final String mainClass;
     final List<String> args = new ArrayList<>();
 
-    Integer androidJarVersion = null;
-
     final List<Consumer<InternalOptions>> optionConsumers = new ArrayList<>();
     final List<Consumer<CodeInspector>> dexInspectorChecks = new ArrayList<>();
     final List<UnaryOperator<B>> builderTransformations = new ArrayList<>();
@@ -83,14 +81,6 @@
       return self();
     }
 
-    Path build() throws Throwable {
-      Path inputFile = getInputJar();
-      Path out = temp.getRoot().toPath().resolve(testName + ZIP_EXTENSION);
-
-      build(inputFile, out);
-      return out;
-    }
-
     Path getInputJar() {
       return Paths.get(EXAMPLE_DIR, packageName + JAR_EXTENSION);
     }
@@ -126,12 +116,6 @@
       return self();
     }
 
-    C withAndroidJar(int androidJarVersion) {
-      assert this.androidJarVersion == null;
-      this.androidJarVersion = androidJarVersion;
-      return self();
-    }
-
     abstract void build(Path inputFile, Path out) throws Throwable;
   }
 
@@ -274,7 +258,6 @@
     test
         .withMinApiLevel(AndroidApiLevel.I.getLevel())
         .withKeepAll()
-        .withAndroidJar(AndroidApiLevel.K.getLevel())
         .withArg(test.getInputJar().toAbsolutePath().toString())
         .run();
   }
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java
index 1b4ca35..cf27791 100644
--- a/src/test/java/com/android/tools/r8/TestBase.java
+++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8;
 
+import static com.android.tools.r8.TestBuilder.getTestingAnnotations;
 import static com.android.tools.r8.utils.InternalOptions.ASM_VERSION;
 import static com.google.common.collect.Lists.cartesianProduct;
 import static org.junit.Assert.assertEquals;
@@ -39,6 +40,7 @@
 import com.android.tools.r8.graph.SubtypingInfo;
 import com.android.tools.r8.jasmin.JasminBuilder;
 import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.origin.PathOrigin;
 import com.android.tools.r8.references.ClassReference;
 import com.android.tools.r8.references.FieldReference;
 import com.android.tools.r8.references.MethodReference;
@@ -131,6 +133,10 @@
     CF,
     DEX;
 
+    public boolean isCf() {
+      return this == CF;
+    }
+
     public boolean isDex() {
       return this == DEX;
     }
@@ -551,7 +557,7 @@
   }
 
   protected static AndroidApp.Builder buildClasses(Class<?>... programClasses) throws IOException {
-    return buildClasses(Arrays.asList(programClasses), Collections.emptyList());
+    return buildClasses(Arrays.asList(programClasses));
   }
 
   protected static AndroidApp.Builder buildClasses(Collection<Class<?>> programClasses)
@@ -559,6 +565,20 @@
     return buildClasses(programClasses, Collections.emptyList());
   }
 
+  protected static AndroidApp.Builder buildClassesWithTestingAnnotations(Class<?>... programClasses)
+      throws IOException {
+    return buildClassesWithTestingAnnotations(Arrays.asList(programClasses));
+  }
+
+  protected static AndroidApp.Builder buildClassesWithTestingAnnotations(
+      Collection<Class<?>> programClasses) throws IOException {
+    AndroidApp.Builder builder = buildClasses(programClasses, Collections.emptyList());
+    for (Class<?> testingAnnotation : getTestingAnnotations()) {
+      builder.addProgramFile(ToolHelper.getClassFileForTestClass(testingAnnotation));
+    }
+    return builder;
+  }
+
   protected static AndroidApp.Builder buildClasses(
       Collection<Class<?>> programClasses, Collection<Class<?>> libraryClasses) throws IOException {
     AndroidApp.Builder builder = AndroidApp.builder();
@@ -1687,6 +1707,10 @@
     return DescriptorUtils.javaTypeToDescriptor(typeName(clazz));
   }
 
+  public static PathOrigin getOrigin(Class<?> clazz) {
+    return new PathOrigin(ToolHelper.getClassFileForTestClass(clazz));
+  }
+
   public static String typeName(Class<?> clazz) {
     return clazz.getTypeName();
   }
diff --git a/src/test/java/com/android/tools/r8/TestBuilder.java b/src/test/java/com/android/tools/r8/TestBuilder.java
index 3d33673..8f5466c 100644
--- a/src/test/java/com/android/tools/r8/TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestBuilder.java
@@ -166,8 +166,9 @@
     return addLibraryClasses(getTestingAnnotations());
   }
 
-  private List<Class<?>> getTestingAnnotations() {
+  public static List<Class<?>> getTestingAnnotations() {
     return ImmutableList.of(
+        AlwaysInline.class,
         AssumeMayHaveSideEffects.class,
         ForceInline.class,
         KeepConstantArguments.class,
diff --git a/src/test/java/com/android/tools/r8/TestCompileResult.java b/src/test/java/com/android/tools/r8/TestCompileResult.java
index 80f3234..ba56c6f 100644
--- a/src/test/java/com/android/tools/r8/TestCompileResult.java
+++ b/src/test/java/com/android/tools/r8/TestCompileResult.java
@@ -65,6 +65,20 @@
     this.outputMode = outputMode;
   }
 
+  public CR applyIf(boolean condition, ThrowableConsumer<CR> thenConsumer) {
+    return applyIf(condition, thenConsumer, result -> {});
+  }
+
+  public CR applyIf(
+      boolean condition, ThrowableConsumer<CR> thenConsumer, ThrowableConsumer<CR> elseConsumer) {
+    if (condition) {
+      thenConsumer.acceptWithRuntimeException(self());
+    } else {
+      elseConsumer.acceptWithRuntimeException(self());
+    }
+    return self();
+  }
+
   public final CR withArt6Plus64BitsLib() {
     withArt6Plus64BitsLib = true;
     return self();
@@ -75,6 +89,10 @@
     return self();
   }
 
+  public final AndroidApp getApp() {
+    return app;
+  }
+
   public final Backend getBackend() {
     if (outputMode == OutputMode.ClassFile) {
       return Backend.CF;
@@ -362,7 +380,7 @@
   }
 
   public CR assertAllWarningMessagesMatch(Matcher<String> matcher) {
-    getDiagnosticMessages().assertAllWarningsMatch(diagnosticMessage(matcher));
+    getDiagnosticMessages().assertHasWarnings().assertAllWarningsMatch(diagnosticMessage(matcher));
     return self();
   }
 
diff --git a/src/test/java/com/android/tools/r8/TestDiagnosticMessages.java b/src/test/java/com/android/tools/r8/TestDiagnosticMessages.java
index 997faf6..e2ea100 100644
--- a/src/test/java/com/android/tools/r8/TestDiagnosticMessages.java
+++ b/src/test/java/com/android/tools/r8/TestDiagnosticMessages.java
@@ -6,131 +6,176 @@
 
 import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
 import static org.hamcrest.CoreMatchers.not;
+import static org.junit.Assert.assertEquals;
 
+import com.android.tools.r8.diagnosticinspector.DiagnosticSubject;
+import com.android.tools.r8.diagnosticinspector.FoundDiagnosticSubject;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Iterator;
 import java.util.List;
 import org.hamcrest.Matcher;
 
-public interface TestDiagnosticMessages {
+public abstract class TestDiagnosticMessages {
 
-  List<Diagnostic> getInfos();
+  public abstract List<Diagnostic> getInfos();
 
-  List<Diagnostic> getWarnings();
+  public abstract List<Diagnostic> getWarnings();
 
-  default <D extends Diagnostic> D getWarning(int index) {
-    return (D) getWarnings().get(index);
+  public final TestDiagnosticMessages inspectWarning(
+      int index, ThrowableConsumer<DiagnosticSubject> consumer) {
+    consumer.acceptWithRuntimeException(new FoundDiagnosticSubject<>(getWarnings().get(index)));
+    return this;
   }
 
-  List<Diagnostic> getErrors();
-
-  default <D extends Diagnostic> D getError(int index) {
-    return (D) getErrors().get(index);
+  @SafeVarargs
+  public final TestDiagnosticMessages inspectWarnings(
+      ThrowableConsumer<DiagnosticSubject>... consumers) {
+    return inspectWarnings(Arrays.asList(consumers));
   }
 
-  TestDiagnosticMessages assertNoMessages();
+  public final TestDiagnosticMessages inspectWarnings(
+      Collection<ThrowableConsumer<DiagnosticSubject>> consumers) {
+    assertEquals(consumers.size(), getWarnings().size());
+    Iterator<ThrowableConsumer<DiagnosticSubject>> consumerIterator = consumers.iterator();
+    Iterator<Diagnostic> warningIterator = getWarnings().iterator();
+    for (int i = 0; i < consumers.size(); i++) {
+      consumerIterator
+          .next()
+          .acceptWithRuntimeException(new FoundDiagnosticSubject<>(warningIterator.next()));
+    }
+    return this;
+  }
 
-  TestDiagnosticMessages assertOnlyInfos();
+  public abstract List<Diagnostic> getErrors();
 
-  TestDiagnosticMessages assertOnlyWarnings();
+  @SafeVarargs
+  public final TestDiagnosticMessages inspectErrors(
+      ThrowableConsumer<DiagnosticSubject>... consumers) {
+    return inspectErrors(Arrays.asList(consumers));
+  }
 
-  TestDiagnosticMessages assertOnlyErrors();
+  public final TestDiagnosticMessages inspectErrors(
+      Collection<ThrowableConsumer<DiagnosticSubject>> consumers) {
+    assertEquals(consumers.size(), getErrors().size());
+    Iterator<ThrowableConsumer<DiagnosticSubject>> consumerIterator = consumers.iterator();
+    Iterator<Diagnostic> errorIterator = getErrors().iterator();
+    for (int i = 0; i < consumers.size(); i++) {
+      consumerIterator
+          .next()
+          .acceptWithRuntimeException(new FoundDiagnosticSubject<>(errorIterator.next()));
+    }
+    return this;
+  }
 
-  TestDiagnosticMessages assertInfosCount(int count);
+  public abstract TestDiagnosticMessages assertNoMessages();
 
-  TestDiagnosticMessages assertWarningsCount(int count);
+  public abstract TestDiagnosticMessages assertHasWarnings();
 
-  TestDiagnosticMessages assertErrorsCount(int count);
+  public abstract TestDiagnosticMessages assertOnlyInfos();
 
-  default TestDiagnosticMessages assertNoInfos() {
+  public abstract TestDiagnosticMessages assertOnlyWarnings();
+
+  public abstract TestDiagnosticMessages assertOnlyErrors();
+
+  public abstract TestDiagnosticMessages assertInfosCount(int count);
+
+  public abstract TestDiagnosticMessages assertWarningsCount(int count);
+
+  public abstract TestDiagnosticMessages assertErrorsCount(int count);
+
+  public final TestDiagnosticMessages assertNoInfos() {
     return assertInfosCount(0);
   }
 
-  default TestDiagnosticMessages assertNoWarnings() {
+  public final TestDiagnosticMessages assertNoWarnings() {
     return assertWarningsCount(0);
   }
 
-  default TestDiagnosticMessages assertNoErrors() {
+  public final TestDiagnosticMessages assertNoErrors() {
     return assertErrorsCount(0);
   }
 
   // Match exact.
 
-  default TestDiagnosticMessages assertDiagnosticsMatch(Matcher<Diagnostic> matcher) {
+  public final TestDiagnosticMessages assertDiagnosticsMatch(Matcher<Diagnostic> matcher) {
     return assertDiagnosticsMatch(Collections.singletonList(matcher));
   }
 
-  TestDiagnosticMessages assertDiagnosticsMatch(Collection<Matcher<Diagnostic>> matchers);
+  public abstract TestDiagnosticMessages assertDiagnosticsMatch(
+      Collection<Matcher<Diagnostic>> matchers);
 
-  default TestDiagnosticMessages assertInfosMatch(Matcher<Diagnostic> matcher) {
+  public final TestDiagnosticMessages assertInfosMatch(Matcher<Diagnostic> matcher) {
     return assertInfosMatch(Collections.singletonList(matcher));
   }
 
-  TestDiagnosticMessages assertInfosMatch(Collection<Matcher<Diagnostic>> matchers);
+  public abstract TestDiagnosticMessages assertInfosMatch(Collection<Matcher<Diagnostic>> matchers);
 
-  default TestDiagnosticMessages assertWarningsMatch(Matcher<Diagnostic> matcher) {
+  public final TestDiagnosticMessages assertWarningsMatch(Matcher<Diagnostic> matcher) {
     return assertWarningsMatch(Collections.singletonList(matcher));
   }
 
-  @SuppressWarnings("unchecked")
-  default TestDiagnosticMessages assertWarningsMatch(Matcher<Diagnostic>... matchers) {
+  @SafeVarargs
+  public final TestDiagnosticMessages assertWarningsMatch(Matcher<Diagnostic>... matchers) {
     return assertWarningsMatch(Arrays.asList(matchers));
   }
 
-  TestDiagnosticMessages assertWarningsMatch(Collection<Matcher<Diagnostic>> matchers);
+  public abstract TestDiagnosticMessages assertWarningsMatch(
+      Collection<Matcher<Diagnostic>> matchers);
 
-  default TestDiagnosticMessages assertErrorsMatch(Matcher<Diagnostic> matcher) {
+  public final TestDiagnosticMessages assertErrorsMatch(Matcher<Diagnostic> matcher) {
     return assertErrorsMatch(Collections.singletonList(matcher));
   }
 
-  TestDiagnosticMessages assertErrorsMatch(Collection<Matcher<Diagnostic>> matchers);
+  public abstract TestDiagnosticMessages assertErrorsMatch(
+      Collection<Matcher<Diagnostic>> matchers);
 
   // Match one.
 
-  TestDiagnosticMessages assertDiagnosticThatMatches(Matcher<Diagnostic> matcher);
+  public abstract TestDiagnosticMessages assertDiagnosticThatMatches(Matcher<Diagnostic> matcher);
 
-  TestDiagnosticMessages assertInfoThatMatches(Matcher<Diagnostic> matcher);
+  public abstract TestDiagnosticMessages assertInfoThatMatches(Matcher<Diagnostic> matcher);
 
-  TestDiagnosticMessages assertWarningThatMatches(Matcher<Diagnostic> matcher);
+  public abstract TestDiagnosticMessages assertWarningThatMatches(Matcher<Diagnostic> matcher);
 
-  TestDiagnosticMessages assertErrorThatMatches(Matcher<Diagnostic> matcher);
+  public abstract TestDiagnosticMessages assertErrorThatMatches(Matcher<Diagnostic> matcher);
 
   // Consider removing this helper.
-  default TestDiagnosticMessages assertWarningMessageThatMatches(Matcher<String> matcher) {
+  public final TestDiagnosticMessages assertWarningMessageThatMatches(Matcher<String> matcher) {
     return assertWarningThatMatches(diagnosticMessage(matcher));
   }
 
   // Consider removing this helper.
-  default TestDiagnosticMessages assertErrorMessageThatMatches(Matcher<String> matcher) {
+  public final TestDiagnosticMessages assertErrorMessageThatMatches(Matcher<String> matcher) {
     return assertErrorThatMatches(diagnosticMessage(matcher));
   }
 
   // Match all.
 
-  TestDiagnosticMessages assertAllDiagnosticsMatch(Matcher<Diagnostic> matcher);
+  public abstract TestDiagnosticMessages assertAllDiagnosticsMatch(Matcher<Diagnostic> matcher);
 
-  TestDiagnosticMessages assertAllInfosMatch(Matcher<Diagnostic> matcher);
+  public abstract TestDiagnosticMessages assertAllInfosMatch(Matcher<Diagnostic> matcher);
 
-  TestDiagnosticMessages assertAllWarningsMatch(Matcher<Diagnostic> matcher);
+  public abstract TestDiagnosticMessages assertAllWarningsMatch(Matcher<Diagnostic> matcher);
 
-  TestDiagnosticMessages assertAllErrorsMatch(Matcher<Diagnostic> matcher);
+  public abstract TestDiagnosticMessages assertAllErrorsMatch(Matcher<Diagnostic> matcher);
 
   // Match none.
 
-  default TestDiagnosticMessages assertNoDiagnosticsMatch(Matcher<Diagnostic> matcher) {
+  public final TestDiagnosticMessages assertNoDiagnosticsMatch(Matcher<Diagnostic> matcher) {
     return assertAllDiagnosticsMatch(not(matcher));
   }
 
-  default TestDiagnosticMessages assertNoInfosMatch(Matcher<Diagnostic> matcher) {
+  public final TestDiagnosticMessages assertNoInfosMatch(Matcher<Diagnostic> matcher) {
     return assertAllInfosMatch(not(matcher));
   }
 
-  default TestDiagnosticMessages assertNoWarningsMatch(Matcher<Diagnostic> matcher) {
+  public final TestDiagnosticMessages assertNoWarningsMatch(Matcher<Diagnostic> matcher) {
     return assertAllWarningsMatch(not(matcher));
   }
 
-  default TestDiagnosticMessages assertNoErrorsMatch(Matcher<Diagnostic> matcher) {
+  public final TestDiagnosticMessages assertNoErrorsMatch(Matcher<Diagnostic> matcher) {
     return assertAllErrorsMatch(not(matcher));
   }
 }
diff --git a/src/test/java/com/android/tools/r8/TestDiagnosticMessagesImpl.java b/src/test/java/com/android/tools/r8/TestDiagnosticMessagesImpl.java
index f1b6e73..b52db8d 100644
--- a/src/test/java/com/android/tools/r8/TestDiagnosticMessagesImpl.java
+++ b/src/test/java/com/android/tools/r8/TestDiagnosticMessagesImpl.java
@@ -6,6 +6,7 @@
 
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.fail;
 
@@ -19,7 +20,8 @@
 import java.util.function.BiFunction;
 import org.hamcrest.Matcher;
 
-public class TestDiagnosticMessagesImpl implements DiagnosticsHandler, TestDiagnosticMessages {
+public class TestDiagnosticMessagesImpl extends TestDiagnosticMessages
+    implements DiagnosticsHandler {
   private final List<Diagnostic> infos = new ArrayList<>();
   private final List<Diagnostic> warnings = new ArrayList<>();
   private final List<Diagnostic> errors = new ArrayList<>();
@@ -106,6 +108,12 @@
   }
 
   @Override
+  public TestDiagnosticMessages assertHasWarnings() {
+    assertFalse(warnings.isEmpty());
+    return this;
+  }
+
+  @Override
   public TestDiagnosticMessages assertOnlyInfos() {
     assertNotEquals(0, getInfos().size());
     assertEmpty("warning", getWarnings());
diff --git a/src/test/java/com/android/tools/r8/TestParameters.java b/src/test/java/com/android/tools/r8/TestParameters.java
index 1ac00bb..be45d1c 100644
--- a/src/test/java/com/android/tools/r8/TestParameters.java
+++ b/src/test/java/com/android/tools/r8/TestParameters.java
@@ -11,6 +11,7 @@
 import com.android.tools.r8.TestRuntime.NoneRuntime;
 import com.android.tools.r8.ToolHelper.DexVm;
 import com.android.tools.r8.utils.AndroidApiLevel;
+import java.nio.file.Path;
 
 // Actual test parameters for a specific configuration. Currently just the runtime configuration.
 public class TestParameters {
@@ -60,6 +61,12 @@
     return apiLevel;
   }
 
+  public Path getDefaultRuntimeLibrary() {
+    return isCfRuntime()
+        ? ToolHelper.getJava8RuntimeJar()
+        : ToolHelper.getFirstSupportedAndroidJar(getApiLevel());
+  }
+
   // Access to underlying runtime/wrapper.
   public TestRuntime getRuntime() {
     return runtime;
diff --git a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
index c0cd551..78ac691 100644
--- a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
@@ -112,10 +112,6 @@
     return self();
   }
 
-  public T addDontWarn(String className) {
-    return addKeepRules("-dontwarn " + className);
-  }
-
   public T addDontWarn(Collection<String> classes) {
     for (String clazz : classes) {
       addKeepRules("-dontwarn " + clazz);
@@ -139,26 +135,6 @@
     return addDontWarn("javax.annotation.Nullable");
   }
 
-  public T addDontWarnJavaLangInvoke() {
-    return addDontWarn("java.lang.invoke.*");
-  }
-
-  public T addDontWarnJavaNioFile() {
-    return addDontWarn("java.nio.file.**");
-  }
-
-  public T addDontWarnJetBrainsAnnotations() {
-    return addDontWarnJetBrainsNotNullAnnotation().addDontWarnJetBrainsNullableAnnotation();
-  }
-
-  public T addDontWarnJetBrainsNotNullAnnotation() {
-    return addDontWarn("org.jetbrains.annotations.NotNull");
-  }
-
-  public T addDontWarnJetBrainsNullableAnnotation() {
-    return addDontWarn("org.jetbrains.annotations.Nullable");
-  }
-
   public T addIgnoreWarnings() {
     return addKeepRules("-ignorewarnings");
   }
diff --git a/src/test/java/com/android/tools/r8/ThrowableConsumer.java b/src/test/java/com/android/tools/r8/ThrowableConsumer.java
index f19039b..269ff0e 100644
--- a/src/test/java/com/android/tools/r8/ThrowableConsumer.java
+++ b/src/test/java/com/android/tools/r8/ThrowableConsumer.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8;
 
+
 import java.util.function.Function;
 
 public interface ThrowableConsumer<Formal> {
@@ -18,7 +19,15 @@
   }
 
   default void acceptWithRuntimeException(Formal formal) {
-    acceptWithHandler(formal, RuntimeException::new);
+    acceptWithHandler(
+        formal,
+        exception -> {
+          if (exception instanceof RuntimeException) {
+            throw (RuntimeException) exception;
+          } else {
+            throw new RuntimeException(exception);
+          }
+        });
   }
 
   default ThrowableConsumer<Formal> andThen(ThrowableConsumer<Formal> consumer) {
@@ -27,4 +36,8 @@
       consumer.accept(formal);
     };
   }
+
+  static <Formal> ThrowableConsumer<Formal> empty() {
+    return ignore -> {};
+  }
 }
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index 6c395bf..883a2b4 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -138,7 +138,8 @@
 
   public static final String JAVA_8_RUNTIME = "third_party/openjdk/openjdk-rt-1.8/rt.jar";
   public static final String DESUGAR_JDK_LIBS =
-      System.getProperty("desugar_jdk_libs", "third_party/openjdk/desugar_jdk_libs/libjava.jar");
+      System.getProperty(
+          "desugar_jdk_libs", "third_party/openjdk/desugar_jdk_libs/desugar_jdk_libs.jar");
   public static final String CORE_LAMBDA_STUBS =
       "third_party/core-lambda-stubs/core-lambda-stubs.jar";
   public static final String JSR223_RI_JAR = "third_party/jsr223-api-1.0/jsr223-api-1.0.jar";
@@ -869,6 +870,10 @@
     return annotationJar;
   }
 
+  public static Path getMostRecentKotlinAnnotationJar() {
+    return getKotlinAnnotationJar(KotlinCompiler.latest());
+  }
+
   public static Path getJdwpTestsCfJarPath(AndroidApiLevel minSdk) {
     if (minSdk.getLevel() >= AndroidApiLevel.N.getLevel()) {
       return Paths.get("third_party", "jdwp-tests", "apache-harmony-jdwp-tests-host.jar");
@@ -2147,8 +2152,7 @@
     return new KotlinCompiler[] {getKotlinC_1_3_72(), getKotlinC_1_4_20()};
   }
 
-  public static void disassemble(AndroidApp app, PrintStream ps)
-      throws IOException, ExecutionException {
+  public static void disassemble(AndroidApp app, PrintStream ps) throws IOException {
     DexApplication application =
         new ApplicationReader(app, new InternalOptions(), Timing.empty()).read().toDirect();
     new AssemblyWriter(application, new InternalOptions(), true, false, true).write(ps);
diff --git a/src/test/java/com/android/tools/r8/annotations/SourceDebugExtensionTest.java b/src/test/java/com/android/tools/r8/annotations/SourceDebugExtensionTest.java
index d6a696c..550e21f 100644
--- a/src/test/java/com/android/tools/r8/annotations/SourceDebugExtensionTest.java
+++ b/src/test/java/com/android/tools/r8/annotations/SourceDebugExtensionTest.java
@@ -5,7 +5,9 @@
 package com.android.tools.r8.annotations;
 
 import static com.android.tools.r8.ToolHelper.getFilesInTestFolderRelativeToClass;
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
 import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
+import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.MatcherAssert.assertThat;
@@ -18,7 +20,6 @@
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestRuntime;
 import com.android.tools.r8.TestRuntime.CfRuntime;
-import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
 import com.android.tools.r8.retrace.KotlinInlineFunctionRetraceTest;
 import com.android.tools.r8.shaking.ProguardKeepAttributes;
@@ -64,11 +65,11 @@
     CodeInspector kotlinInspector = new CodeInspector(kotlinSources);
     inspectSourceDebugExtension(kotlinInspector);
     testForR8(parameters.getBackend())
-        .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinCompiler))
+        .addClasspathFiles(
+            getKotlinStdlibJar(kotlinCompiler), getKotlinAnnotationJar(kotlinCompiler))
         .addProgramFiles(kotlinSources)
         .addKeepAttributes(ProguardKeepAttributes.SOURCE_DEBUG_EXTENSION)
         .addKeepAllClassesRule()
-        .addDontWarnJetBrainsNotNullAnnotation()
         .setMode(CompilationMode.RELEASE)
         .setMinApi(parameters.getApiLevel())
         .compile()
diff --git a/src/test/java/com/android/tools/r8/cf/AlwaysNullGetItemTestRunner.java b/src/test/java/com/android/tools/r8/cf/AlwaysNullGetItemTestRunner.java
index b0292e3..f99896f 100644
--- a/src/test/java/com/android/tools/r8/cf/AlwaysNullGetItemTestRunner.java
+++ b/src/test/java/com/android/tools/r8/cf/AlwaysNullGetItemTestRunner.java
@@ -4,79 +4,56 @@
 package com.android.tools.r8.cf;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assume.assumeTrue;
 
-import com.android.tools.r8.ByteDataView;
-import com.android.tools.r8.ClassFileConsumer;
-import com.android.tools.r8.CompilationMode;
-import com.android.tools.r8.DexIndexedConsumer;
-import com.android.tools.r8.R8;
-import com.android.tools.r8.R8Command;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.ToolHelper.ProcessResult;
-import com.android.tools.r8.origin.Origin;
-import com.android.tools.r8.utils.DescriptorUtils;
-import com.android.tools.r8.utils.TestDescriptionWatcher;
-import java.nio.file.Path;
-import org.junit.Rule;
 import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
 
-public class AlwaysNullGetItemTestRunner {
-  static final Class CLASS = AlwaysNullGetItemTest.class;
+@RunWith(Parameterized.class)
+public class AlwaysNullGetItemTestRunner extends TestBase {
 
-  @Rule
-  public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest();
+  private static final Class<?> CLASS = AlwaysNullGetItemTest.class;
 
-  @Rule
-  public TestDescriptionWatcher watcher = new TestDescriptionWatcher();
+  private final TestParameters parameters;
+
+  @Parameterized.Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  public AlwaysNullGetItemTestRunner(TestParameters parameters) {
+    this.parameters = parameters;
+  }
 
   @Test
   public void test() throws Exception {
     ProcessResult runInput =
         ToolHelper.runJava(ToolHelper.getClassPathForTests(), CLASS.getCanonicalName());
     assertEquals(0, runInput.exitCode);
-    Path outCf = temp.getRoot().toPath().resolve("cf.jar");
-    Path outDex = temp.getRoot().toPath().resolve("dex.zip");
-    R8.run(
-        R8Command.builder()
-            .setMode(CompilationMode.DEBUG)
-            .setDisableTreeShaking(true)
-            .setDisableMinification(true)
-            .addClassProgramData(ToolHelper.getClassAsBytes(CLASS), Origin.unknown())
-            .addLibraryFiles(ToolHelper.getAndroidJar(ToolHelper.getMinApiLevelForDexVm()))
-            .setProgramConsumer(new DexIndexedConsumer.ArchiveConsumer(outDex))
-            .build());
-    R8.run(
-        R8Command.builder()
-            .setMode(CompilationMode.DEBUG)
-            .setDisableTreeShaking(true)
-            .setDisableMinification(true)
-            .addClassProgramData(ToolHelper.getClassAsBytes(CLASS), Origin.unknown())
-            .addLibraryFiles(ToolHelper.getJava8RuntimeJar())
-            .setProgramConsumer(new ClassFileConsumer.ArchiveConsumer(outCf))
-            .build());
-    ProcessResult runCf = ToolHelper.runJava(outCf, CLASS.getCanonicalName());
-    ProcessResult runDex = ToolHelper.runArtRaw(outDex.toString(), CLASS.getCanonicalName());
-    assertEquals(runInput.toString(), runCf.toString());
-    // Only compare stdout and exitCode since dex2oat prints to stderr.
-    assertEquals(runInput.stdout, runDex.stdout);
-    assertEquals(runInput.exitCode, runDex.exitCode);
+    testForR8(parameters.getBackend())
+        .addProgramClassesAndInnerClasses(CLASS)
+        .debug()
+        .noMinification()
+        .noTreeShaking()
+        .setMinApi(parameters.getApiLevel())
+        .compile()
+        .run(parameters.getRuntime(), CLASS)
+        .assertSuccessWithOutputLines(NullPointerException.class.getSimpleName());
   }
 
   @Test
   public void testNoCheckCast() throws Exception {
     // Test that JVM accepts javac output when method calls have been replaced by ACONST_NULL.
-    Path out = temp.getRoot().toPath().resolve("aaload-null.jar");
-    ClassFileConsumer.ArchiveConsumer archiveConsumer = new ClassFileConsumer.ArchiveConsumer(out);
-    archiveConsumer.accept(
-        ByteDataView.of(AlwaysNullGetItemDump.dump()),
-        DescriptorUtils.javaTypeToDescriptor(CLASS.getCanonicalName()),
-        null);
-    archiveConsumer.finished(null);
-    ProcessResult processResult = ToolHelper.runJava(out, CLASS.getCanonicalName());
-    if (processResult.exitCode != 0) {
-      System.out.println(processResult);
-    }
-    assertEquals(0, processResult.exitCode);
+    assumeTrue(parameters.isCfRuntime());
+    testForJvm()
+        .addProgramClassFileData(AlwaysNullGetItemDump.dump())
+        .run(parameters.getRuntime(), CLASS)
+        .assertSuccessWithOutputLines(NullPointerException.class.getSimpleName());
   }
 }
diff --git a/src/test/java/com/android/tools/r8/cf/MethodHandleTestRunner.java b/src/test/java/com/android/tools/r8/cf/MethodHandleTestRunner.java
index 2a6652b..cc9b61a 100644
--- a/src/test/java/com/android/tools/r8/cf/MethodHandleTestRunner.java
+++ b/src/test/java/com/android/tools/r8/cf/MethodHandleTestRunner.java
@@ -10,6 +10,7 @@
 import com.android.tools.r8.ClassFileConsumer;
 import com.android.tools.r8.CompilationMode;
 import com.android.tools.r8.DexIndexedConsumer;
+import com.android.tools.r8.NoVerticalClassMerging;
 import com.android.tools.r8.ProgramConsumer;
 import com.android.tools.r8.R8Command;
 import com.android.tools.r8.R8Command.Builder;
@@ -87,7 +88,7 @@
     }
   }
 
-  private final Class[] inputClasses = {
+  private final Class<?>[] inputClasses = {
     MethodHandleTest.class,
     MethodHandleTest.C.class,
     MethodHandleTest.I.class,
@@ -95,6 +96,7 @@
     MethodHandleTest.D.class,
     MethodHandleTest.E.class,
     MethodHandleTest.F.class,
+    NoVerticalClassMerging.class
   };
 
   private void runInput() throws Exception {
diff --git a/src/test/java/com/android/tools/r8/cf/bootstrap/BootstrapTest.java b/src/test/java/com/android/tools/r8/cf/bootstrap/BootstrapTest.java
index 722e4f6..5d890ab 100644
--- a/src/test/java/com/android/tools/r8/cf/bootstrap/BootstrapTest.java
+++ b/src/test/java/com/android/tools/r8/cf/bootstrap/BootstrapTest.java
@@ -38,13 +38,14 @@
   private static final String[] KEEP_R8 = {
     "-keep public class " + R8_NAME + " {", "  public static void main(...);", "}",
   };
+  private static final Path DONTWARN_R8 = Paths.get("src/main/dontwarn.txt");
 
   private static final String HELLO_NAME = "hello.Hello";
   private static final String[] KEEP_HELLO = {
     "-keep class " + HELLO_NAME + " {", "  public static void main(...);", "}",
   };
 
-  private class R8Result {
+  private static class R8Result {
 
     final ProcessResult processResult;
     final Path outputJar;
@@ -64,11 +65,12 @@
 
   @Parameters(name = "{0}")
   public static TestParametersCollection data() {
-    return getTestParameters().withCfRuntimes().build();
+    return getTestParameters().withNoneRuntime().build();
   }
 
   public BootstrapTest(TestParameters parameters) {
     // TODO: use parameters to fork the right Java.
+    assert parameters.isNoneRuntime();
   }
 
   @Test
@@ -96,7 +98,7 @@
       String externalOutput)
       throws Exception {
     // Run R8 on r8.jar.
-    Path output = runR8(R8_STABLE_JAR, internalOutput, KEEP_R8, internalMode);
+    Path output = runR8(internalOutput, internalMode);
     // Run the resulting compiler on hello.jar.
     R8Result runR8R8 = runExternalR8(output, hello, externalOutput, KEEP_HELLO, externalMode);
     // Check that the process outputs (exit code, stdout, stderr) are the same.
@@ -105,19 +107,18 @@
     assertProgramsEqual(runInputR8.outputJar, runR8R8.outputJar);
   }
 
-  private Path runR8(Path inputJar, String outputFolder, String[] keepRules, CompilationMode mode)
-      throws Exception {
+  private Path runR8(String outputFolder, CompilationMode mode) throws Exception {
     Path outputPath = temp.newFolder(outputFolder).toPath();
     Path outputJar = outputPath.resolve("output.jar");
     Path pgConfigFile = outputPath.resolve("keep.rules");
-    FileUtils.writeTextFile(pgConfigFile, keepRules);
+    FileUtils.writeTextFile(pgConfigFile, BootstrapTest.KEEP_R8);
     ToolHelper.runR8(
         R8Command.builder()
             .setMode(mode)
             .addLibraryFiles(ToolHelper.getJava8RuntimeJar())
             .setProgramConsumer(new ClassFileConsumer.ArchiveConsumer(outputJar, true))
-            .addProgramFiles(inputJar)
-            .addProguardConfigurationFiles(pgConfigFile)
+            .addProgramFiles(R8_STABLE_JAR)
+            .addProguardConfigurationFiles(pgConfigFile, DONTWARN_R8)
             .build());
     return outputJar;
   }
diff --git a/src/test/java/com/android/tools/r8/classlookup/LibraryClassExtendsProgramClassTest.java b/src/test/java/com/android/tools/r8/classlookup/LibraryClassExtendsProgramClassTest.java
index 1b68052..c827c09 100644
--- a/src/test/java/com/android/tools/r8/classlookup/LibraryClassExtendsProgramClassTest.java
+++ b/src/test/java/com/android/tools/r8/classlookup/LibraryClassExtendsProgramClassTest.java
@@ -198,8 +198,7 @@
         .addProgramClasses(TestClass.class)
         .addProgramClassFileData(junitClasses)
         .addKeepAllClassesRule()
-        .applyIf(
-            libraryContainsJUnit(), builder -> builder.addKeepRules("-dontwarn android.test.**"))
+        .applyIf(libraryContainsJUnit(), builder -> builder.addDontWarn("android.test.**"))
         .addOptionsModification(options -> options.lookupLibraryBeforeProgram = false)
         .compile()
         .assertNoMessages();
diff --git a/src/test/java/com/android/tools/r8/classmerging/KeptTargetsIncompleteDiamondTest.java b/src/test/java/com/android/tools/r8/classmerging/KeptTargetsIncompleteDiamondTest.java
index 8866342..9527564 100644
--- a/src/test/java/com/android/tools/r8/classmerging/KeptTargetsIncompleteDiamondTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/KeptTargetsIncompleteDiamondTest.java
@@ -10,6 +10,7 @@
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProgramClass;
@@ -37,13 +38,15 @@
   }
 
   public KeptTargetsIncompleteDiamondTest(TestParameters parameters) {
-    // Empty to satisfy construction of none-runtime.
+    assert parameters.isNoneRuntime();
   }
 
   private AppView<AppInfoWithLiveness> computeAppViewWithLiveness(
       Class<?> methodToBeKept, Class<?> classToBeKept) throws Exception {
     return computeAppViewWithLiveness(
-        buildClasses(I.class, J.class, K.class, L.class, A.class, Main.class).build(),
+        buildClasses(I.class, J.class, K.class, L.class, A.class, Main.class)
+            .addLibraryFile(ToolHelper.getJava8RuntimeJar())
+            .build(),
         factory ->
             buildConfigForRules(
                 factory,
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/NestClassTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/NestClassTest.java
index b416826..a043e68 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/NestClassTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/NestClassTest.java
@@ -10,6 +10,7 @@
 import static com.android.tools.r8.utils.codeinspector.Matchers.notIf;
 import static org.hamcrest.MatcherAssert.assertThat;
 
+import com.android.tools.r8.Jdk9TestUtils;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestRuntime.CfVm;
 import com.android.tools.r8.classmerging.horizontal.NestClassTest.R.horizontalclassmerging.BasicNestHostHorizontalClassMerging;
@@ -57,6 +58,7 @@
     testForR8(parameters.getBackend())
         .addKeepMainRule(examplesTypeName(BasicNestHostHorizontalClassMerging.class))
         .addExamplesProgramFiles(R.class)
+        .applyIf(parameters.isCfRuntime(), Jdk9TestUtils.addJdk9LibraryFiles(temp))
         .addOptionsModification(
             options ->
                 options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
diff --git a/src/test/java/com/android/tools/r8/code/NativeMethodWithCodeTest.java b/src/test/java/com/android/tools/r8/code/NativeMethodWithCodeTest.java
index 961be33..af127e7 100644
--- a/src/test/java/com/android/tools/r8/code/NativeMethodWithCodeTest.java
+++ b/src/test/java/com/android/tools/r8/code/NativeMethodWithCodeTest.java
@@ -27,7 +27,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-@RunWith(VmTestRunner.class)
 public class NativeMethodWithCodeTest extends TestBase {
 
   // Test that D8 removes code from native methods (to match the behavior of dx).
diff --git a/src/test/java/com/android/tools/r8/compatproguard/ifrules/ConditionalOnInlinedFieldTest.java b/src/test/java/com/android/tools/r8/compatproguard/ifrules/ConditionalOnInlinedFieldTest.java
index efc344e..588948f 100644
--- a/src/test/java/com/android/tools/r8/compatproguard/ifrules/ConditionalOnInlinedFieldTest.java
+++ b/src/test/java/com/android/tools/r8/compatproguard/ifrules/ConditionalOnInlinedFieldTest.java
@@ -88,9 +88,7 @@
   private TestShrinkerBuilder<?, ?, ?, ?, ?> buildShrinker() throws Exception {
     TestShrinkerBuilder<?, ?, ?, ?, ?> builder;
     if (shrinker == Shrinker.Proguard) {
-      builder =
-          testForProguard()
-              .addKeepRules("-dontwarn " + ConditionalOnInlinedFieldTest.class.getTypeName());
+      builder = testForProguard().addDontWarn(ConditionalOnInlinedFieldTest.class);
     } else if (shrinker == Shrinker.R8Compat) {
       builder = testForR8Compat(parameters.getBackend());
     } else {
diff --git a/src/test/java/com/android/tools/r8/compatproguard/ifrules/ConditionalOnInlinedTest.java b/src/test/java/com/android/tools/r8/compatproguard/ifrules/ConditionalOnInlinedTest.java
index faa9eda..e1d6571 100644
--- a/src/test/java/com/android/tools/r8/compatproguard/ifrules/ConditionalOnInlinedTest.java
+++ b/src/test/java/com/android/tools/r8/compatproguard/ifrules/ConditionalOnInlinedTest.java
@@ -69,9 +69,7 @@
   private TestShrinkerBuilder<?, ?, ?, ?, ?> buildShrinker() throws Exception {
     TestShrinkerBuilder<?, ?, ?, ?, ?> builder;
     if (shrinker == Shrinker.Proguard) {
-      builder =
-          testForProguard()
-              .addKeepRules("-dontwarn " + ConditionalOnInlinedTest.class.getTypeName());
+      builder = testForProguard().addDontWarn(ConditionalOnInlinedTest.class);
     } else if (shrinker == Shrinker.R8Compat) {
       builder = testForR8Compat(parameters.getBackend());
     } else {
diff --git a/src/test/java/com/android/tools/r8/debug/KotlinStdLibCompilationTest.java b/src/test/java/com/android/tools/r8/debug/KotlinStdLibCompilationTest.java
index 86e11d0..eebed6b 100644
--- a/src/test/java/com/android/tools/r8/debug/KotlinStdLibCompilationTest.java
+++ b/src/test/java/com/android/tools/r8/debug/KotlinStdLibCompilationTest.java
@@ -3,7 +3,10 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.debug;
 
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
 import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
+import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
+import static org.hamcrest.CoreMatchers.equalTo;
 import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.CompilationFailedException;
@@ -13,7 +16,6 @@
 import com.android.tools.r8.TestDiagnosticMessages;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersBuilder;
-import com.android.tools.r8.ToolHelper;
 import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -42,7 +44,7 @@
   public void testD8() throws CompilationFailedException {
     assumeTrue(parameters.isDexRuntime());
     testForD8()
-        .addProgramFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+        .addProgramFiles(getKotlinStdlibJar(kotlinc))
         .setMinApi(parameters.getApiLevel())
         .compileWithExpectedDiagnostics(TestDiagnosticMessages::assertNoMessages);
   }
@@ -50,13 +52,14 @@
   @Test
   public void testR8() throws CompilationFailedException {
     testForR8(parameters.getBackend())
-        .addProgramFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+        .addProgramFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
+        .addKeepAllAttributes()
+        .allowDiagnosticWarningMessages()
         .noMinification()
         .noTreeShaking()
-        .addKeepAllAttributes()
-        .addDontWarnJetBrainsAnnotations()
         .setMode(CompilationMode.DEBUG)
         .setMinApi(parameters.getApiLevel())
-        .compileWithExpectedDiagnostics(TestDiagnosticMessages::assertNoMessages);
+        .compile()
+        .assertAllWarningMessagesMatch(equalTo("Resource 'META-INF/MANIFEST.MF' already exists."));
   }
 }
diff --git a/src/test/java/com/android/tools/r8/debuginfo/KotlinDebugInfoTestRunner.java b/src/test/java/com/android/tools/r8/debuginfo/KotlinDebugInfoTestRunner.java
index a0e9a1d..80a51c8 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/KotlinDebugInfoTestRunner.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/KotlinDebugInfoTestRunner.java
@@ -6,21 +6,33 @@
 import static org.junit.Assert.assertEquals;
 
 import com.android.tools.r8.ByteDataView;
-import com.android.tools.r8.ClassFileConsumer;
 import com.android.tools.r8.ClassFileConsumer.ArchiveConsumer;
-import com.android.tools.r8.CompilationMode;
-import com.android.tools.r8.ProgramConsumer;
-import com.android.tools.r8.R8Command;
-import com.android.tools.r8.R8Command.Builder;
+import com.android.tools.r8.R8FullTestBuilder;
 import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ThrowableConsumer;
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.ToolHelper.ProcessResult;
-import com.android.tools.r8.origin.Origin;
-import com.google.common.collect.ImmutableList;
 import java.nio.file.Path;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
 
+@RunWith(Parameterized.class)
 public class KotlinDebugInfoTestRunner extends TestBase {
+
+  private final TestParameters parameters;
+
+  @Parameterized.Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withCfRuntimes().build();
+  }
+
+  public KotlinDebugInfoTestRunner(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
   private Path buildInput(byte[] clazz, String descriptor) {
     Path inputJar = temp.getRoot().toPath().resolve("input.jar");
     ArchiveConsumer inputJarConsumer = new ArchiveConsumer(inputJar);
@@ -29,19 +41,16 @@
     return inputJar;
   }
 
-  private Path buildCf(Path inputJar) throws Exception {
-    Path cfJar = temp.getRoot().toPath().resolve("r8cf.jar");
-    build(inputJar, new ArchiveConsumer(cfJar));
-    return cfJar;
-  }
-
   @Test
   public void testRingBuffer() throws Exception {
     // This test hits the case where we simplify a DebugLocalWrite v'(x) <- v
     // with debug use [live: y], and y is written between v and v'.
     // In this case we must not move [live: y] to the definition of v,
     // since it causes the live range of y to extend to the entry to the first block.
-    test(KotlinRingBufferDump.dump(), KotlinRingBufferDump.CLASS_NAME);
+    test(
+        KotlinRingBufferDump.dump(),
+        KotlinRingBufferDump.CLASS_NAME,
+        builder -> builder.addDontWarn("kotlin.Metadata"));
   }
 
   @Test
@@ -56,7 +65,11 @@
     test(DebugInfoDump.dump(), DebugInfoDump.CLASS_NAME);
   }
 
-  public void test(byte[] bytes, String className) throws Exception {
+  public void test(byte[] bytes, String className) throws Exception {}
+
+  public void test(
+      byte[] bytes, String className, ThrowableConsumer<R8FullTestBuilder> configuration)
+      throws Exception {
     String descriptor = 'L' + className.replace('.', '/') + ';';
     Path inputJar = buildInput(bytes, descriptor);
     ProcessResult runInput = ToolHelper.runJava(inputJar, className);
@@ -64,26 +77,18 @@
       System.out.println(runInput);
     }
     assertEquals(0, runInput.exitCode);
-    Path outCf = buildCf(inputJar);
-    ProcessResult runCf = ToolHelper.runJava(outCf, className);
-    assertEquals(runInput.toString(), runCf.toString());
-  }
 
-  private void build(Path inputJar, ProgramConsumer consumer) throws Exception {
-    Builder builder =
-        R8Command.builder()
-            .setMode(CompilationMode.DEBUG)
-            .setDisableTreeShaking(true)
-            .setDisableMinification(true)
-            .addProguardConfiguration(
-                ImmutableList.of("-keepattributes SourceFile,LineNumberTable"), Origin.unknown())
-            .setProgramConsumer(consumer)
-            .addProgramFiles(inputJar);
-    if ((consumer instanceof ClassFileConsumer)) {
-      builder.addLibraryFiles(ToolHelper.getJava8RuntimeJar());
-    } else {
-      builder.addLibraryFiles(ToolHelper.getAndroidJar(ToolHelper.getMinApiLevelForDexVm()));
-    }
-    ToolHelper.runR8(builder.build(), options -> options.invalidDebugInfoFatal = true);
+    testForR8(parameters.getBackend())
+        .addProgramFiles(inputJar)
+        .addKeepAttributeLineNumberTable()
+        .addKeepAttributeSourceFile()
+        .addOptionsModification(options -> options.invalidDebugInfoFatal = true)
+        .apply(configuration)
+        .debug()
+        .noMinification()
+        .noTreeShaking()
+        .compile()
+        .run(parameters.getRuntime(), className)
+        .assertSuccessWithOutput(runInput.stdout);
   }
 }
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/ConcurrentHashMapFileSerializationTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/ConcurrentHashMapFileSerializationTest.java
index b38eac1..db361d4 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/ConcurrentHashMapFileSerializationTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/ConcurrentHashMapFileSerializationTest.java
@@ -94,6 +94,7 @@
       chmTest();
     }
 
+    @SuppressWarnings("unchecked")
     private static void chmTest() throws IOException, ClassNotFoundException {
       ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>();
       map.put("k1", "v1");
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/MyMapFileSerializationTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/MyMapFileSerializationTest.java
index 623cfd0..42844c1 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/MyMapFileSerializationTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/MyMapFileSerializationTest.java
@@ -88,6 +88,8 @@
 
   @SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
   static class Executor {
+
+    @SuppressWarnings("unchecked")
     public static void main(String[] args) throws Exception {
       MyMap<String, String> map = new MyMap<>();
       map.put("k1", "v1");
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11MathTests.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11MathTests.java
index 2c62b8f..6a69902 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11MathTests.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11MathTests.java
@@ -7,6 +7,7 @@
 import static com.android.tools.r8.utils.FileUtils.CLASS_EXTENSION;
 import static com.android.tools.r8.utils.FileUtils.JAVA_EXTENSION;
 
+import com.android.tools.r8.Jdk9TestUtils;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
@@ -114,6 +115,7 @@
         .addKeepMainRule(EXACTARITH)
         .addProgramFiles(JDK_11_MATH_TEST_CLASS_FILES)
         .addLibraryFiles(ToolHelper.getMostRecentAndroidJar())
+        .applyIf(parameters.isCfRuntime(), Jdk9TestUtils.addJdk9LibraryFiles(temp))
         .setMinApi(parameters.getRuntime())
         .run(parameters.getRuntime(), EXACTARITH)
         .assertSuccessWithOutput("");
@@ -126,6 +128,7 @@
         .addKeepMainRule(EXACTARITH)
         .addProgramFiles(JDK_11_MATH_TEST_CLASS_FILES)
         .addLibraryFiles(ToolHelper.getMostRecentAndroidJar())
+        .applyIf(parameters.isCfRuntime(), Jdk9TestUtils.addJdk9LibraryFiles(temp))
         .setMinApi(parameters.getRuntime())
         .run(parameters.getRuntime(), DIVMOD)
         .assertSuccessWithOutput("");
@@ -137,6 +140,7 @@
         .addProgramFiles(JDK_11_STRICT_MATH_TEST_CLASS_FILES)
         .addKeepMainRule(EXACTARITH)
         .addLibraryFiles(ToolHelper.getMostRecentAndroidJar())
+        .applyIf(parameters.isCfRuntime(), Jdk9TestUtils.addJdk9LibraryFiles(temp))
         .setMinApi(parameters.getRuntime())
         .run(parameters.getRuntime(), EXACTARITH)
         .assertSuccessWithOutput("");
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11ObjectsTests.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11ObjectsTests.java
index c49e10c..f4bcceb 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11ObjectsTests.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11ObjectsTests.java
@@ -7,6 +7,7 @@
 import static com.android.tools.r8.utils.FileUtils.CLASS_EXTENSION;
 import static com.android.tools.r8.utils.FileUtils.JAVA_EXTENSION;
 
+import com.android.tools.r8.Jdk9TestUtils;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
@@ -81,6 +82,7 @@
         .addLibraryFiles(libraryJar)
         .addKeepMainRule(BASIC_OBJECTS_TEST)
         .addProgramFiles(JDK_11_OBJECTS_TEST_CLASS_FILES)
+        .applyIf(parameters.isCfRuntime(), Jdk9TestUtils.addJdk9LibraryFiles(temp))
         .setMinApi(parameters.getRuntime())
         .run(parameters.getRuntime(), BASIC_OBJECTS_TEST)
         .assertSuccessWithOutput("");
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/FullNestOnProgramPathTest.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/FullNestOnProgramPathTest.java
index 8a37cd0..68f3fcf 100644
--- a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/FullNestOnProgramPathTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/FullNestOnProgramPathTest.java
@@ -17,12 +17,15 @@
 
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.D8TestCompileResult;
+import com.android.tools.r8.Jdk9TestUtils;
+import com.android.tools.r8.R8FullTestBuilder;
 import com.android.tools.r8.R8TestCompileResult;
 import com.android.tools.r8.R8TestRunResult;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ThrowableConsumer;
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -108,6 +111,7 @@
           .setMinApi(parameters.getApiLevel())
           .addProgramFiles(classesOfNest(nestID))
           .addOptionsModification(options -> options.enableNestReduction = false)
+          .applyIf(parameters.isCfRuntime(), Jdk9TestUtils.addJdk9LibraryFiles(temp))
           .compile()
           .run(parameters.getRuntime(), getMainClass(nestID))
           .assertSuccessWithOutput(getExpectedResult(nestID));
@@ -135,9 +139,16 @@
         .compile();
   }
 
-  private static R8TestCompileResult compileAllNestsR8(Backend backend, AndroidApiLevel minApi)
+  static R8TestCompileResult compileAllNestsR8(Backend backend, AndroidApiLevel minApi)
+      throws CompilationFailedException {
+    return compileAllNestsR8(backend, minApi, null);
+  }
+
+  static R8TestCompileResult compileAllNestsR8(
+      Backend backend, AndroidApiLevel minApi, ThrowableConsumer<R8FullTestBuilder> configuration)
       throws CompilationFailedException {
     return testForR8(getStaticTemp(), backend)
+        .apply(configuration)
         .noTreeShaking()
         .noMinification()
         .addKeepAllAttributes()
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/Java11R8BootstrapTest.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/Java11R8BootstrapTest.java
index a756d95..1eac80e 100644
--- a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/Java11R8BootstrapTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/Java11R8BootstrapTest.java
@@ -8,6 +8,7 @@
 import static junit.framework.TestCase.assertEquals;
 import static junit.framework.TestCase.assertTrue;
 
+import com.android.tools.r8.Jdk11TestUtils;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
@@ -66,6 +67,7 @@
     // Shrink R8 11 with R8
     return testForR8(TestBase.getStaticTemp(), Backend.CF)
         .addProgramFiles(ToolHelper.R8_WITH_RELOCATED_DEPS_11_JAR)
+        .addLibraryFiles(Jdk11TestUtils.getJdk11LibraryFiles(getStaticTemp()))
         .addKeepRuleFiles(MAIN_KEEP)
         .applyIf(
             desugar,
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/Java11R8CompilationTest.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/Java11R8CompilationTest.java
index f47e524..cb549f5 100644
--- a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/Java11R8CompilationTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/Java11R8CompilationTest.java
@@ -31,8 +31,8 @@
   @Parameters(name = "{0}")
   public static TestParametersCollection data() {
     return getTestParameters()
-        // Use of APIs, such as java.util.functions.* are only available from 24+
-        .withApiLevelsStartingAtIncluding(AndroidApiLevel.N)
+        // Use of APIs, such as java.nio.file.* are only available from 26+.
+        .withApiLevelsStartingAtIncluding(AndroidApiLevel.O)
         .withDexRuntimes()
         .build();
   }
@@ -50,11 +50,6 @@
         .setMinApi(parameters.getApiLevel())
         .addProgramFiles(ToolHelper.R8_WITH_RELOCATED_DEPS_11_JAR)
         .addKeepRuleFiles(MAIN_KEEP)
-        // TODO(b/177967938): Investigate why this is needed.
-        .applyIf(
-            parameters.getApiLevel().isLessThan(AndroidApiLevel.O),
-            builder -> builder.addDontWarnJavaLangInvoke().addDontWarnJavaNioFile())
-        .addOptionsModification(opt -> opt.ignoreMissingClasses = true)
         .compile()
         .inspect(this::assertNotEmpty)
         .inspect(Java11R8CompilationTest::assertNoNests);
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/MinimumNumberOfBridgesGenerated.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/MinimumNumberOfBridgesGenerated.java
index 6557f52..b38e710 100644
--- a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/MinimumNumberOfBridgesGenerated.java
+++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/MinimumNumberOfBridgesGenerated.java
@@ -7,6 +7,7 @@
 import static com.android.tools.r8.desugar.nestaccesscontrol.NestAccessControlTestUtils.getMainClass;
 import static org.junit.Assert.assertEquals;
 
+import com.android.tools.r8.Jdk9TestUtils;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
@@ -51,8 +52,11 @@
           .apply(parameters.getApiLevel())
           .inspect(this::assertOnlyRequiredBridges);
     }
-    FullNestOnProgramPathTest.r8CompilationResult
-        .apply(parameters.getBackend(), parameters.getApiLevel())
+    FullNestOnProgramPathTest.compileAllNestsR8(
+            parameters.getBackend(),
+            parameters.getApiLevel(),
+            builder ->
+                builder.applyIf(parameters.isCfRuntime(), Jdk9TestUtils.addJdk9LibraryFiles(temp)))
         .inspect(this::assertOnlyRequiredBridges);
   }
 
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesUpdateTest.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesUpdateTest.java
index aa22447..f1884e9 100644
--- a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesUpdateTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesUpdateTest.java
@@ -11,6 +11,7 @@
 import static junit.framework.TestCase.assertSame;
 import static junit.framework.TestCase.assertTrue;
 
+import com.android.tools.r8.Jdk9TestUtils;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
@@ -94,6 +95,7 @@
               options.enableClassInlining = false;
             })
         .addProgramFiles(classesMatching(outerNestName))
+        .applyIf(parameters.isCfRuntime(), Jdk9TestUtils.addJdk9LibraryFiles(temp))
         .addInliningAnnotations()
         .compile()
         .inspect(
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestClassMergingTest.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestClassMergingTest.java
index 9a188cf..073c7b1 100644
--- a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestClassMergingTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestClassMergingTest.java
@@ -3,6 +3,7 @@
 import static com.android.tools.r8.desugar.nestaccesscontrol.NestAccessControlTestUtils.PACKAGE_NAME;
 import static com.android.tools.r8.desugar.nestaccesscontrol.NestAccessControlTestUtils.classesMatching;
 
+import com.android.tools.r8.Jdk9TestUtils;
 import com.android.tools.r8.R8FullTestBuilder;
 import com.android.tools.r8.R8TestCompileResult;
 import com.android.tools.r8.TestBase;
@@ -97,6 +98,7 @@
                 })
             .enableInliningAnnotations()
             .addProgramFiles(bothNestsAndOutsideClassToCompile)
+            .applyIf(parameters.isCfRuntime(), Jdk9TestUtils.addJdk9LibraryFiles(temp))
             .compile()
             .inspect(NestAttributesUpdateTest::assertNestAttributesCorrect);
     for (int i = 0; i < mainClasses.length; i++) {
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestCompilationExceptionTest.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestCompilationExceptionTest.java
index 78904fd..c6df029 100644
--- a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestCompilationExceptionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestCompilationExceptionTest.java
@@ -12,23 +12,23 @@
 import static org.hamcrest.core.StringContains.containsString;
 import static org.hamcrest.core.StringEndsWith.endsWith;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.Jdk9TestUtils;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestCompileResult;
 import com.android.tools.r8.TestCompilerBuilder;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.TestRuntime.CfVm;
-import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.ToolHelper.DexVm;
 import com.android.tools.r8.diagnostic.internal.MissingDefinitionsDiagnosticImpl;
 import com.android.tools.r8.errors.IncompleteNestNestDesugarDiagnosic;
 import com.android.tools.r8.errors.InterfaceDesugarMissingTypeDiagnostic;
 import com.android.tools.r8.errors.MissingNestHostNestDesugarDiagnostic;
+import com.android.tools.r8.references.Reference;
 import java.nio.file.Path;
 import java.util.List;
 import org.hamcrest.Matcher;
@@ -95,7 +95,7 @@
           .addKeepAllAttributes()
           .setMinApi(parameters.getApiLevel())
           .addProgramFiles(matchingClasses)
-          .addLibraryFiles(ToolHelper.getMostRecentAndroidJar())
+          .applyIf(parameters.isCfRuntime(), Jdk9TestUtils.addJdk9LibraryFiles(temp))
           .addOptionsModification(
               options -> {
                 options.ignoreMissingClasses = ignoreMissingClasses;
@@ -128,14 +128,14 @@
                 } else {
                   diagnostics
                       .assertOnlyErrors()
-                      .assertErrorsMatch(diagnosticType(MissingDefinitionsDiagnosticImpl.class));
-
-                  MissingDefinitionsDiagnosticImpl diagnostic =
-                      (MissingDefinitionsDiagnosticImpl) diagnostics.getErrors().get(0);
-                  assertEquals(1, diagnostic.getMissingClasses().size());
-                  assertEquals(
-                      "nesthostexample.BasicNestHostWithInnerClassMethods",
-                      diagnostic.getMissingClasses().iterator().next().getTypeName());
+                      .inspectErrors(
+                          diagnostic ->
+                              diagnostic
+                                  .assertIsMissingDefinitionsDiagnostic()
+                                  .assertIsMissingClass(
+                                      Reference.classFromTypeName(
+                                          "nesthostexample.BasicNestHostWithInnerClassMethods"))
+                                  .assertNumberOfMissingClasses(1));
                 }
               });
     } catch (CompilationFailedException e) {
@@ -167,14 +167,14 @@
                 } else {
                   diagnostics
                       .assertOnlyErrors()
-                      .assertErrorsMatch(diagnosticType(MissingDefinitionsDiagnosticImpl.class));
-
-                  MissingDefinitionsDiagnosticImpl diagnostic =
-                      (MissingDefinitionsDiagnosticImpl) diagnostics.getErrors().get(0);
-                  assertEquals(1, diagnostic.getMissingClasses().size());
-                  assertEquals(
-                      "nesthostexample.BasicNestHostWithInnerClassMethods$BasicNestedClass",
-                      diagnostic.getMissingClasses().iterator().next().getTypeName());
+                      .inspectErrors(
+                          diagnostic ->
+                              diagnostic
+                                  .assertIsMissingDefinitionsDiagnostic()
+                                  .assertIsMissingClass(
+                                      Reference.classFromTypeName(
+                                          "nesthostexample.BasicNestHostWithInnerClassMethods$BasicNestedClass"))
+                                  .assertNumberOfMissingClasses(1));
                 }
               });
     } catch (Exception e) {
@@ -208,13 +208,15 @@
                   diagnosticType(MissingDefinitionsDiagnosticImpl.class),
                   diagnosticType(InterfaceDesugarMissingTypeDiagnostic.class));
             }
-
-            MissingDefinitionsDiagnosticImpl diagnostic =
-                (MissingDefinitionsDiagnosticImpl) diagnostics.getWarnings().get(0);
-            assertEquals(1, diagnostic.getMissingClasses().size());
-            assertEquals(
-                "nesthostexample.BasicNestHostWithInnerClassMethods",
-                diagnostic.getMissingClasses().iterator().next().getTypeName());
+            diagnostics.inspectWarning(
+                0,
+                diagnostic ->
+                    diagnostic
+                        .assertIsMissingDefinitionsDiagnostic()
+                        .assertIsMissingClass(
+                            Reference.classFromTypeName(
+                                "nesthostexample.BasicNestHostWithInnerClassMethods"))
+                        .assertNumberOfMissingClasses(1));
           });
     }
   }
@@ -242,14 +244,15 @@
                   diagnosticType(MissingDefinitionsDiagnosticImpl.class),
                   diagnosticType(InterfaceDesugarMissingTypeDiagnostic.class));
             }
-
-            MissingDefinitionsDiagnosticImpl diagnostic =
-                (MissingDefinitionsDiagnosticImpl) diagnostics.getWarnings().get(0);
-            assertNotNull(diagnostic);
-            assertEquals(1, diagnostic.getMissingClasses().size());
-            assertEquals(
-                "nesthostexample.BasicNestHostWithInnerClassMethods$BasicNestedClass",
-                diagnostic.getMissingClasses().iterator().next().getTypeName());
+            diagnostics.inspectWarning(
+                0,
+                diagnostic ->
+                    diagnostic
+                        .assertIsMissingDefinitionsDiagnostic()
+                        .assertIsMissingClass(
+                            Reference.classFromTypeName(
+                                "nesthostexample.BasicNestHostWithInnerClassMethods$BasicNestedClass"))
+                        .assertNumberOfMissingClasses(1));
           });
     }
   }
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestConstructorRemovedArgTest.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestConstructorRemovedArgTest.java
index 85bade9..b216639 100644
--- a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestConstructorRemovedArgTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestConstructorRemovedArgTest.java
@@ -8,6 +8,7 @@
 import static com.android.tools.r8.desugar.nestaccesscontrol.NestAccessControlTestUtils.getExpectedResult;
 import static com.android.tools.r8.desugar.nestaccesscontrol.NestAccessControlTestUtils.getMainClass;
 
+import com.android.tools.r8.Jdk9TestUtils;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
@@ -44,11 +45,9 @@
         .addKeepMainRule(getMainClass(nestID))
         .noMinification()
         .setMinApi(parameters.getApiLevel())
-        .addOptionsModification(
-            options -> {
-              options.enableClassInlining = false;
-            })
+        .addOptionsModification(options -> options.enableClassInlining = false)
         .addProgramFiles(classesOfNest(nestID))
+        .applyIf(parameters.isCfRuntime(), Jdk9TestUtils.addJdk9LibraryFiles(temp))
         .compile()
         .run(parameters.getRuntime(), getMainClass(nestID))
         .assertSuccessWithOutput(getExpectedResult(nestID));
@@ -62,11 +61,9 @@
         .addKeepMainRule(getMainClass(nestID))
         .noMinification()
         .setMinApi(parameters.getApiLevel())
-        .addOptionsModification(
-            options -> {
-              options.enableClassInlining = false;
-            })
+        .addOptionsModification(options -> options.enableClassInlining = false)
         .addProgramFiles(classesOfNest(nestID))
+        .applyIf(parameters.isCfRuntime(), Jdk9TestUtils.addJdk9LibraryFiles(temp))
         .compile()
         .run(parameters.getRuntime(), getMainClass(nestID))
         .assertSuccessWithOutput(getExpectedResult(nestID));
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordTestUtils.java b/src/test/java/com/android/tools/r8/desugar/records/RecordTestUtils.java
index 245607b..3a0a306 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordTestUtils.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/RecordTestUtils.java
@@ -52,6 +52,7 @@
         JavaCompilerTool.create(getCheckedInJdk8(), temp)
             .addSourceFiles(Paths.get("src", "test", "javaStubs", "Record.java"))
             .addSourceFiles(Paths.get("src", "test", "javaStubs", "ObjectMethods.java"))
+            .addSourceFiles(Paths.get("src", "test", "javaStubs", "StringConcatFactory.java"))
             .addSourceFiles(Paths.get("src", "test", "javaStubs", "TypeDescriptor.java"))
             .addSourceFiles(Paths.get("src", "test", "javaStubs", "RecordComponent.java"))
             .compile();
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordWithMembersTest.java b/src/test/java/com/android/tools/r8/desugar/records/RecordWithMembersTest.java
index 6d97f29..e6d1444 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordWithMembersTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/RecordWithMembersTest.java
@@ -6,6 +6,7 @@
 
 import static com.android.tools.r8.desugar.records.RecordTestUtils.RECORD_KEEP_RULE;
 
+import com.android.tools.r8.Jdk9TestUtils;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestRuntime.CfRuntime;
@@ -54,6 +55,7 @@
     Path output =
         testForR8(parameters.getBackend())
             .addProgramClassFileData(PROGRAM_DATA)
+            .addLibraryFiles(Jdk9TestUtils.getJdk9LibraryFiles(temp))
             .setMinApi(parameters.getApiLevel())
             .addKeepRules(RECORD_KEEP_RULE)
             .addKeepMainRule(MAIN_TYPE)
diff --git a/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterTests.java b/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterTests.java
index 0ef3bdf..e90e0ab 100644
--- a/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterTests.java
+++ b/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterTests.java
@@ -52,6 +52,7 @@
   private static final String CLASS2_CLASS = CLASS_DIR + "/Class2.class";
   private static final String CLASS3_CLASS = CLASS_DIR + "/Class3.class";
   private static final String CLASS3_INNER_CLASS = CLASS_DIR + "/Class3$InnerClass.class";
+  private static final String CLASS3_SYNTHETIC_CLASS = CLASS_DIR + "/Class3$1.class";
   private static final String CLASS4_CLASS = CLASS_DIR + "/Class4.class";
   private static final String CLASS4_LAMBDA_INTERFACE = CLASS_DIR + "/Class4$LambdaInterface.class";
   private static final String TEXT_FILE =
@@ -71,6 +72,7 @@
             .addProgramFiles(Paths.get(CLASS2_CLASS))
             .addProgramFiles(Paths.get(CLASS3_CLASS))
             .addProgramFiles(Paths.get(CLASS3_INNER_CLASS))
+            .addProgramFiles(Paths.get(CLASS3_SYNTHETIC_CLASS))
             .addProgramFiles(Paths.get(CLASS4_CLASS))
             .addProgramFiles(Paths.get(CLASS4_LAMBDA_INTERFACE))
             .build();
@@ -264,6 +266,10 @@
     featureStream.putNextEntry(new ZipEntry(name));
     featureStream.write(Files.readAllBytes(Paths.get(CLASS3_INNER_CLASS)));
     featureStream.closeEntry();
+    name = "dexsplitsample/Class3$1.class";
+    featureStream.putNextEntry(new ZipEntry(name));
+    featureStream.write(Files.readAllBytes(Paths.get(CLASS3_SYNTHETIC_CLASS)));
+    featureStream.closeEntry();
     name = "dexsplitsample/Class4";
     featureStream.putNextEntry(new ZipEntry(name));
     featureStream.write(Files.readAllBytes(Paths.get(CLASS4_CLASS)));
@@ -325,6 +331,7 @@
             .addProgramFiles(Paths.get(CLASS2_CLASS))
             .addProgramFiles(Paths.get(CLASS3_CLASS))
             .addProgramFiles(Paths.get(CLASS3_INNER_CLASS))
+            .addProgramFiles(Paths.get(CLASS3_SYNTHETIC_CLASS))
             .addProgramFiles(Paths.get(CLASS4_CLASS))
             .addProgramFiles(Paths.get(CLASS4_LAMBDA_INTERFACE))
             .addLibraryFiles(ToolHelper.getDefaultAndroidJar())
diff --git a/src/test/java/com/android/tools/r8/diagnosticinspector/AbsentDiagnosticSubject.java b/src/test/java/com/android/tools/r8/diagnosticinspector/AbsentDiagnosticSubject.java
new file mode 100644
index 0000000..f94c8f4
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/diagnosticinspector/AbsentDiagnosticSubject.java
@@ -0,0 +1,17 @@
+// Copyright (c) 2021, 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.diagnosticinspector;
+
+import static org.junit.Assert.fail;
+
+import com.android.tools.r8.errors.Unreachable;
+
+public class AbsentDiagnosticSubject implements DiagnosticSubject {
+  @Override
+  public FoundMissingDefinitionsDiagnosticSubject assertIsMissingDefinitionsDiagnostic() {
+    fail("Expected MissingDefinitionsDiagnostic, but was absent");
+    throw new Unreachable();
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/diagnosticinspector/DiagnosticSubject.java b/src/test/java/com/android/tools/r8/diagnosticinspector/DiagnosticSubject.java
new file mode 100644
index 0000000..f7123eb
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/diagnosticinspector/DiagnosticSubject.java
@@ -0,0 +1,10 @@
+// Copyright (c) 2021, 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.diagnosticinspector;
+
+public interface DiagnosticSubject {
+
+  FoundMissingDefinitionsDiagnosticSubject assertIsMissingDefinitionsDiagnostic();
+}
diff --git a/src/test/java/com/android/tools/r8/diagnosticinspector/FoundDiagnosticSubject.java b/src/test/java/com/android/tools/r8/diagnosticinspector/FoundDiagnosticSubject.java
new file mode 100644
index 0000000..427bef0
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/diagnosticinspector/FoundDiagnosticSubject.java
@@ -0,0 +1,30 @@
+// Copyright (c) 2021, 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.diagnosticinspector;
+
+import static com.android.tools.r8.DiagnosticsMatcher.diagnosticType;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.Diagnostic;
+import com.android.tools.r8.diagnostic.MissingDefinitionsDiagnostic;
+
+public class FoundDiagnosticSubject<D extends Diagnostic> implements DiagnosticSubject {
+
+  private final D diagnostic;
+
+  public FoundDiagnosticSubject(D diagnostic) {
+    this.diagnostic = diagnostic;
+  }
+
+  public D getDiagnostic() {
+    return diagnostic;
+  }
+
+  @Override
+  public FoundMissingDefinitionsDiagnosticSubject assertIsMissingDefinitionsDiagnostic() {
+    assertThat(diagnostic, diagnosticType(MissingDefinitionsDiagnostic.class));
+    return new FoundMissingDefinitionsDiagnosticSubject((MissingDefinitionsDiagnostic) diagnostic);
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/diagnosticinspector/FoundMissingDefinitionContextSubject.java b/src/test/java/com/android/tools/r8/diagnosticinspector/FoundMissingDefinitionContextSubject.java
new file mode 100644
index 0000000..4178db4
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/diagnosticinspector/FoundMissingDefinitionContextSubject.java
@@ -0,0 +1,44 @@
+// Copyright (c) 2021, 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.diagnosticinspector;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.diagnostic.MissingDefinitionClassContext;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.MissingDefinitionFieldContext;
+import com.android.tools.r8.diagnostic.MissingDefinitionMethodContext;
+
+public class FoundMissingDefinitionContextSubject {
+
+  private final MissingDefinitionContext context;
+
+  public FoundMissingDefinitionContextSubject(MissingDefinitionContext context) {
+    this.context = context;
+  }
+
+  public FoundMissingDefinitionContextSubject assertEqualTo(
+      MissingDefinitionClassContext expectedContext) {
+    assertTrue(context.isClassContext());
+    assertEquals(expectedContext.getClassReference(), context.asClassContext().getClassReference());
+    return this;
+  }
+
+  public FoundMissingDefinitionContextSubject assertEqualTo(
+      MissingDefinitionFieldContext expectedContext) {
+    assertTrue(context.isFieldContext());
+    assertEquals(expectedContext.getFieldReference(), context.asFieldContext().getFieldReference());
+    return this;
+  }
+
+  public FoundMissingDefinitionContextSubject assertEqualTo(
+      MissingDefinitionMethodContext expectedContext) {
+    assertTrue(context.isMethodContext());
+    assertEquals(
+        expectedContext.getMethodReference(), context.asMethodContext().getMethodReference());
+    return this;
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/diagnosticinspector/FoundMissingDefinitionInfoSubject.java b/src/test/java/com/android/tools/r8/diagnosticinspector/FoundMissingDefinitionInfoSubject.java
new file mode 100644
index 0000000..89a5db5
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/diagnosticinspector/FoundMissingDefinitionInfoSubject.java
@@ -0,0 +1,80 @@
+// Copyright (c) 2021, 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.diagnosticinspector;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.MissingDefinitionInfo;
+import com.android.tools.r8.diagnostic.internal.MissingDefinitionContextUtils;
+import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.references.FieldReference;
+import com.android.tools.r8.references.MethodReference;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class FoundMissingDefinitionInfoSubject {
+
+  private final MissingDefinitionInfo missingDefinitionInfo;
+
+  private final Map<ClassReference, FoundMissingDefinitionContextSubject> classContexts =
+      new HashMap<>();
+  private final Map<FieldReference, FoundMissingDefinitionContextSubject> fieldContexts =
+      new HashMap<>();
+  private final Map<MethodReference, FoundMissingDefinitionContextSubject> methodContexts =
+      new HashMap<>();
+
+  public FoundMissingDefinitionInfoSubject(MissingDefinitionInfo missingDefinitionInfo) {
+    this.missingDefinitionInfo = missingDefinitionInfo;
+    missingDefinitionInfo
+        .getReferencedFromContexts()
+        .forEach(
+            context ->
+                MissingDefinitionContextUtils.accept(
+                    context,
+                    classContext ->
+                        classContexts.put(
+                            classContext.getClassReference(),
+                            new FoundMissingDefinitionContextSubject(context)),
+                    fieldContext ->
+                        fieldContexts.put(
+                            fieldContext.getFieldReference(),
+                            new FoundMissingDefinitionContextSubject(context)),
+                    methodContext ->
+                        methodContexts.put(
+                            methodContext.getMethodReference(),
+                            new FoundMissingDefinitionContextSubject(context))));
+  }
+
+  public FoundMissingDefinitionInfoSubject assertExactContexts(
+      List<MissingDefinitionContext> expectedContexts) {
+    assertEquals(expectedContexts.size(), missingDefinitionInfo.getReferencedFromContexts().size());
+    expectedContexts.forEach(
+        expectedContext ->
+            MissingDefinitionContextUtils.accept(
+                expectedContext,
+                expectedClassContext -> {
+                  FoundMissingDefinitionContextSubject subject =
+                      classContexts.get(expectedClassContext.getClassReference());
+                  assertNotNull(subject);
+                  subject.assertEqualTo(expectedClassContext);
+                },
+                expectedFieldContext -> {
+                  FoundMissingDefinitionContextSubject subject =
+                      fieldContexts.get(expectedFieldContext.getFieldReference());
+                  assertNotNull(subject);
+                  subject.assertEqualTo(expectedFieldContext);
+                },
+                expectedMethodContext -> {
+                  FoundMissingDefinitionContextSubject subject =
+                      methodContexts.get(expectedMethodContext.getMethodReference());
+                  assertNotNull(subject);
+                  subject.assertEqualTo(expectedMethodContext);
+                }));
+    return this;
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/diagnosticinspector/FoundMissingDefinitionsDiagnosticSubject.java b/src/test/java/com/android/tools/r8/diagnosticinspector/FoundMissingDefinitionsDiagnosticSubject.java
new file mode 100644
index 0000000..84e3f4b
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/diagnosticinspector/FoundMissingDefinitionsDiagnosticSubject.java
@@ -0,0 +1,96 @@
+// Copyright (c) 2021, 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.diagnosticinspector;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.ThrowableConsumer;
+import com.android.tools.r8.diagnostic.MissingClassInfo;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.MissingDefinitionInfo;
+import com.android.tools.r8.diagnostic.MissingDefinitionsDiagnostic;
+import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.references.Reference;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class FoundMissingDefinitionsDiagnosticSubject
+    extends FoundDiagnosticSubject<MissingDefinitionsDiagnostic> {
+
+  private final Map<ClassReference, MissingClassInfo> missingClasses = new HashMap<>();
+
+  public FoundMissingDefinitionsDiagnosticSubject(MissingDefinitionsDiagnostic diagnostic) {
+    super(diagnostic);
+    diagnostic.getMissingDefinitions().stream()
+        .filter(MissingDefinitionInfo::isMissingClass)
+        .map(MissingDefinitionInfo::asMissingClass)
+        .forEach(
+            missingClassInfo ->
+                missingClasses.put(missingClassInfo.getClassReference(), missingClassInfo));
+  }
+
+  public FoundMissingDefinitionsDiagnosticSubject assertHasMessage(String expectedMessage) {
+    assertEquals(expectedMessage, getDiagnostic().getDiagnosticMessage());
+    return this;
+  }
+
+  public FoundMissingDefinitionsDiagnosticSubject assertIsMissingClass(Class<?> clazz) {
+    return assertIsMissingClass(Reference.classFromClass(clazz));
+  }
+
+  public FoundMissingDefinitionsDiagnosticSubject assertIsMissingClass(
+      ClassReference classReference) {
+    assertTrue(missingClasses.containsKey(classReference));
+    return this;
+  }
+
+  public FoundMissingDefinitionsDiagnosticSubject assertIsMissingClassWithExactContexts(
+      ClassReference classReference, MissingDefinitionContext... expectedContexts) {
+    return assertIsMissingClassWithExactContexts(classReference, Arrays.asList(expectedContexts));
+  }
+
+  public FoundMissingDefinitionsDiagnosticSubject assertIsMissingClassWithExactContexts(
+      ClassReference classReference, List<MissingDefinitionContext> expectedContexts) {
+    return inspectMissingClassInfo(
+        classReference,
+        missingClassInfoSubject -> missingClassInfoSubject.assertExactContexts(expectedContexts));
+  }
+
+  public FoundMissingDefinitionsDiagnosticSubject assertNumberOfMissingClasses(int expected) {
+    assertEquals(expected, getDiagnostic().getMissingDefinitions().size());
+    return this;
+  }
+
+  public FoundMissingDefinitionsDiagnosticSubject applyIf(
+      boolean condition, ThrowableConsumer<FoundMissingDefinitionsDiagnosticSubject> thenConsumer) {
+    return applyIf(condition, thenConsumer, ThrowableConsumer.empty());
+  }
+
+  public FoundMissingDefinitionsDiagnosticSubject applyIf(
+      boolean condition,
+      ThrowableConsumer<FoundMissingDefinitionsDiagnosticSubject> thenConsumer,
+      ThrowableConsumer<FoundMissingDefinitionsDiagnosticSubject> elseConsumer) {
+    if (condition) {
+      thenConsumer.acceptWithRuntimeException(this);
+    } else {
+      elseConsumer.acceptWithRuntimeException(this);
+    }
+    return this;
+  }
+
+  public FoundMissingDefinitionsDiagnosticSubject inspectMissingClassInfo(
+      ClassReference classReference,
+      ThrowableConsumer<FoundMissingDefinitionInfoSubject> inspector) {
+    MissingDefinitionInfo missingDefinitionInfo = missingClasses.get(classReference);
+    assertNotNull(missingDefinitionInfo);
+    inspector.acceptWithRuntimeException(
+        new FoundMissingDefinitionInfoSubject(missingDefinitionInfo));
+    return this;
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/graph/GenericSignatureTest.java b/src/test/java/com/android/tools/r8/graph/GenericSignatureTest.java
index 0011245..2d1be5b 100644
--- a/src/test/java/com/android/tools/r8/graph/GenericSignatureTest.java
+++ b/src/test/java/com/android/tools/r8/graph/GenericSignatureTest.java
@@ -11,9 +11,11 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
+import com.android.tools.r8.D8TestCompileResult;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.graph.GenericSignature.ClassSignature;
 import com.android.tools.r8.graph.GenericSignature.ClassTypeSignature;
 import com.android.tools.r8.graph.GenericSignature.FieldTypeSignature;
@@ -56,7 +58,7 @@
 
   @Test
   public void test() throws Exception {
-    AndroidApp app =
+    D8TestCompileResult compileResult =
         testForD8(parameters.getBackend())
             .debug()
             .addProgramClassesAndInnerClasses(
@@ -65,8 +67,14 @@
                 GenericSignatureTestClassCY.class,
                 GenericSignatureTestClassCYY.class)
             .setMinApi(parameters.getApiLevel())
-            .compile()
-            .app;
+            .compile();
+    AndroidApp app =
+        AndroidApp.builder(compileResult.getApp())
+            .addLibraryFile(
+                parameters.isCfRuntime()
+                    ? ToolHelper.getJava8RuntimeJar()
+                    : ToolHelper.getMostRecentAndroidJar())
+            .build();
     AppView<AppInfoWithLiveness> appView = computeAppViewWithLiveness(app);
     DexItemFactory factory = appView.dexItemFactory();
     CodeInspector inspector = new CodeInspector(appView.appInfo().app());
diff --git a/src/test/java/com/android/tools/r8/graph/MissingClassThrowingTest.java b/src/test/java/com/android/tools/r8/graph/MissingClassThrowingTest.java
index 2eb88a1..5526415 100644
--- a/src/test/java/com/android/tools/r8/graph/MissingClassThrowingTest.java
+++ b/src/test/java/com/android/tools/r8/graph/MissingClassThrowingTest.java
@@ -4,8 +4,6 @@
 
 package com.android.tools.r8.graph;
 
-import static com.android.tools.r8.DiagnosticsMatcher.diagnosticType;
-import static org.junit.Assert.assertEquals;
 
 import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.NoHorizontalClassMerging;
@@ -13,7 +11,6 @@
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.TestRuntime.CfVm;
-import com.android.tools.r8.diagnostic.internal.MissingDefinitionsDiagnosticImpl;
 import com.android.tools.r8.utils.InternalOptions.TestingOptions;
 import com.android.tools.r8.utils.codeinspector.AssertUtils;
 import java.io.IOException;
@@ -82,15 +79,12 @@
                     diagnostics -> {
                       diagnostics
                           .assertOnlyErrors()
-                          .assertErrorsMatch(
-                              diagnosticType(MissingDefinitionsDiagnosticImpl.class));
-
-                      MissingDefinitionsDiagnosticImpl diagnostic =
-                          (MissingDefinitionsDiagnosticImpl) diagnostics.getErrors().get(0);
-                      assertEquals(1, diagnostic.getMissingClasses().size());
-                      assertEquals(
-                          MissingException.class.getTypeName(),
-                          diagnostic.getMissingClasses().iterator().next().getTypeName());
+                          .inspectErrors(
+                              diagnostic ->
+                                  diagnostic
+                                      .assertIsMissingDefinitionsDiagnostic()
+                                      .assertIsMissingClass(MissingException.class)
+                                      .assertNumberOfMissingClasses(1));
                     }));
   }
 }
diff --git a/src/test/java/com/android/tools/r8/internal/Regression127524985.java b/src/test/java/com/android/tools/r8/internal/Regression127524985.java
index 5fb64ea..4af8640 100644
--- a/src/test/java/com/android/tools/r8/internal/Regression127524985.java
+++ b/src/test/java/com/android/tools/r8/internal/Regression127524985.java
@@ -50,7 +50,7 @@
                 .noTreeShaking()
                 .noMinification()
                 .addKeepAllAttributes()
-                .addKeepRules("-dontwarn *"))
+                .addKeepRules("-dontwarn"))
         .addProgramFiles(JAR)
         .setMinApi(parameters.getRuntime())
         .compile()
diff --git a/src/test/java/com/android/tools/r8/ir/InlineTest.java b/src/test/java/com/android/tools/r8/ir/InlineTest.java
index c141654..909a929 100644
--- a/src/test/java/com/android/tools/r8/ir/InlineTest.java
+++ b/src/test/java/com/android/tools/r8/ir/InlineTest.java
@@ -4,11 +4,13 @@
 
 package com.android.tools.r8.ir;
 
+import static com.android.tools.r8.ToolHelper.getMostRecentAndroidJar;
 import static org.junit.Assert.assertEquals;
 
 import com.android.tools.r8.DexIndexedConsumer;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.dex.ApplicationReader;
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppServices;
 import com.android.tools.r8.graph.AppView;
@@ -19,6 +21,7 @@
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.InstructionListIterator;
+import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.shaking.Enqueuer;
 import com.android.tools.r8.shaking.EnqueuerFactory;
 import com.android.tools.r8.shaking.EnqueuerResult;
@@ -27,6 +30,7 @@
 import com.android.tools.r8.shaking.RootSetUtils.RootSet;
 import com.android.tools.r8.smali.SmaliBuilder;
 import com.android.tools.r8.smali.SmaliBuilder.MethodSignature;
+import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.Reporter;
 import com.android.tools.r8.utils.ThreadUtils;
@@ -34,6 +38,7 @@
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Sets;
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
@@ -41,6 +46,7 @@
 import java.util.Set;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
+import org.antlr.runtime.RecognitionException;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -446,6 +452,19 @@
         application, options, methodSubject, ImmutableList.of(codeA, codeB));
   }
 
+  protected DexApplication buildApplication(SmaliBuilder builder, InternalOptions options) {
+    try {
+      AndroidApp app =
+          AndroidApp.builder()
+              .addDexProgramData(builder.compile(), Origin.unknown())
+              .addLibraryFile(getMostRecentAndroidJar())
+              .build();
+      return new ApplicationReader(app, options, Timing.empty()).read();
+    } catch (IOException | RecognitionException | ExecutionException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
   private void runInlineCallerHasCatchHandlersTest(
       int a, int b, boolean twoGuards, int expectedA, int expectedB) throws Exception {
     // Run code without inlining.
diff --git a/src/test/java/com/android/tools/r8/ir/IrInjectionTestBase.java b/src/test/java/com/android/tools/r8/ir/IrInjectionTestBase.java
index 55fcc74..328f9ff 100644
--- a/src/test/java/com/android/tools/r8/ir/IrInjectionTestBase.java
+++ b/src/test/java/com/android/tools/r8/ir/IrInjectionTestBase.java
@@ -30,14 +30,6 @@
 
 public class IrInjectionTestBase extends SmaliTestBase {
 
-  protected DexApplication buildApplication(SmaliBuilder builder, InternalOptions options) {
-    try {
-      return new ApplicationReader(builder.build(), options, Timing.empty()).read();
-    } catch (IOException | RecognitionException | ExecutionException e) {
-      throw new RuntimeException(e);
-    }
-  }
-
   protected MethodSubject getMethodSubject(DexApplication application, MethodSignature signature) {
     return getMethodSubject(
         application,
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/AnalysisTestBase.java b/src/test/java/com/android/tools/r8/ir/analysis/AnalysisTestBase.java
index 6f24c38..a015fd9 100644
--- a/src/test/java/com/android/tools/r8/ir/analysis/AnalysisTestBase.java
+++ b/src/test/java/com/android/tools/r8/ir/analysis/AnalysisTestBase.java
@@ -6,6 +6,7 @@
 
 import static org.junit.Assert.fail;
 
+import com.android.tools.r8.D8TestCompileResult;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.graph.AppView;
@@ -21,33 +22,60 @@
 
 public abstract class AnalysisTestBase extends TestBase {
 
-  protected final TestParameters parameters;
+  public AppView<?> appView;
   private final AndroidApp app;
   private final String className;
-
-  public AppView<?> appView;
+  protected final TestParameters parameters;
 
   public AnalysisTestBase(TestParameters parameters, Class<?> clazz) throws Exception {
+    if (parameters.isCfRuntime()) {
+      this.app =
+          buildClassesWithTestingAnnotations(clazz)
+              .addLibraryFile(parameters.getDefaultRuntimeLibrary())
+              .build();
+    } else {
+      D8TestCompileResult compileResult =
+          testForD8()
+              .release()
+              .setMinApi(parameters.getApiLevel())
+              .addProgramClasses(clazz)
+              .addTestingAnnotationsAsProgramClasses()
+              .compile();
+      this.app =
+          AndroidApp.builder(compileResult.getApp())
+              .addLibraryFile(parameters.getDefaultRuntimeLibrary())
+              .build();
+    }
     this.parameters = parameters;
-    this.app =
-        testForD8()
-            .release()
-            .setMinApi(parameters.getRuntime())
-            .addProgramClasses(clazz)
-            .compile()
-            .app;
     this.className = clazz.getTypeName();
   }
 
+  public AnalysisTestBase(TestParameters parameters, Class<?> mainClass, Class<?>... classes)
+      throws Exception {
+    this(parameters, mainClass.getTypeName(), classes);
+  }
+
   public AnalysisTestBase(
       TestParameters parameters, String mainClassName, Class<?>... classes) throws Exception {
+    if (parameters.isCfRuntime()) {
+      this.app =
+          buildClassesWithTestingAnnotations(classes)
+              .addLibraryFile(parameters.getDefaultRuntimeLibrary())
+              .build();
+    } else {
+      D8TestCompileResult compileResult =
+          testForD8()
+              .release()
+              .setMinApi(parameters.getApiLevel())
+              .addProgramClasses(classes)
+              .addTestingAnnotationsAsProgramClasses()
+              .compile();
+      this.app =
+          AndroidApp.builder(compileResult.getApp())
+              .addLibraryFile(parameters.getDefaultRuntimeLibrary())
+              .build();
+    }
     this.parameters = parameters;
-    this.app =
-        testForD8()
-            .addProgramClasses(classes)
-            .setMinApi(parameters.getRuntime())
-            .compile()
-            .app;
     this.className = mainClassName;
   }
 
@@ -67,7 +95,7 @@
   public void buildAndCheckIR(String methodName, Consumer<IRCode> irInspector) {
     CodeInspector inspector = new CodeInspector(appView.appInfo().app());
     MethodSubject methodSubject = inspector.clazz(className).uniqueMethodWithName(methodName);
-    irInspector.accept(methodSubject.buildIR());
+    irInspector.accept(methodSubject.buildIR(appView));
   }
 
   @SuppressWarnings("unchecked")
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/DeterminismAnalysisTest.java b/src/test/java/com/android/tools/r8/ir/analysis/DeterminismAnalysisTest.java
index 5bd8472..48e0c20 100644
--- a/src/test/java/com/android/tools/r8/ir/analysis/DeterminismAnalysisTest.java
+++ b/src/test/java/com/android/tools/r8/ir/analysis/DeterminismAnalysisTest.java
@@ -18,7 +18,7 @@
 
   @Parameterized.Parameters(name = "{0}")
   public static TestParametersCollection data() {
-    return getTestParameters().withAllRuntimes().build();
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
   public DeterminismAnalysisTest(TestParameters parameters) throws Exception {
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/escape/EscapeAnalysisForNameReflectionTest.java b/src/test/java/com/android/tools/r8/ir/analysis/escape/EscapeAnalysisForNameReflectionTest.java
index 9362432..408e8d1 100644
--- a/src/test/java/com/android/tools/r8/ir/analysis/escape/EscapeAnalysisForNameReflectionTest.java
+++ b/src/test/java/com/android/tools/r8/ir/analysis/escape/EscapeAnalysisForNameReflectionTest.java
@@ -34,7 +34,7 @@
 
   @Parameterized.Parameters(name = "{0}")
   public static TestParametersCollection data() {
-    return getTestParameters().withAllRuntimes().build();
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
   public EscapeAnalysisForNameReflectionTest(TestParameters parameters) throws Exception {
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/type/ArrayTypeTest.java b/src/test/java/com/android/tools/r8/ir/analysis/type/ArrayTypeTest.java
index bdeda3c..dd3e853 100644
--- a/src/test/java/com/android/tools/r8/ir/analysis/type/ArrayTypeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/analysis/type/ArrayTypeTest.java
@@ -30,7 +30,7 @@
 
   @Parameterized.Parameters(name = "{0}")
   public static TestParametersCollection data() {
-    return getTestParameters().withAllRuntimes().build();
+    return getTestParameters().withDexRuntimes().withAllApiLevels().build();
   }
 
   public ArrayTypeTest(TestParameters parameters) throws Exception {
@@ -38,12 +38,12 @@
   }
 
   @Test
-  public void testArray() throws Exception {
+  public void testArray() {
     buildAndCheckIR("arrayTest", arrayTestInspector());
   }
 
   @Test
-  public void testNestedArray() throws Exception {
+  public void testNestedArray() {
     buildAndCheckIR("nestedArrayTest", nestedArrayTestInspector());
   }
 
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/type/ConstrainedPrimitiveTypeTest.java b/src/test/java/com/android/tools/r8/ir/analysis/type/ConstrainedPrimitiveTypeTest.java
index e421309..44de35e 100644
--- a/src/test/java/com/android/tools/r8/ir/analysis/type/ConstrainedPrimitiveTypeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/analysis/type/ConstrainedPrimitiveTypeTest.java
@@ -29,11 +29,11 @@
 
   @Parameterized.Parameters(name = "{0}")
   public static TestParametersCollection data() {
-    return getTestParameters().withAllRuntimes().withAllApiLevels().build();
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
   public ConstrainedPrimitiveTypeTest(TestParameters parameters) throws Exception {
-    super(parameters, TestClass.class);
+    super(parameters, TestClass.class, TestClass.class);
   }
 
   @Test
@@ -53,42 +53,42 @@
   }
 
   @Test
-  public void testIntWithInvokeUser() throws Exception {
+  public void testIntWithInvokeUser() {
     buildAndCheckIR("intWithInvokeUserTest", testInspector(getInt(), 1));
   }
 
   @Test
-  public void testIntWithIndirectInvokeUser() throws Exception {
+  public void testIntWithIndirectInvokeUser() {
     buildAndCheckIR("intWithIndirectInvokeUserTest", testInspector(getInt(), 2));
   }
 
   @Test
-  public void testFloatWithInvokeUser() throws Exception {
+  public void testFloatWithInvokeUser() {
     buildAndCheckIR("floatWithInvokeUserTest", testInspector(getFloat(), 1));
   }
 
   @Test
-  public void testFloatWithIndirectInvokeUser() throws Exception {
+  public void testFloatWithIndirectInvokeUser() {
     buildAndCheckIR("floatWithIndirectInvokeUserTest", testInspector(getFloat(), 2));
   }
 
   @Test
-  public void testLongWithInvokeUser() throws Exception {
+  public void testLongWithInvokeUser() {
     buildAndCheckIR("longWithInvokeUserTest", testInspector(getLong(), 1));
   }
 
   @Test
-  public void testLongWithIndirectInvokeUser() throws Exception {
+  public void testLongWithIndirectInvokeUser() {
     buildAndCheckIR("longWithIndirectInvokeUserTest", testInspector(getLong(), 2));
   }
 
   @Test
-  public void testDoubleWithInvokeUser() throws Exception {
+  public void testDoubleWithInvokeUser() {
     buildAndCheckIR("doubleWithInvokeUserTest", testInspector(getDouble(), 1));
   }
 
   @Test
-  public void testDoubleWithIndirectInvokeUser() throws Exception {
+  public void testDoubleWithIndirectInvokeUser() {
     buildAndCheckIR("doubleWithIndirectInvokeUserTest", testInspector(getDouble(), 2));
   }
 
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/type/NullabilityTest.java b/src/test/java/com/android/tools/r8/ir/analysis/type/NullabilityTest.java
index 3a6f0e4..1769dc9 100644
--- a/src/test/java/com/android/tools/r8/ir/analysis/type/NullabilityTest.java
+++ b/src/test/java/com/android/tools/r8/ir/analysis/type/NullabilityTest.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.ir.analysis.type;
 
+import static com.android.tools.r8.ToolHelper.getMostRecentAndroidJar;
 import static com.android.tools.r8.ir.analysis.type.Nullability.definitelyNotNull;
 import static com.android.tools.r8.ir.analysis.type.Nullability.maybeNull;
 import static com.android.tools.r8.ir.analysis.type.TypeElement.fromDexType;
@@ -11,6 +12,7 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
+import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.graph.AppView;
@@ -26,7 +28,6 @@
 import com.android.tools.r8.ir.code.NewInstance;
 import com.android.tools.r8.ir.code.Value;
 import com.android.tools.r8.ir.optimize.AssumeInserter;
-import com.android.tools.r8.ir.optimize.NonNullTrackerTestBase;
 import com.android.tools.r8.ir.optimize.nonnull.FieldAccessTest;
 import com.android.tools.r8.ir.optimize.nonnull.NonNullAfterArrayAccess;
 import com.android.tools.r8.ir.optimize.nonnull.NonNullAfterFieldAccess;
@@ -37,7 +38,9 @@
 import com.android.tools.r8.utils.Timing;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+import java.util.Collection;
 import java.util.Map;
 import java.util.function.BiConsumer;
 import org.junit.Test;
@@ -46,7 +49,7 @@
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
-public class NullabilityTest extends NonNullTrackerTestBase {
+public class NullabilityTest extends TestBase {
 
   @Parameters(name = "{0}")
   public static TestParametersCollection data() {
@@ -58,12 +61,15 @@
   }
 
   private void buildAndTest(
+      Collection<Class<?>> classes,
       Class<?> mainClass,
       MethodSignature signature,
       boolean npeCaught,
       BiConsumer<AppView<?>, IRCode> inspector)
       throws Exception {
-    AppView<AppInfoWithLiveness> appView = build(mainClass);
+    AppView<AppInfoWithLiveness> appView =
+        computeAppViewWithLiveness(
+            buildClasses(classes).addLibraryFile(getMostRecentAndroidJar()).build());
     CodeInspector codeInspector = new CodeInspector(appView.appInfo().app());
     MethodSubject fooSubject = codeInspector.clazz(mainClass.getName()).method(signature);
     IRCode irCode = fooSubject.buildIR();
@@ -131,6 +137,7 @@
     MethodSignature signature =
         new MethodSignature("foo", "int", new String[]{"java.lang.String"});
     buildAndTest(
+        ImmutableList.of(NonNullAfterInvoke.class),
         NonNullAfterInvoke.class,
         signature,
         false,
@@ -158,6 +165,7 @@
     MethodSignature signature =
         new MethodSignature("bar", "int", new String[]{"java.lang.String"});
     buildAndTest(
+        ImmutableList.of(NonNullAfterInvoke.class),
         NonNullAfterInvoke.class,
         signature,
         true,
@@ -185,6 +193,7 @@
     MethodSignature signature =
         new MethodSignature("foo", "int", new String[]{"java.lang.String[]"});
     buildAndTest(
+        ImmutableList.of(NonNullAfterArrayAccess.class),
         NonNullAfterArrayAccess.class,
         signature,
         false,
@@ -227,6 +236,7 @@
     MethodSignature signature =
         new MethodSignature("bar", "int", new String[]{"java.lang.String[]"});
     buildAndTest(
+        ImmutableList.of(NonNullAfterArrayAccess.class),
         NonNullAfterArrayAccess.class,
         signature,
         true,
@@ -269,6 +279,7 @@
     MethodSignature signature = new MethodSignature("foo", "int",
         new String[]{FieldAccessTest.class.getCanonicalName()});
     buildAndTest(
+        ImmutableList.of(FieldAccessTest.class, NonNullAfterFieldAccess.class),
         NonNullAfterFieldAccess.class,
         signature,
         false,
@@ -305,6 +316,7 @@
     MethodSignature signature = new MethodSignature("bar", "int",
         new String[]{FieldAccessTest.class.getCanonicalName()});
     buildAndTest(
+        ImmutableList.of(FieldAccessTest.class, NonNullAfterFieldAccess.class),
         NonNullAfterFieldAccess.class,
         signature,
         true,
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/type/TypeConstraintOnTrivialPhiTest.java b/src/test/java/com/android/tools/r8/ir/analysis/type/TypeConstraintOnTrivialPhiTest.java
index 9fb2f9b..609b2c9 100644
--- a/src/test/java/com/android/tools/r8/ir/analysis/type/TypeConstraintOnTrivialPhiTest.java
+++ b/src/test/java/com/android/tools/r8/ir/analysis/type/TypeConstraintOnTrivialPhiTest.java
@@ -8,11 +8,13 @@
 
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.ir.analysis.AnalysisTestBase;
 import com.android.tools.r8.ir.code.ConstNumber;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.Instruction;
+import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.smali.SmaliBuilder;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.StringUtils;
@@ -85,26 +87,29 @@
               "goto :label_1");
       smaliBuilder.addStaticMethod("void", config.getTestName(), ImmutableList.of("int"), 4, code);
     }
-    return smaliBuilder.build();
+    return AndroidApp.builder()
+        .addDexProgramData(smaliBuilder.compile(), Origin.unknown())
+        .addLibraryFile(ToolHelper.getMostRecentAndroidJar())
+        .build();
   }
 
   @Test
-  public void testIntConstraintOnTrivialPhi() throws Exception {
+  public void testIntConstraintOnTrivialPhi() {
     buildAndCheckIR("intConstraintOnTrivialPhiTest", testInspector(TypeElement.getInt()));
   }
 
   @Test
-  public void testFloatConstraintOnTrivialPhi() throws Exception {
+  public void testFloatConstraintOnTrivialPhi() {
     buildAndCheckIR("floatConstraintOnTrivialPhiTest", testInspector(TypeElement.getFloat()));
   }
 
   @Test
-  public void testLongConstraintOnTrivialPhi() throws Exception {
+  public void testLongConstraintOnTrivialPhi() {
     buildAndCheckIR("longConstraintOnTrivialPhiTest", testInspector(TypeElement.getLong()));
   }
 
   @Test
-  public void testDoubleConstraintOnTrivialPhi() throws Exception {
+  public void testDoubleConstraintOnTrivialPhi() {
     buildAndCheckIR("doubleConstraintOnTrivialPhiTest", testInspector(TypeElement.getDouble()));
   }
 
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/type/UnconstrainedPrimitiveTypeTest.java b/src/test/java/com/android/tools/r8/ir/analysis/type/UnconstrainedPrimitiveTypeTest.java
index 961827a..d0b9c70 100644
--- a/src/test/java/com/android/tools/r8/ir/analysis/type/UnconstrainedPrimitiveTypeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/analysis/type/UnconstrainedPrimitiveTypeTest.java
@@ -8,15 +8,16 @@
 
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.ir.analysis.AnalysisTestBase;
 import com.android.tools.r8.ir.code.ConstNumber;
 import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.Instruction;
+import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.smali.SmaliBuilder;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.StringUtils;
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Streams;
 import java.util.function.Consumer;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -27,7 +28,7 @@
 
   @Parameterized.Parameters(name = "{0}")
   public static TestParametersCollection data() {
-    return getTestParameters().withAllRuntimes().build();
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
   public UnconstrainedPrimitiveTypeTest(TestParameters parameters) throws Exception {
@@ -81,32 +82,35 @@
           "void", "unconstrainedWideWithIfUserTest", ImmutableList.of(), 4, code);
     }
 
-    return smaliBuilder.build();
+    return AndroidApp.builder()
+        .addDexProgramData(smaliBuilder.compile(), Origin.unknown())
+        .addLibraryFile(ToolHelper.getMostRecentAndroidJar())
+        .build();
   }
 
   @Test
-  public void testUnconstrainedSingleWithNoUsers() throws Exception {
+  public void testUnconstrainedSingleWithNoUsers() {
     buildAndCheckIR("unconstrainedSingleWithNoUsersTest", testInspector(TypeElement.getInt(), 1));
   }
 
   @Test
-  public void testUnconstrainedSingleWithIfUser() throws Exception {
+  public void testUnconstrainedSingleWithIfUser() {
     buildAndCheckIR("unconstrainedSingleWithIfUserTest", testInspector(TypeElement.getInt(), 2));
   }
 
   @Test
-  public void testUnconstrainedSingleWithIfZeroUser() throws Exception {
+  public void testUnconstrainedSingleWithIfZeroUser() {
     buildAndCheckIR(
         "unconstrainedSingleWithIfZeroUserTest", testInspector(IntTypeElement.getInt(), 1));
   }
 
   @Test
-  public void testUnconstrainedWideWithNoUsers() throws Exception {
+  public void testUnconstrainedWideWithNoUsers() {
     buildAndCheckIR("unconstrainedWideWithNoUsersTest", testInspector(TypeElement.getLong(), 1));
   }
 
   @Test
-  public void testUnconstrainedWideWithIfUser() throws Exception {
+  public void testUnconstrainedWideWithIfUser() {
     buildAndCheckIR("unconstrainedWideWithIfUserTest", testInspector(TypeElement.getLong(), 2));
   }
 
@@ -122,7 +126,7 @@
 
       assertEquals(
           expectedNumberOfConstNumberInstructions,
-          Streams.stream(code.instructionIterator()).filter(Instruction::isConstNumber).count());
+          code.streamInstructions().filter(Instruction::isConstNumber).count());
     };
   }
 }
diff --git a/src/test/java/com/android/tools/r8/ir/conversion/PartialCallGraphTest.java b/src/test/java/com/android/tools/r8/ir/conversion/PartialCallGraphTest.java
index 41c5ef5..009d4e3d 100644
--- a/src/test/java/com/android/tools/r8/ir/conversion/PartialCallGraphTest.java
+++ b/src/test/java/com/android/tools/r8/ir/conversion/PartialCallGraphTest.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.ir.conversion;
 
+import static com.android.tools.r8.ToolHelper.getMostRecentAndroidJar;
 import static com.android.tools.r8.shaking.ProguardConfigurationSourceStrings.createConfigurationForTesting;
 import static org.hamcrest.CoreMatchers.hasItem;
 import static org.hamcrest.MatcherAssert.assertThat;
@@ -35,7 +36,10 @@
   private final ExecutorService executorService;
 
   public PartialCallGraphTest() throws Exception {
-    AndroidApp app = testForD8().addProgramClasses(TestClass.class).compile().app;
+    AndroidApp app =
+        AndroidApp.builder(testForD8().addProgramClasses(TestClass.class).compile().getApp())
+            .addLibraryFile(getMostRecentAndroidJar())
+            .build();
     this.appView =
         computeAppViewWithLiveness(
             app,
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTest.java b/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTest.java
index f5431bb..19ff50d 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTest.java
@@ -3,10 +3,12 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.ir.optimize;
 
+import static com.android.tools.r8.ToolHelper.getMostRecentAndroidJar;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
+import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.graph.AppView;
@@ -25,6 +27,8 @@
 import com.android.tools.r8.utils.Timing;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import com.google.common.collect.ImmutableList;
+import java.util.List;
 import java.util.function.Consumer;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -32,7 +36,7 @@
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
-public class NonNullTrackerTest extends NonNullTrackerTestBase {
+public class NonNullTrackerTest extends TestBase {
 
   @Parameters(name = "{0}")
   public static TestParametersCollection data() {
@@ -44,12 +48,15 @@
   }
 
   private void buildAndTest(
+      List<Class<?>> classes,
       Class<?> testClass,
       MethodSignature signature,
       int expectedNumberOfNonNull,
       Consumer<IRCode> testAugmentedIRCode)
       throws Exception {
-    AppView<AppInfoWithLiveness> appView = build(testClass);
+    AppView<AppInfoWithLiveness> appView =
+        computeAppViewWithLiveness(
+            buildClasses(classes).addLibraryFile(getMostRecentAndroidJar()).build());
     CodeInspector codeInspector = new CodeInspector(appView.appInfo().app());
     MethodSubject fooSubject = codeInspector.clazz(testClass.getName()).method(signature);
     IRCode code = fooSubject.buildIR();
@@ -127,31 +134,56 @@
   public void nonNullAfterSafeInvokes() throws Exception {
     MethodSignature foo =
         new MethodSignature("foo", "int", new String[]{"java.lang.String"});
-    buildAndTest(NonNullAfterInvoke.class, foo, 1, this::checkInvokeGetsNonNullReceiver);
+    buildAndTest(
+        ImmutableList.of(NonNullAfterInvoke.class),
+        NonNullAfterInvoke.class,
+        foo,
+        1,
+        this::checkInvokeGetsNonNullReceiver);
     MethodSignature bar =
         new MethodSignature("bar", "int", new String[]{"java.lang.String"});
-    buildAndTest(NonNullAfterInvoke.class, bar, 2, this::checkInvokeGetsNullReceiver);
+    buildAndTest(
+        ImmutableList.of(NonNullAfterInvoke.class),
+        NonNullAfterInvoke.class,
+        bar,
+        2,
+        this::checkInvokeGetsNullReceiver);
   }
 
   @Test
   public void nonNullAfterSafeArrayAccess() throws Exception {
     MethodSignature foo =
         new MethodSignature("foo", "int", new String[]{"java.lang.String[]"});
-    buildAndTest(NonNullAfterArrayAccess.class, foo, 1, null);
+    buildAndTest(
+        ImmutableList.of(NonNullAfterArrayAccess.class),
+        NonNullAfterArrayAccess.class,
+        foo,
+        1,
+        null);
   }
 
   @Test
   public void nonNullAfterSafeArrayLength() throws Exception {
     MethodSignature signature =
         new MethodSignature("arrayLength", "int", new String[]{"java.lang.String[]"});
-    buildAndTest(NonNullAfterArrayAccess.class, signature, 1, null);
+    buildAndTest(
+        ImmutableList.of(NonNullAfterArrayAccess.class),
+        NonNullAfterArrayAccess.class,
+        signature,
+        1,
+        null);
   }
 
   @Test
   public void nonNullAfterSafeFieldAccess() throws Exception {
     MethodSignature foo = new MethodSignature("foo", "int",
         new String[]{FieldAccessTest.class.getCanonicalName()});
-    buildAndTest(NonNullAfterFieldAccess.class, foo, 1, null);
+    buildAndTest(
+        ImmutableList.of(FieldAccessTest.class, NonNullAfterFieldAccess.class),
+        NonNullAfterFieldAccess.class,
+        foo,
+        1,
+        null);
   }
 
   @Test
@@ -159,6 +191,7 @@
     MethodSignature signature = new MethodSignature("foo2", "int",
         new String[]{FieldAccessTest.class.getCanonicalName()});
     buildAndTest(
+        ImmutableList.of(FieldAccessTest.class, NonNullAfterFieldAccess.class),
         NonNullAfterFieldAccess.class,
         signature,
         1,
@@ -191,12 +224,27 @@
   public void nonNullAfterNullCheck() throws Exception {
     MethodSignature foo =
         new MethodSignature("foo", "int", new String[]{"java.lang.String"});
-    buildAndTest(NonNullAfterNullCheck.class, foo, 1, this::checkInvokeGetsNonNullReceiver);
+    buildAndTest(
+        ImmutableList.of(NonNullAfterNullCheck.class),
+        NonNullAfterNullCheck.class,
+        foo,
+        1,
+        this::checkInvokeGetsNonNullReceiver);
     MethodSignature bar =
         new MethodSignature("bar", "int", new String[]{"java.lang.String"});
-    buildAndTest(NonNullAfterNullCheck.class, bar, 1, this::checkInvokeGetsNonNullReceiver);
+    buildAndTest(
+        ImmutableList.of(NonNullAfterNullCheck.class),
+        NonNullAfterNullCheck.class,
+        bar,
+        1,
+        this::checkInvokeGetsNonNullReceiver);
     MethodSignature baz =
         new MethodSignature("baz", "int", new String[]{"java.lang.String"});
-    buildAndTest(NonNullAfterNullCheck.class, baz, 2, this::checkInvokeGetsNullReceiver);
+    buildAndTest(
+        ImmutableList.of(NonNullAfterNullCheck.class),
+        NonNullAfterNullCheck.class,
+        baz,
+        2,
+        this::checkInvokeGetsNullReceiver);
   }
 }
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTestBase.java b/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTestBase.java
deleted file mode 100644
index 7d5e23e..0000000
--- a/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTestBase.java
+++ /dev/null
@@ -1,16 +0,0 @@
-// 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 com.android.tools.r8.ir.optimize;
-
-import com.android.tools.r8.TestBase;
-import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
-
-public abstract class NonNullTrackerTestBase extends TestBase {
-
-  protected AppView<AppInfoWithLiveness> build(Class<?> mainClass) throws Exception {
-    return computeAppViewWithLiveness(buildAndroidApp(ToolHelper.getClassAsBytes(mainClass)));
-  }
-}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/Regress131349148.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/Regress131349148.java
index 235aa07..68991bd 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/Regress131349148.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/Regress131349148.java
@@ -4,7 +4,6 @@
 
 package com.android.tools.r8.ir.optimize.inliner;
 
-import static org.hamcrest.CoreMatchers.containsString;
 import static org.junit.Assert.assertEquals;
 
 import com.android.tools.r8.R8TestRunResult;
@@ -64,11 +63,9 @@
                 ClassWithCatchNonExisting.class,
                 ExistingException.class)
             .addKeepMainRule(TestClassCallingMethodWithNonExisting.class)
-            .addKeepRules("-dontwarn " + NonExistingException.class.getTypeName())
+            .addDontWarn(NonExistingException.class)
             .setMinApi(parameters.getApiLevel())
             .compile()
-            .assertAllWarningMessagesMatch(
-                containsString("required for default or static interface methods desugaring"))
             .run(parameters.getRuntime(), TestClassCallingMethodWithNonExisting.class)
             .assertSuccess();
     ClassSubject classSubject =
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/nonnull/NullCheckWithCatchHandlerTest.java b/src/test/java/com/android/tools/r8/ir/optimize/nonnull/NullCheckWithCatchHandlerTest.java
new file mode 100644
index 0000000..3e58794
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/nonnull/NullCheckWithCatchHandlerTest.java
@@ -0,0 +1,56 @@
+// Copyright (c) 2021, 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.nonnull;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class NullCheckWithCatchHandlerTest extends TestBase {
+
+  private final TestParameters parameters;
+
+  @Parameterized.Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  public NullCheckWithCatchHandlerTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Test
+  public void test() throws Exception {
+    testForR8(parameters.getBackend())
+        .addProgramClasses(Main.class)
+        .addKeepMainRule(Main.class)
+        .setMinApi(parameters.getApiLevel())
+        .compile()
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithEmptyOutput();
+  }
+
+  static class Main {
+
+    public static void main(String[] args) {
+      Object alwaysNull = System.currentTimeMillis() > 0 ? null : new Object();
+      notNullCheck(alwaysNull);
+      if (alwaysNull != null) {
+        System.out.println(alwaysNull.toString());
+      }
+    }
+
+    private static void notNullCheck(Object o) {
+      try {
+        o.getClass();
+      } catch (Throwable e) {
+      }
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/outliner/b111893131/B111893131.java b/src/test/java/com/android/tools/r8/ir/optimize/outliner/b111893131/B111893131.java
index ed54024..5db4d92 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/outliner/b111893131/B111893131.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/outliner/b111893131/B111893131.java
@@ -62,7 +62,6 @@
   }
 }
 
-@RunWith(VmTestRunner.class)
 public class B111893131 extends TestBase {
 
   @Test
@@ -109,5 +108,4 @@
       }
     }
   }
-
 }
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/redundantfieldloadelimination/InstanceFieldLoadsSeparatedByInvokeCustomTest.java b/src/test/java/com/android/tools/r8/ir/optimize/redundantfieldloadelimination/InstanceFieldLoadsSeparatedByInvokeCustomTest.java
index 730c399..974a4fc 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/redundantfieldloadelimination/InstanceFieldLoadsSeparatedByInvokeCustomTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/redundantfieldloadelimination/InstanceFieldLoadsSeparatedByInvokeCustomTest.java
@@ -46,7 +46,6 @@
         .addKeepAllClassesRule()
         .setMinApi(parameters.getApiLevel())
         .compile()
-        .assertAllWarningMessagesMatch(containsString("Unknown bootstrap method"))
         .run(parameters.getRuntime(), "InstanceFieldLoadsSeparatedByInvokeCustomTestClass")
         .assertSuccess();
   }
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/string/StringBuilderOptimizerAnalysisSmaliTest.java b/src/test/java/com/android/tools/r8/ir/optimize/string/StringBuilderOptimizerAnalysisSmaliTest.java
index 7ddb3bc..8552e48 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/string/StringBuilderOptimizerAnalysisSmaliTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/string/StringBuilderOptimizerAnalysisSmaliTest.java
@@ -9,10 +9,12 @@
 
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.ir.analysis.AnalysisTestBase;
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.Value;
 import com.android.tools.r8.ir.optimize.string.StringBuilderOptimizer.BuilderState;
+import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.smali.SmaliBuilder;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.StringUtils;
@@ -26,7 +28,7 @@
 public class StringBuilderOptimizerAnalysisSmaliTest extends AnalysisTestBase {
   @Parameterized.Parameters(name = "{0}")
   public static TestParametersCollection data() {
-    return getTestParameters().withAllRuntimes().build();
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
   }
 
   public StringBuilderOptimizerAnalysisSmaliTest(TestParameters parameters) throws Exception {
@@ -61,7 +63,7 @@
               "sget-object v2, Ljava/lang/System;->out:Ljava/io/PrintStream;",
               "invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;",
               "move-result-object v1",
-              "invoke-virtual {v2, v1}, Ljava/io/Stream;->println(Ljava/lang/String;)V",
+              "invoke-virtual {v2, v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V",
               "return-void");
       smaliBuilder.addStaticMethod(
           "void", "phiAtInit_5_1_1", ImmutableList.of(), 5, code);
@@ -93,7 +95,7 @@
               "sget-object v2, Ljava/lang/System;->out:Ljava/io/PrintStream;",
               "invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;",
               "move-result-object v1",
-              "invoke-virtual {v2, v1}, Ljava/io/Stream;->println(Ljava/lang/String;)V",
+              "invoke-virtual {v2, v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V",
               "return-void");
       smaliBuilder.addStaticMethod(
           "void", "phiWithDifferentNewInstance", ImmutableList.of(), 5, code);
@@ -125,17 +127,20 @@
               "sget-object v2, Ljava/lang/System;->out:Ljava/io/PrintStream;",
               "invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;",
               "move-result-object v1",
-              "invoke-virtual {v2, v1}, Ljava/io/Stream;->println(Ljava/lang/String;)V",
+              "invoke-virtual {v2, v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V",
               "return-void");
       smaliBuilder.addStaticMethod(
           "void", "phiAtInit", ImmutableList.of(), 5, code);
     }
 
-    return smaliBuilder.build();
+    return AndroidApp.builder()
+        .addDexProgramData(smaliBuilder.compile(), Origin.unknown())
+        .addLibraryFile(ToolHelper.getMostRecentAndroidJar())
+        .build();
   }
 
   @Test
-  public void testPhiAtInit_5_1_1() throws Exception {
+  public void testPhiAtInit_5_1_1() {
     buildAndCheckIR(
         "phiAtInit_5_1_1",
         checkOptimizerStates(appView, optimizer -> {
@@ -150,7 +155,7 @@
   }
 
   @Test
-  public void testPhiWithDifferentNewInstance() throws Exception {
+  public void testPhiWithDifferentNewInstance() {
     buildAndCheckIR(
         "phiWithDifferentNewInstance",
         checkOptimizerStates(appView, optimizer -> {
@@ -165,7 +170,7 @@
   }
 
   @Test
-  public void testPhiAtInit() throws Exception {
+  public void testPhiAtInit() {
     buildAndCheckIR(
         "phiAtInit",
         checkOptimizerStates(appView, optimizer -> {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/string/StringBuilderOptimizerAnalysisTest.java b/src/test/java/com/android/tools/r8/ir/optimize/string/StringBuilderOptimizerAnalysisTest.java
index eaa9941..e18c8ea 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/string/StringBuilderOptimizerAnalysisTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/string/StringBuilderOptimizerAnalysisTest.java
@@ -9,7 +9,6 @@
 
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.ToolHelper.DexVm;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.ir.analysis.AnalysisTestBase;
 import com.android.tools.r8.ir.code.IRCode;
@@ -17,6 +16,7 @@
 import com.android.tools.r8.ir.code.InvokeMethod;
 import com.android.tools.r8.ir.code.Value;
 import com.android.tools.r8.ir.optimize.string.StringBuilderOptimizer.BuilderState;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.InternalOptions;
 import java.util.HashSet;
 import java.util.Map;
@@ -32,7 +32,7 @@
 
   @Parameterized.Parameters(name = "{0}")
   public static TestParametersCollection data() {
-    return getTestParameters().withAllRuntimes().build();
+    return getTestParameters().withDexRuntimes().withAllApiLevels().build();
   }
 
   public StringBuilderOptimizerAnalysisTest(TestParameters parameters) throws Exception {
@@ -49,16 +49,7 @@
   public void testUnusedBuilder() {
     buildAndCheckIR(
         "unusedBuilder",
-        checkOptimizerStates(appView, optimizer -> {
-          assertEquals(1, optimizer.analysis.builderStates.size());
-          for (Value builder : optimizer.analysis.builderStates.keySet()) {
-            Map<Instruction, BuilderState> perBuilderState =
-                optimizer.analysis.builderStates.get(builder);
-            checkBuilderState(optimizer, perBuilderState, "42", true);
-          }
-          assertEquals(1, optimizer.analysis.deadBuilders.size());
-          assertEquals(0, optimizer.analysis.simplifiedBuilders.size());
-        }));
+        code -> assertTrue(code.streamInstructions().allMatch(Instruction::isReturn)));
   }
 
   @Test
@@ -276,8 +267,7 @@
   public void testPhiAtInit() {
     int expectedNumOfNewBuilder = 2;
     boolean expectToMeetToString = false;
-    if (parameters.isDexRuntime()
-        && parameters.getRuntime().asDex().getVm().isOlderThanOrEqual(DexVm.ART_5_1_1_HOST)) {
+    if (parameters.isDexRuntime() && parameters.getApiLevel().isLessThan(AndroidApiLevel.M)) {
       expectedNumOfNewBuilder = 1;
       expectToMeetToString = true;
     }
@@ -315,15 +305,17 @@
   public void testConditionalPhiWithoutAppend() {
     buildAndCheckIR(
         "conditionalPhiWithoutAppend",
-        checkOptimizerStates(appView, optimizer -> {
-          assertEquals(1, optimizer.analysis.builderStates.size());
-          for (Value builder : optimizer.analysis.builderStates.keySet()) {
-            Map<Instruction, BuilderState> perBuilderState =
-                optimizer.analysis.builderStates.get(builder);
-            checkBuilderState(optimizer, perBuilderState, null, true);
-          }
-          assertEquals(0, optimizer.analysis.simplifiedBuilders.size());
-        }));
+        checkOptimizerStates(
+            appView,
+            optimizer -> {
+              assertEquals(1, optimizer.analysis.builderStates.size());
+              for (Value builder : optimizer.analysis.builderStates.keySet()) {
+                Map<Instruction, BuilderState> perBuilderState =
+                    optimizer.analysis.builderStates.get(builder);
+                checkBuilderState(optimizer, perBuilderState, "initial:suffix", true);
+              }
+              assertEquals(1, optimizer.analysis.simplifiedBuilders.size());
+            }));
   }
 
   @Test
diff --git a/src/test/java/com/android/tools/r8/jsr45/JSR45Tests.java b/src/test/java/com/android/tools/r8/jsr45/JSR45Tests.java
index 0d96a65..cdc4346 100644
--- a/src/test/java/com/android/tools/r8/jsr45/JSR45Tests.java
+++ b/src/test/java/com/android/tools/r8/jsr45/JSR45Tests.java
@@ -3,9 +3,14 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.jsr45;
 
+import static com.android.tools.r8.ToolHelper.getDefaultAndroidJar;
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
+import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
+
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.D8;
 import com.android.tools.r8.D8Command;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
 import com.android.tools.r8.OutputMode;
 import com.android.tools.r8.R8Command;
 import com.android.tools.r8.ToolHelper;
@@ -64,7 +69,10 @@
     return ToolHelper.runR8(
         R8Command.builder()
             .addProgramFiles(inputPath)
-            .addLibraryFiles(ToolHelper.getDefaultAndroidJar())
+            .addProgramFiles(
+                getKotlinStdlibJar(KotlinCompiler.latest()),
+                getKotlinAnnotationJar(KotlinCompiler.latest()))
+            .addLibraryFiles(getDefaultAndroidJar())
             .setOutput(outputPath, OutputMode.DexIndexed)
             .addProguardConfigurationFiles(keepRulesPath)
             .build());
diff --git a/src/test/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java b/src/test/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java
index 33848bb..a4b4d35 100644
--- a/src/test/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java
+++ b/src/test/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.kotlin;
 
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static org.hamcrest.CoreMatchers.containsString;
 import static org.hamcrest.CoreMatchers.not;
@@ -233,6 +234,7 @@
     classpath.clear();
     classpath.add(kotlinJarFile);
     classpath.add(getJavaJarFile(folder));
+    classpath.add(getKotlinAnnotationJar(kotlinc));
     classpath.addAll(extraClasspath);
 
     // Compare with Java.
diff --git a/src/test/java/com/android/tools/r8/kotlin/KotlinClassInlinerTest.java b/src/test/java/com/android/tools/r8/kotlin/KotlinClassInlinerTest.java
index 3b554fd..16413e0 100644
--- a/src/test/java/com/android/tools/r8/kotlin/KotlinClassInlinerTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/KotlinClassInlinerTest.java
@@ -13,7 +13,6 @@
 
 import com.android.tools.r8.KotlinTestParameters;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestShrinkerBuilder;
 import com.android.tools.r8.code.NewInstance;
 import com.android.tools.r8.code.SgetObject;
 import com.android.tools.r8.graph.DexClass;
@@ -83,7 +82,6 @@
                 testBuilder
                     // TODO(jsjeon): Introduce @NeverInline to kotlinR8TestResources
                     .addKeepRules("-neverinline class * { void test*State*(...); }")
-                    .addDontWarnJetBrainsNotNullAnnotation()
                     .addHorizontallyMergedClassesInspector(
                         inspector ->
                             inspector
@@ -115,8 +113,7 @@
             testBuilder ->
                 testBuilder
                     // TODO(jsjeon): Introduce @NeverInline to kotlinR8TestResources
-                    .addKeepRules("-neverinline class * { void test*State*(...); }")
-                    .addDontWarnJetBrainsNotNullAnnotation())
+                    .addKeepRules("-neverinline class * { void test*State*(...); }"))
         .inspect(
             inspector -> {
               // TODO(b/173337498): MainKt$testStateless$1 should be class inlined.
@@ -144,7 +141,6 @@
                         "-neverinline class * { void test*State*(...); }",
                         "-neverinline class * { void testBigExtraMethod(...); }",
                         "-neverinline class * { void testBigExtraMethodReturningLambda(...); }")
-                    .addDontWarnJetBrainsAnnotations()
                     .addHorizontallyMergedClassesInspector(
                         inspector ->
                             inspector.assertIsCompleteMergeGroup(
@@ -177,10 +173,9 @@
                 testBuilder
                     // TODO(jsjeon): Introduce @NeverInline to kotlinR8TestResources
                     .addKeepRules(
-                        "-neverinline class * { void test*State*(...); }",
-                        "-neverinline class * { void testBigExtraMethod(...); }",
-                        "-neverinline class * { void testBigExtraMethodReturningLambda(...); }")
-                    .addDontWarnJetBrainsAnnotations())
+                    "-neverinline class * { void test*State*(...); }",
+                    "-neverinline class * { void testBigExtraMethod(...); }",
+                    "-neverinline class * { void testBigExtraMethodReturningLambda(...); }"))
         .inspect(
             inspector -> {
               // TODO(b/173337498): Should be absent, but horizontal class merging interferes with
@@ -210,10 +205,7 @@
     // TODO(b/179866251): Update tests.
     assumeTrue(kotlinc.is(KOTLINC_1_3_72) && testParameters.isDexRuntime());
     String mainClassName = "class_inliner_data_class.MainKt";
-    runTest(
-            "class_inliner_data_class",
-            mainClassName,
-            TestShrinkerBuilder::addDontWarnJetBrainsAnnotations)
+    runTest("class_inliner_data_class", mainClassName)
         .inspect(
             inspector -> {
               ClassSubject clazz = inspector.clazz(mainClassName);
diff --git a/src/test/java/com/android/tools/r8/kotlin/KotlinClassStaticizerTest.java b/src/test/java/com/android/tools/r8/kotlin/KotlinClassStaticizerTest.java
index ecf67ae..1b96692 100644
--- a/src/test/java/com/android/tools/r8/kotlin/KotlinClassStaticizerTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/KotlinClassStaticizerTest.java
@@ -82,7 +82,6 @@
         mainClass,
         testBuilder ->
             testBuilder
-                .addDontWarnJetBrainsNotNullAnnotation()
                 .noClassInlining()
                 .noClassStaticizing(noClassStaticizing));
   }
diff --git a/src/test/java/com/android/tools/r8/kotlin/KotlinIntrinsicsInlineTest.java b/src/test/java/com/android/tools/r8/kotlin/KotlinIntrinsicsInlineTest.java
index 068ac79..b76eaa0 100644
--- a/src/test/java/com/android/tools/r8/kotlin/KotlinIntrinsicsInlineTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/KotlinIntrinsicsInlineTest.java
@@ -4,7 +4,9 @@
 package com.android.tools.r8.kotlin;
 
 import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.KOTLINC_1_3_72;
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.CoreMatchers.equalTo;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assume.assumeTrue;
@@ -55,15 +57,18 @@
     // TODO(b/179866251): Update tests.
     assumeTrue(kotlinc.is(KOTLINC_1_3_72) || allowAccessModification);
     testForR8(parameters.getBackend())
-        .addProgramFiles(compiledJars.getForConfiguration(kotlinc, targetVersion))
+        .addProgramFiles(
+            compiledJars.getForConfiguration(kotlinc, targetVersion),
+            getKotlinAnnotationJar(kotlinc))
         .addKeepRules(
             StringUtils.lines(
                 "-keepclasseswithmembers class " + MAIN + "{", "  public static *** *(...);", "}"))
         .allowAccessModification(allowAccessModification)
-        .addDontWarnJetBrainsNotNullAnnotation()
+        .allowDiagnosticWarningMessages()
         .noMinification()
-        .setMinApi(parameters.getRuntime())
+        .setMinApi(parameters.getApiLevel())
         .compile()
+        .assertAllWarningMessagesMatch(equalTo("Resource 'META-INF/MANIFEST.MF' already exists."))
         .inspect(
             inspector -> {
               ClassSubject main = inspector.clazz(MAIN);
@@ -103,17 +108,20 @@
 
   private void testSingle(String methodName) throws Exception {
     testForR8(parameters.getBackend())
-        .addProgramFiles(compiledJars.getForConfiguration(kotlinc, targetVersion))
+        .addProgramFiles(
+            compiledJars.getForConfiguration(kotlinc, targetVersion),
+            getKotlinAnnotationJar(kotlinc))
         .addKeepRules(
             StringUtils.lines(
                 "-keepclasseswithmembers class " + MAIN + "{",
                 "  public static *** " + methodName + "(...);",
                 "}"))
-        .addDontWarnJetBrainsNotNullAnnotation()
         .allowAccessModification(allowAccessModification)
+        .allowDiagnosticWarningMessages()
         .noMinification()
-        .setMinApi(parameters.getRuntime())
+        .setMinApi(parameters.getApiLevel())
         .compile()
+        .assertAllWarningMessagesMatch(equalTo("Resource 'META-INF/MANIFEST.MF' already exists."))
         .inspect(
             inspector -> {
               ClassSubject main = inspector.clazz(MAIN);
diff --git a/src/test/java/com/android/tools/r8/kotlin/KotlinUnusedArgumentsInLambdasTest.java b/src/test/java/com/android/tools/r8/kotlin/KotlinUnusedArgumentsInLambdasTest.java
index e928379..4db441f 100644
--- a/src/test/java/com/android/tools/r8/kotlin/KotlinUnusedArgumentsInLambdasTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/KotlinUnusedArgumentsInLambdasTest.java
@@ -10,7 +10,6 @@
 
 import com.android.tools.r8.KotlinTestParameters;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestShrinkerBuilder;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
 import com.google.common.collect.ImmutableList;
@@ -40,10 +39,7 @@
   @Test
   public void testMergingKStyleLambdasAfterUnusedArgumentRemoval() throws Exception {
     final String mainClassName = "unused_arg_in_lambdas_kstyle.MainKt";
-    runTest(
-            "unused_arg_in_lambdas_kstyle",
-            mainClassName,
-            TestShrinkerBuilder::addDontWarnJetBrainsAnnotations)
+    runTest("unused_arg_in_lambdas_kstyle", mainClassName)
         .inspect(
             inspector ->
                 inspector.forAllClasses(
@@ -64,10 +60,7 @@
   @Test
   public void testMergingJStyleLambdasAfterUnusedArgumentRemoval() throws Exception {
     final String mainClassName = "unused_arg_in_lambdas_jstyle.MainKt";
-    runTest(
-            "unused_arg_in_lambdas_jstyle",
-            mainClassName,
-            TestShrinkerBuilder::addDontWarnJetBrainsAnnotations)
+    runTest("unused_arg_in_lambdas_jstyle", mainClassName)
         .inspect(
             inspector ->
                 inspector.forAllClasses(
diff --git a/src/test/java/com/android/tools/r8/kotlin/KotlinUnusedSingletonTest.java b/src/test/java/com/android/tools/r8/kotlin/KotlinUnusedSingletonTest.java
index 4da0c68..9d66188 100644
--- a/src/test/java/com/android/tools/r8/kotlin/KotlinUnusedSingletonTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/KotlinUnusedSingletonTest.java
@@ -13,7 +13,6 @@
 
 import com.android.tools.r8.KotlinTestParameters;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestShrinkerBuilder;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.FieldSubject;
@@ -54,10 +53,7 @@
     assumeTrue(kotlinc.is(KOTLINC_1_3_72));
     final String mainClassName = "unused_singleton.MainKt";
     final String moduleName = "unused_singleton.TestModule";
-    runTest(
-            "unused_singleton",
-            mainClassName,
-            TestShrinkerBuilder::addDontWarnJetBrainsNotNullAnnotation)
+    runTest("unused_singleton", mainClassName)
         .inspect(
             inspector -> {
               ClassSubject main = inspector.clazz(mainClassName);
diff --git a/src/test/java/com/android/tools/r8/kotlin/ProcessKotlinStdlibTest.java b/src/test/java/com/android/tools/r8/kotlin/ProcessKotlinStdlibTest.java
index c2c68e4..679177e 100644
--- a/src/test/java/com/android/tools/r8/kotlin/ProcessKotlinStdlibTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/ProcessKotlinStdlibTest.java
@@ -3,14 +3,13 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.kotlin;
 
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
+import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
+import static org.hamcrest.CoreMatchers.equalTo;
 
 import com.android.tools.r8.KotlinTestBase;
 import com.android.tools.r8.KotlinTestParameters;
-import com.android.tools.r8.R8FullTestBuilder;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestShrinkerBuilder;
-import com.android.tools.r8.ThrowableConsumer;
-import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.shaking.ProguardKeepAttributes;
 import com.google.common.collect.ImmutableList;
 import java.util.Collection;
@@ -35,47 +34,35 @@
   }
 
   private void test(Collection<String> rules) throws Exception {
-    test(rules, null);
-  }
-
-  private void test(
-      Collection<String> rules,
-      ThrowableConsumer<R8FullTestBuilder> consumer)
-      throws Exception {
     testForR8(parameters.getBackend())
-        .addProgramFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+        .addProgramFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
         .addKeepRules(rules)
         .addKeepAttributes(ProguardKeepAttributes.SIGNATURE)
         .addKeepAttributes(ProguardKeepAttributes.INNER_CLASSES)
         .addKeepAttributes(ProguardKeepAttributes.ENCLOSING_METHOD)
-        .apply(consumer)
-        .compile();
+        .allowDiagnosticWarningMessages()
+        .compile()
+        .assertAllWarningMessagesMatch(equalTo("Resource 'META-INF/MANIFEST.MF' already exists."));
   }
 
   @Test
   public void testAsIs() throws Exception {
-    test(
-        ImmutableList.of("-dontshrink", "-dontoptimize", "-dontobfuscate"),
-        TestShrinkerBuilder::addDontWarnJetBrainsAnnotations);
+    test(ImmutableList.of("-dontshrink", "-dontoptimize", "-dontobfuscate"));
   }
 
   @Test
   public void testDontShrinkAndDontOptimize() throws Exception {
-    test(
-        ImmutableList.of("-dontshrink", "-dontoptimize"),
-        TestShrinkerBuilder::addDontWarnJetBrainsAnnotations);
+    test(ImmutableList.of("-dontshrink", "-dontoptimize"));
   }
 
   @Test
   public void testDontShrinkAndDontObfuscate() throws Exception {
-    test(
-        ImmutableList.of("-dontshrink", "-dontobfuscate"),
-        TestShrinkerBuilder::addDontWarnJetBrainsAnnotations);
+    test(ImmutableList.of("-dontshrink", "-dontobfuscate"));
   }
 
   @Test
   public void testDontShrink() throws Exception {
-    test(ImmutableList.of("-dontshrink"), TestShrinkerBuilder::addDontWarnJetBrainsAnnotations);
+    test(ImmutableList.of("-dontshrink"));
   }
 
   @Test
diff --git a/src/test/java/com/android/tools/r8/kotlin/R8KotlinAccessorTest.java b/src/test/java/com/android/tools/r8/kotlin/R8KotlinAccessorTest.java
index 8773698..1b2dd74 100644
--- a/src/test/java/com/android/tools/r8/kotlin/R8KotlinAccessorTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/R8KotlinAccessorTest.java
@@ -9,8 +9,8 @@
 import static org.junit.Assert.assertTrue;
 
 import com.android.tools.r8.KotlinTestParameters;
+import com.android.tools.r8.R8TestBuilder;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestShrinkerBuilder;
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.ToolHelper.ProcessResult;
 import com.android.tools.r8.jasmin.JasminBuilder;
@@ -86,10 +86,7 @@
     final TestKotlinCompanionClass testedClass = COMPANION_PROPERTY_CLASS;
     String mainClass = addMainToClasspath("properties.CompanionPropertiesKt",
         "companionProperties_usePrimitiveProp");
-    runTest(
-            PROPERTIES_PACKAGE_NAME,
-            mainClass,
-            builder -> builder.addDontWarnJetBrainsNotNullAnnotation().noClassStaticizing())
+    runTest(PROPERTIES_PACKAGE_NAME, mainClass, R8TestBuilder::noClassStaticizing)
         .inspect(
             inspector -> {
               ClassSubject outerClass =
@@ -122,10 +119,7 @@
     final TestKotlinCompanionClass testedClass = COMPANION_PROPERTY_CLASS;
     String mainClass = addMainToClasspath("properties.CompanionPropertiesKt",
         "companionProperties_usePrivateProp");
-    runTest(
-            PROPERTIES_PACKAGE_NAME,
-            mainClass,
-            builder -> builder.addDontWarnJetBrainsNotNullAnnotation().noClassStaticizing())
+    runTest(PROPERTIES_PACKAGE_NAME, mainClass, R8TestBuilder::noClassStaticizing)
         .inspect(
             inspector -> {
               ClassSubject outerClass =
@@ -160,10 +154,7 @@
     final TestKotlinCompanionClass testedClass = COMPANION_PROPERTY_CLASS;
     String mainClass = addMainToClasspath("properties.CompanionPropertiesKt",
         "companionProperties_useInternalProp");
-    runTest(
-            PROPERTIES_PACKAGE_NAME,
-            mainClass,
-            builder -> builder.addDontWarnJetBrainsNotNullAnnotation().noClassStaticizing())
+    runTest(PROPERTIES_PACKAGE_NAME, mainClass, R8TestBuilder::noClassStaticizing)
         .inspect(
             inspector -> {
               ClassSubject outerClass =
@@ -197,10 +188,7 @@
     final TestKotlinCompanionClass testedClass = COMPANION_PROPERTY_CLASS;
     String mainClass = addMainToClasspath("properties.CompanionPropertiesKt",
         "companionProperties_usePublicProp");
-    runTest(
-            PROPERTIES_PACKAGE_NAME,
-            mainClass,
-            builder -> builder.addDontWarnJetBrainsNotNullAnnotation().noClassStaticizing())
+    runTest(PROPERTIES_PACKAGE_NAME, mainClass, R8TestBuilder::noClassStaticizing)
         .inspect(
             inspector -> {
               ClassSubject outerClass =
@@ -234,10 +222,7 @@
     final TestKotlinCompanionClass testedClass = COMPANION_LATE_INIT_PROPERTY_CLASS;
     String mainClass = addMainToClasspath("properties.CompanionLateInitPropertiesKt",
         "companionLateInitProperties_usePrivateLateInitProp");
-    runTest(
-            PROPERTIES_PACKAGE_NAME,
-            mainClass,
-            builder -> builder.addDontWarnJetBrainsAnnotations().noClassStaticizing())
+    runTest(PROPERTIES_PACKAGE_NAME, mainClass, R8TestBuilder::noClassStaticizing)
         .inspect(
             inspector -> {
               ClassSubject outerClass =
@@ -270,10 +255,7 @@
     final TestKotlinCompanionClass testedClass = COMPANION_LATE_INIT_PROPERTY_CLASS;
     String mainClass = addMainToClasspath("properties.CompanionLateInitPropertiesKt",
         "companionLateInitProperties_useInternalLateInitProp");
-    runTest(
-            PROPERTIES_PACKAGE_NAME,
-            mainClass,
-            TestShrinkerBuilder::addDontWarnJetBrainsAnnotations)
+    runTest(PROPERTIES_PACKAGE_NAME, mainClass)
         .inspect(
             inspector -> {
               ClassSubject outerClass =
@@ -302,10 +284,7 @@
     final TestKotlinCompanionClass testedClass = COMPANION_LATE_INIT_PROPERTY_CLASS;
     String mainClass = addMainToClasspath("properties.CompanionLateInitPropertiesKt",
         "companionLateInitProperties_usePublicLateInitProp");
-    runTest(
-            PROPERTIES_PACKAGE_NAME,
-            mainClass,
-            TestShrinkerBuilder::addDontWarnJetBrainsAnnotations)
+    runTest(PROPERTIES_PACKAGE_NAME, mainClass)
         .inspect(
             inspector -> {
               ClassSubject outerClass =
@@ -389,7 +368,7 @@
     String mainClass =
         addMainToClasspath(
             "accessors.PropertyAccessorForInnerClassKt", "noUseOfPropertyAccessorFromInnerClass");
-    runTest("accessors", mainClass, TestShrinkerBuilder::addDontWarnJetBrainsNotNullAnnotation)
+    runTest("accessors", mainClass)
         .inspect(
             inspector -> {
               // Class is removed because the instantiation of the inner class has no side effects.
diff --git a/src/test/java/com/android/tools/r8/kotlin/R8KotlinDataClassTest.java b/src/test/java/com/android/tools/r8/kotlin/R8KotlinDataClassTest.java
index b992613..e2c0a0a 100644
--- a/src/test/java/com/android/tools/r8/kotlin/R8KotlinDataClassTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/R8KotlinDataClassTest.java
@@ -74,7 +74,6 @@
             testBuilder ->
                 testBuilder
                     .addKeepRules(extraRules)
-                    .addDontWarnJetBrainsAnnotations()
                     .addOptionsModification(disableClassInliner))
         .inspect(
             inspector -> {
@@ -120,7 +119,6 @@
             testBuilder ->
                 testBuilder
                     .addKeepRules(extraRules)
-                    .addDontWarnJetBrainsAnnotations()
                     .addOptionsModification(disableClassInliner))
         .inspect(
             inspector -> {
@@ -165,7 +163,6 @@
             testBuilder ->
                 testBuilder
                     .addKeepRules(extraRules)
-                    .addDontWarnJetBrainsAnnotations()
                     .addOptionsModification(disableClassInliner))
         .inspect(
             inspector -> {
@@ -208,7 +205,6 @@
             testBuilder ->
                 testBuilder
                     .addKeepRules(extraRules)
-                    .addDontWarnJetBrainsAnnotations()
                     .addOptionsModification(disableClassInliner))
         .inspect(
             inspector -> {
@@ -231,7 +227,6 @@
             testBuilder ->
                 testBuilder
                     .addKeepRules(extraRules)
-                    .addDontWarnJetBrainsAnnotations()
                     .addOptionsModification(disableClassInliner))
         .inspect(
             inspector -> {
diff --git a/src/test/java/com/android/tools/r8/kotlin/R8KotlinIntrinsicsTest.java b/src/test/java/com/android/tools/r8/kotlin/R8KotlinIntrinsicsTest.java
index 9d9fcee..5de5dbd 100644
--- a/src/test/java/com/android/tools/r8/kotlin/R8KotlinIntrinsicsTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/R8KotlinIntrinsicsTest.java
@@ -56,7 +56,6 @@
             testBuilder ->
                 testBuilder
                     .addKeepRules(extraRules)
-                    .addDontWarnJetBrainsAnnotations()
                     .noHorizontalClassMerging(Intrinsics.class))
         .inspect(
             inspector -> {
diff --git a/src/test/java/com/android/tools/r8/kotlin/R8KotlinPropertiesTest.java b/src/test/java/com/android/tools/r8/kotlin/R8KotlinPropertiesTest.java
index c7325b0..65822f7 100644
--- a/src/test/java/com/android/tools/r8/kotlin/R8KotlinPropertiesTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/R8KotlinPropertiesTest.java
@@ -118,7 +118,6 @@
             mainClass,
             testBuilder ->
                 testBuilder
-                    .addDontWarnJetBrainsNotNullAnnotation()
                     .addOptionsModification(disableAggressiveClassOptimizations))
         .inspect(
             inspector -> {
@@ -135,7 +134,6 @@
             mainClass,
             testBuilder ->
                 testBuilder
-                    .addDontWarnJetBrainsNotNullAnnotation()
                     .addOptionsModification(disableAggressiveClassOptimizations))
         .inspect(
             inspector -> {
@@ -167,7 +165,6 @@
             mainClass,
             testBuilder ->
                 testBuilder
-                    .addDontWarnJetBrainsNotNullAnnotation()
                     .addOptionsModification(disableAggressiveClassOptimizations))
         .inspect(
             inspector -> {
@@ -198,7 +195,6 @@
             mainClass,
             testBuilder ->
                 testBuilder
-                    .addDontWarnJetBrainsNotNullAnnotation()
                     .addOptionsModification(disableAggressiveClassOptimizations))
         .inspect(
             inspector -> {
@@ -229,7 +225,6 @@
             mainClass,
             testBuilder ->
                 testBuilder
-                    .addDontWarnJetBrainsNotNullAnnotation()
                     .addOptionsModification(disableAggressiveClassOptimizations))
         .inspect(
             inspector -> {
@@ -260,7 +255,6 @@
             mainClass,
             testBuilder ->
                 testBuilder
-                    .addDontWarnJetBrainsNotNullAnnotation()
                     .addOptionsModification(disableAggressiveClassOptimizations))
         .inspect(
             inspector -> {
@@ -306,7 +300,6 @@
             mainClass,
             testBuilder ->
                 testBuilder
-                    .addDontWarnJetBrainsAnnotations()
                     .addOptionsModification(disableAggressiveClassOptimizations))
         .inspect(
             inspector -> {
@@ -336,7 +329,6 @@
             mainClass,
             testBuilder ->
                 testBuilder
-                    .addDontWarnJetBrainsAnnotations()
                     .addOptionsModification(disableAggressiveClassOptimizations))
         .inspect(
             inspector -> {
@@ -364,7 +356,6 @@
             mainClass,
             testBuilder ->
                 testBuilder
-                    .addDontWarnJetBrainsAnnotations()
                     .addOptionsModification(disableAggressiveClassOptimizations))
         .inspect(
             inspector -> {
@@ -390,7 +381,6 @@
             mainClass,
             testBuilder ->
                 testBuilder
-                    .addDontWarnJetBrainsAnnotations()
                     .addOptionsModification(disableAggressiveClassOptimizations))
         .inspect(
             inspector -> {
@@ -461,7 +451,6 @@
             mainClass,
             testBuilder ->
                 testBuilder
-                    .addDontWarnJetBrainsNotNullAnnotation()
                     .addOptionsModification(disableAggressiveClassOptimizations))
         .inspect(
             inspector -> {
@@ -488,7 +477,6 @@
             mainClass,
             testBuilder ->
                 testBuilder
-                    .addDontWarnJetBrainsNotNullAnnotation()
                     .addOptionsModification(disableAggressiveClassOptimizations))
         .inspect(
             inspector -> {
@@ -527,7 +515,6 @@
             mainClass,
             testBuilder ->
                 testBuilder
-                    .addDontWarnJetBrainsNotNullAnnotation()
                     .addOptionsModification(disableAggressiveClassOptimizations))
         .inspect(
             inspector -> {
@@ -555,7 +542,6 @@
             mainClass,
             testBuilder ->
                 testBuilder
-                    .addDontWarnJetBrainsNotNullAnnotation()
                     .addOptionsModification(disableAggressiveClassOptimizations))
         .inspect(
             inspector -> {
@@ -584,7 +570,6 @@
             mainClass,
             testBuilder ->
                 testBuilder
-                    .addDontWarnJetBrainsAnnotations()
                     .addOptionsModification(disableAggressiveClassOptimizations))
         .inspect(
             inspector -> {
@@ -619,7 +604,6 @@
             mainClass,
             testBuilder ->
                 testBuilder
-                    .addDontWarnJetBrainsAnnotations()
                     .addOptionsModification(disableAggressiveClassOptimizations))
         .inspect(
             inspector -> {
@@ -644,7 +628,6 @@
             mainClass,
             testBuilder ->
                 testBuilder
-                    .addDontWarnJetBrainsAnnotations()
                     .addOptionsModification(disableAggressiveClassOptimizations))
         .inspect(
             inspector -> {
@@ -669,7 +652,6 @@
             mainClass,
             testBuilder ->
                 testBuilder
-                    .addDontWarnJetBrainsNotNullAnnotation()
                     .addOptionsModification(disableAggressiveClassOptimizations))
         .inspect(
             inspector -> {
@@ -710,7 +692,6 @@
             mainClass,
             testBuilder ->
                 testBuilder
-                    .addDontWarnJetBrainsNotNullAnnotation()
                     .addOptionsModification(disableAggressiveClassOptimizations))
         .inspect(
             inspector -> {
@@ -745,7 +726,6 @@
             mainClass,
             testBuilder ->
                 testBuilder
-                    .addDontWarnJetBrainsNotNullAnnotation()
                     .addOptionsModification(disableAggressiveClassOptimizations))
         .inspect(
             inspector -> {
@@ -787,7 +767,6 @@
             mainClass,
             testBuilder ->
                 testBuilder
-                    .addDontWarnJetBrainsNotNullAnnotation()
                     .addOptionsModification(disableAggressiveClassOptimizations))
         .inspect(
             inspector -> {
@@ -829,7 +808,6 @@
             mainClass,
             testBuilder ->
                 testBuilder
-                    .addDontWarnJetBrainsAnnotations()
                     .addOptionsModification(disableAggressiveClassOptimizations))
         .inspect(
             inspector -> {
@@ -864,7 +842,6 @@
             mainClass,
             testBuilder ->
                 testBuilder
-                    .addDontWarnJetBrainsAnnotations()
                     .addOptionsModification(disableAggressiveClassOptimizations))
         .inspect(
             inspector -> {
@@ -893,7 +870,6 @@
             mainClass,
             testBuilder ->
                 testBuilder
-                    .addDontWarnJetBrainsAnnotations()
                     .addOptionsModification(disableAggressiveClassOptimizations))
         .inspect(
             inspector -> {
@@ -922,7 +898,6 @@
             mainClass,
             testBuilder ->
                 testBuilder
-                    .addDontWarnJetBrainsNotNullAnnotation()
                     .addOptionsModification(disableAggressiveClassOptimizations))
         .inspect(
             inspector -> {
@@ -956,7 +931,6 @@
             mainClass,
             testBuilder ->
                 testBuilder
-                    .addDontWarnJetBrainsNotNullAnnotation()
                     .addOptionsModification(disableAggressiveClassOptimizations))
         .inspect(
             inspector -> {
@@ -990,7 +964,6 @@
             mainClass,
             testBuilder ->
                 testBuilder
-                    .addDontWarnJetBrainsNotNullAnnotation()
                     .addOptionsModification(disableAggressiveClassOptimizations))
         .inspect(
             inspector -> {
@@ -1026,7 +999,6 @@
             mainClass,
             testBuilder ->
                 testBuilder
-                    .addDontWarnJetBrainsNotNullAnnotation()
                     .addOptionsModification(disableAggressiveClassOptimizations))
         .inspect(
             inspector -> {
@@ -1061,7 +1033,6 @@
             mainClass,
             testBuilder ->
                 testBuilder
-                    .addDontWarnJetBrainsAnnotations()
                     .addOptionsModification(disableAggressiveClassOptimizations))
         .inspect(
             inspector -> {
@@ -1095,7 +1066,6 @@
             mainClass,
             testBuilder ->
                 testBuilder
-                    .addDontWarnJetBrainsAnnotations()
                     .addOptionsModification(disableAggressiveClassOptimizations))
         .inspect(
             inspector -> {
@@ -1126,7 +1096,6 @@
             mainClass,
             testBuilder ->
                 testBuilder
-                    .addDontWarnJetBrainsAnnotations()
                     .addOptionsModification(disableAggressiveClassOptimizations))
         .inspect(
             inspector -> {
diff --git a/src/test/java/com/android/tools/r8/kotlin/SimplifyIfNotNullKotlinTest.java b/src/test/java/com/android/tools/r8/kotlin/SimplifyIfNotNullKotlinTest.java
index b3537a9..00c9978 100644
--- a/src/test/java/com/android/tools/r8/kotlin/SimplifyIfNotNullKotlinTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/SimplifyIfNotNullKotlinTest.java
@@ -48,10 +48,7 @@
 
     final String mainClassName = ex1.getClassName();
     final String extraRules = neverInlineMethod(mainClassName, testMethodSignature);
-    runTest(
-            FOLDER,
-            mainClassName,
-            testBuilder -> testBuilder.addKeepRules(extraRules).addDontWarnJetBrainsAnnotations())
+    runTest(FOLDER, mainClassName, testBuilder -> testBuilder.addKeepRules(extraRules))
         .inspect(
             inspector -> {
               ClassSubject clazz = checkClassIsKept(inspector, ex1.getClassName());
@@ -78,10 +75,7 @@
 
     final String mainClassName = ex2.getClassName();
     final String extraRules = neverInlineMethod(mainClassName, testMethodSignature);
-    runTest(
-            FOLDER,
-            mainClassName,
-            testBuilder -> testBuilder.addKeepRules(extraRules).addDontWarnJetBrainsAnnotations())
+    runTest(FOLDER, mainClassName, testBuilder -> testBuilder.addKeepRules(extraRules))
         .inspect(
             inspector -> {
               ClassSubject clazz = checkClassIsKept(inspector, ex2.getClassName());
@@ -106,10 +100,7 @@
 
     final String mainClassName = ex3.getClassName();
     final String extraRules = neverInlineMethod(mainClassName, testMethodSignature);
-    runTest(
-            FOLDER,
-            mainClassName,
-            testBuilder -> testBuilder.addKeepRules(extraRules).addDontWarnJetBrainsAnnotations())
+    runTest(FOLDER, mainClassName, testBuilder -> testBuilder.addKeepRules(extraRules))
         .inspect(
             inspector -> {
               ClassSubject clazz = checkClassIsKept(inspector, ex3.getClassName());
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/KStyleKotlinLambdaMergingWithEnumUnboxingTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/KStyleKotlinLambdaMergingWithEnumUnboxingTest.java
index fe0ef77..5b22795 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/KStyleKotlinLambdaMergingWithEnumUnboxingTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/KStyleKotlinLambdaMergingWithEnumUnboxingTest.java
@@ -4,14 +4,16 @@
 
 package com.android.tools.r8.kotlin.lambda;
 
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
 import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
+import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
+import static org.hamcrest.CoreMatchers.equalTo;
 
 import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
 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.ToolHelper;
 import com.android.tools.r8.kotlin.lambda.KStyleKotlinLambdaMergingWithEnumUnboxingTest.Main.EnumUnboxingCandidate;
 import java.util.List;
 import org.junit.Test;
@@ -42,17 +44,18 @@
   public void test() throws Exception {
     testForR8(parameters.getBackend())
         .addInnerClasses(getClass())
-        .addProgramFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+        .addProgramFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
         .addKeepMainRule(Main.class)
         .addHorizontallyMergedClassesInspector(
             inspector -> inspector.assertMergedInto(Lambda2.class, Lambda1.class))
         .addEnumUnboxingInspector(inspector -> inspector.assertUnboxed(EnumUnboxingCandidate.class))
-        .addDontWarnJetBrainsNotNullAnnotation()
+        .allowDiagnosticWarningMessages()
         .enableInliningAnnotations()
         .enableNeverClassInliningAnnotations()
         .noMinification()
         .setMinApi(parameters.getApiLevel())
         .compile()
+        .assertAllWarningMessagesMatch(equalTo("Resource 'META-INF/MANIFEST.MF' already exists."))
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLines("Lambda1.method()", "Lambda2.method()");
   }
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergerValidationTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergerValidationTest.java
index 9d9f42a..7966656 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergerValidationTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergerValidationTest.java
@@ -3,6 +3,9 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.kotlin.lambda;
 
+import static com.android.tools.r8.ToolHelper.getJava8RuntimeJar;
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
+import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
 import static org.hamcrest.CoreMatchers.equalTo;
 import static org.junit.Assume.assumeTrue;
 
@@ -11,7 +14,6 @@
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestRuntime;
 import com.android.tools.r8.TestRuntime.CfRuntime;
-import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.utils.DescriptorUtils;
 import java.nio.file.Path;
 import java.util.Collection;
@@ -43,21 +45,21 @@
 
     String pkg = getClass().getPackage().getName();
     String folder = DescriptorUtils.getBinaryNameFromJavaType(pkg);
-    CfRuntime cfRuntime =
-        parameters.isCfRuntime() ? parameters.getRuntime().asCf() : TestRuntime.getCheckedInJdk9();
+    CfRuntime cfRuntime = parameters.getRuntime().asCf();
     Path ktClasses =
         kotlinc(cfRuntime, kotlinc, targetVersion)
             .addSourceFiles(getKotlinFileInTest(folder, "b143165163"))
             .compile();
     testForR8(parameters.getBackend())
-        .addLibraryFiles(ToolHelper.getJava8RuntimeJar())
-        .addLibraryFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
-        .addProgramFiles(ktClasses)
+        .addLibraryFiles(getJava8RuntimeJar())
+        .addLibraryFiles(getKotlinStdlibJar(kotlinc))
+        .addProgramFiles(ktClasses, getKotlinAnnotationJar(kotlinc))
         .addKeepMainRule("**.B143165163Kt")
-        .addDontWarnJetBrainsNotNullAnnotation()
+        .allowDiagnosticWarningMessages()
         .setMinApi(parameters.getApiLevel())
         .compile()
-        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+        .assertAllWarningMessagesMatch(equalTo("Resource 'META-INF/MANIFEST.MF' already exists."))
+        .addRunClasspathFiles(getKotlinStdlibJar(kotlinc))
         .run(parameters.getRuntime(), pkg + ".B143165163Kt")
         .assertSuccessWithOutputLines("outer foo bar", "outer foo default");
   }
@@ -75,10 +77,9 @@
             .addSourceFiles(getKotlinFileInTest(folder, "b143165163"))
             .compile();
     testForR8(parameters.getBackend())
-        .addProgramFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+        .addProgramFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
         .addProgramFiles(ktClasses)
         .addKeepMainRule("**.B143165163Kt")
-        .addDontWarnJetBrainsNotNullAnnotation()
         .allowDiagnosticWarningMessages()
         .setMinApi(parameters.getApiLevel())
         .compile()
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingCapturesKotlinStyleTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingCapturesKotlinStyleTest.java
index 0a49461..1e8065c 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingCapturesKotlinStyleTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingCapturesKotlinStyleTest.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.kotlin.lambda;
 
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
 import static com.android.tools.r8.utils.PredicateUtils.not;
 import static junit.framework.TestCase.assertEquals;
 import static org.hamcrest.CoreMatchers.containsString;
@@ -75,7 +76,6 @@
     testForR8(parameters.getBackend())
         .addProgramFiles(getProgramFiles())
         .addKeepMainRule(getMainClassName())
-        .addDontWarnJetBrainsAnnotations()
         .addHorizontallyMergedClassesInspector(this::inspect)
         .allowAccessModification(allowAccessModification)
         .allowDiagnosticWarningMessages()
@@ -152,7 +152,7 @@
         getCompileMemoizer(getKotlinFilesInResource(getTestName()), getTestName())
             .configure(kotlinCompilerTool -> kotlinCompilerTool.includeRuntime().noReflect())
             .getForConfiguration(kotlinc, targetVersion);
-    return ImmutableList.of(kotlinJarFile, getJavaJarFile());
+    return ImmutableList.of(kotlinJarFile, getJavaJarFile(), getKotlinAnnotationJar(kotlinc));
   }
 
   private String getTestName() {
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingDebugTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingDebugTest.java
index 7aaeade..de923a9 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingDebugTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingDebugTest.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.kotlin.lambda;
 
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
 import static org.hamcrest.CoreMatchers.equalTo;
 
 import com.android.tools.r8.CompilationMode;
@@ -47,9 +48,10 @@
   public void testMergingKStyleLambdasAndReprocessingInDebug() throws Exception {
     testForR8(parameters.getBackend())
         .setMode(CompilationMode.DEBUG)
-        .addProgramFiles(compiledJars.getForConfiguration(kotlinc, KotlinTargetVersion.JAVA_6))
+        .addProgramFiles(
+            compiledJars.getForConfiguration(kotlinc, KotlinTargetVersion.JAVA_6),
+            getKotlinAnnotationJar(kotlinc))
         .addProgramFiles(getJavaJarFile(FOLDER))
-        .addDontWarnJetBrainsNotNullAnnotation()
         .setMinApi(parameters.getApiLevel())
         .addKeepMainRule(MAIN_CLASS)
         .allowDiagnosticWarningMessages()
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingKeepAttributesKotlinStyleTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingKeepAttributesKotlinStyleTest.java
index a20a77d..3ccb9ad 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingKeepAttributesKotlinStyleTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingKeepAttributesKotlinStyleTest.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.kotlin.lambda;
 
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
 import static com.android.tools.r8.shaking.ProguardKeepAttributes.ENCLOSING_METHOD;
 import static com.android.tools.r8.shaking.ProguardKeepAttributes.INNER_CLASSES;
 import static com.android.tools.r8.shaking.ProguardKeepAttributes.SIGNATURE;
@@ -82,7 +83,6 @@
         .addProgramFiles(getProgramFiles())
         .addKeepMainRule(getMainClassName())
         .applyIf(!attributes.isEmpty(), builder -> builder.addKeepAttributes(attributes))
-        .addDontWarnJetBrainsAnnotations()
         .addHorizontallyMergedClassesInspector(this::inspect)
         .allowAccessModification(allowAccessModification)
         .allowDiagnosticWarningMessages()
@@ -151,7 +151,7 @@
         getCompileMemoizer(getKotlinFilesInResource(getTestName()), getTestName())
             .configure(kotlinCompilerTool -> kotlinCompilerTool.includeRuntime().noReflect())
             .getForConfiguration(kotlinc, targetVersion);
-    return ImmutableList.of(kotlinJarFile, getJavaJarFile());
+    return ImmutableList.of(kotlinJarFile, getJavaJarFile(), getKotlinAnnotationJar(kotlinc));
   }
 
   private String getTestName() {
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingSingletonTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingSingletonTest.java
index 72abfe3..500f7c1 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingSingletonTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingSingletonTest.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.kotlin.lambda;
 
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
 import static com.android.tools.r8.utils.PredicateUtils.not;
 import static junit.framework.TestCase.assertEquals;
 import static org.hamcrest.CoreMatchers.containsString;
@@ -75,7 +76,6 @@
     testForR8(parameters.getBackend())
         .addProgramFiles(getProgramFiles())
         .addKeepMainRule(getMainClassName())
-        .addDontWarnJetBrainsAnnotations()
         .addHorizontallyMergedClassesInspector(this::inspect)
         .allowAccessModification(allowAccessModification)
         .allowDiagnosticWarningMessages()
@@ -146,7 +146,7 @@
         getCompileMemoizer(getKotlinFilesInResource(getTestName()), getTestName())
             .configure(kotlinCompilerTool -> kotlinCompilerTool.includeRuntime().noReflect())
             .getForConfiguration(kotlinc, targetVersion);
-    return ImmutableList.of(kotlinJarFile, getJavaJarFile());
+    return ImmutableList.of(kotlinJarFile, getJavaJarFile(), getKotlinAnnotationJar(kotlinc));
   }
 
   private String getTestName() {
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingTrivialJavaStyleTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingTrivialJavaStyleTest.java
index 1e83c00..6fbd439 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingTrivialJavaStyleTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingTrivialJavaStyleTest.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.kotlin.lambda;
 
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
 import static com.android.tools.r8.utils.PredicateUtils.not;
 import static junit.framework.TestCase.assertEquals;
 import static org.hamcrest.CoreMatchers.containsString;
@@ -75,7 +76,6 @@
     testForR8(parameters.getBackend())
         .addProgramFiles(getProgramFiles())
         .addKeepMainRule(getMainClassName())
-        .addDontWarnJetBrainsAnnotations()
         .addHorizontallyMergedClassesInspector(this::inspect)
         .allowAccessModification(allowAccessModification)
         .allowDiagnosticWarningMessages()
@@ -201,7 +201,7 @@
         getCompileMemoizer(getKotlinFilesInResource(getTestName()), getTestName())
             .configure(kotlinCompilerTool -> kotlinCompilerTool.includeRuntime().noReflect())
             .getForConfiguration(kotlinc, targetVersion);
-    return ImmutableList.of(kotlinJarFile, getJavaJarFile());
+    return ImmutableList.of(kotlinJarFile, getJavaJarFile(), getKotlinAnnotationJar(kotlinc));
   }
 
   private String getTestName() {
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingTrivialKotlinStyleTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingTrivialKotlinStyleTest.java
index 3515109..cb79d89 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingTrivialKotlinStyleTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingTrivialKotlinStyleTest.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.kotlin.lambda;
 
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
 import static com.android.tools.r8.utils.PredicateUtils.not;
 import static junit.framework.TestCase.assertEquals;
 import static org.hamcrest.CoreMatchers.containsString;
@@ -75,7 +76,6 @@
     testForR8(parameters.getBackend())
         .addProgramFiles(getProgramFiles())
         .addKeepMainRule(getMainClassName())
-        .addDontWarnJetBrainsNotNullAnnotation()
         .addHorizontallyMergedClassesInspector(this::inspect)
         .allowAccessModification(allowAccessModification)
         .allowDiagnosticWarningMessages()
@@ -162,7 +162,7 @@
         getCompileMemoizer(getKotlinFilesInResource(getTestName()), getTestName())
             .configure(kotlinCompilerTool -> kotlinCompilerTool.includeRuntime().noReflect())
             .getForConfiguration(kotlinc, targetVersion);
-    return ImmutableList.of(kotlinJarFile, getJavaJarFile());
+    return ImmutableList.of(kotlinJarFile, getJavaJarFile(), getKotlinAnnotationJar(kotlinc));
   }
 
   private String getTestName() {
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingWithReprocessingTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingWithReprocessingTest.java
index 96135ae..5629f15 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingWithReprocessingTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingWithReprocessingTest.java
@@ -5,7 +5,6 @@
 
 import com.android.tools.r8.KotlinTestParameters;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestShrinkerBuilder;
 import com.android.tools.r8.kotlin.AbstractR8KotlinTestBase;
 import com.android.tools.r8.utils.BooleanUtils;
 import java.util.Collection;
@@ -34,9 +33,6 @@
   @Test
   public void testMergingKStyleLambdasAndReprocessing() throws Exception {
     final String mainClassName = "reprocess_merged_lambdas_kstyle.MainKt";
-    runTest(
-        "reprocess_merged_lambdas_kstyle",
-        mainClassName,
-        TestShrinkerBuilder::addDontWarnJetBrainsNotNullAnnotation);
+    runTest("reprocess_merged_lambdas_kstyle", mainClassName);
   }
 }
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingWithSmallInliningBudgetTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingWithSmallInliningBudgetTest.java
index 2700f5e..729869f 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingWithSmallInliningBudgetTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingWithSmallInliningBudgetTest.java
@@ -38,7 +38,6 @@
         mainClassName,
         testBuilder ->
             testBuilder
-                .addDontWarnJetBrainsAnnotations()
                 .addOptionsModification(options -> options.inliningInstructionAllowance = 3));
   }
 }
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/b148525512/B148525512.java b/src/test/java/com/android/tools/r8/kotlin/lambda/b148525512/B148525512.java
index ac22198..23b51d7 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/b148525512/B148525512.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/b148525512/B148525512.java
@@ -4,6 +4,8 @@
 
 package com.android.tools.r8.kotlin.lambda.b148525512;
 
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
+import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
 import static org.hamcrest.CoreMatchers.equalTo;
 
 import com.android.tools.r8.DexIndexedConsumer.ArchiveConsumer;
@@ -11,7 +13,6 @@
 import com.android.tools.r8.KotlinTestParameters;
 import com.android.tools.r8.R8TestCompileResult;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.utils.ArchiveResourceProvider;
 import java.io.IOException;
 import java.nio.file.Files;
@@ -75,7 +76,7 @@
     Path featureCode = temp.newFile("feature.zip").toPath();
     R8TestCompileResult compileResult =
         testForR8(parameters.getBackend())
-            .addProgramFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+            .addProgramFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
             .addProgramFiles(kotlinBaseClasses.getForConfiguration(kotlinc, targetVersion))
             .addProgramClasses(FeatureAPI.class)
             .addKeepMainRule(baseKtClassName)
@@ -102,7 +103,6 @@
                         .setProgramConsumer(new ArchiveConsumer(featureCode, false))
                         .build())
             .allowDiagnosticWarningMessages()
-            .addDontWarnJetBrainsNotNullAnnotation()
             .compile()
             .assertAllWarningMessagesMatch(
                 equalTo("Resource 'META-INF/MANIFEST.MF' already exists."));
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/LambdaGroupGCLimitTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/LambdaGroupGCLimitTest.java
index 8d476be..1f82c8b 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/LambdaGroupGCLimitTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/LambdaGroupGCLimitTest.java
@@ -4,7 +4,11 @@
 
 package com.android.tools.r8.kotlin.lambda.b159688129;
 
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
+import static com.android.tools.r8.ToolHelper.getKotlinC_1_3_72;
+import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
 import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.equalTo;
 import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
@@ -59,7 +63,6 @@
                     builder.addKeepClassAndMembersRules(PKG_NAME + ".MainKt" + mainId);
                   }
                 })
-            .addDontWarnJetBrainsNotNullAnnotation()
             .addHorizontallyMergedClassesInspector(
                 inspector -> {
                   HorizontalClassMergerOptions defaultHorizontalClassMergerOptions =
@@ -73,7 +76,10 @@
                                   mergeGroup.size()
                                       <= defaultHorizontalClassMergerOptions.getMaxGroupSize()));
                 })
-            .compile();
+            .allowDiagnosticWarningMessages()
+            .compile()
+            .assertAllWarningMessagesMatch(
+                equalTo("Resource 'META-INF/MANIFEST.MF' already exists."));
     Path path = compileResult.writeToZip();
     compileResult
         .run(parameters.getRuntime(), PKG_NAME + ".MainKt0")
@@ -97,6 +103,8 @@
     }
     writeClassFileDataToJar(classFiles, classFileData);
     return ImmutableList.of(
-        classFiles, ToolHelper.getKotlinStdlibJar(ToolHelper.getKotlinC_1_3_72()));
+        classFiles,
+        getKotlinStdlibJar(getKotlinC_1_3_72()),
+        getKotlinAnnotationJar(getKotlinC_1_3_72()));
   }
 }
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/LambdaSplitByCodeCorrectnessTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/LambdaSplitByCodeCorrectnessTest.java
index 67bb203..3ce8beb 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/LambdaSplitByCodeCorrectnessTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/LambdaSplitByCodeCorrectnessTest.java
@@ -4,6 +4,8 @@
 
 package com.android.tools.r8.kotlin.lambda.b159688129;
 
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
+import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
 import static com.android.tools.r8.utils.codeinspector.CodeMatchers.invokesMethod;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static org.hamcrest.CoreMatchers.equalTo;
@@ -15,7 +17,6 @@
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestRuntime;
 import com.android.tools.r8.TestRuntime.CfRuntime;
-import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -60,11 +61,10 @@
             .addSourceFiles(getKotlinFileInTest(folder, "Simple"))
             .compile();
     testForR8(parameters.getBackend())
-        .addProgramFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+        .addProgramFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
         .addProgramFiles(ktClasses)
         .setMinApi(parameters.getApiLevel())
         .addKeepMainRule(PKG_NAME + ".SimpleKt")
-        .addDontWarnJetBrainsNotNullAnnotation()
         .applyIf(
             splitGroup,
             b ->
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataPrimitiveTypeRewriteTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataPrimitiveTypeRewriteTest.java
index b0a30d7..cfa333f 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataPrimitiveTypeRewriteTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataPrimitiveTypeRewriteTest.java
@@ -4,6 +4,8 @@
 
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
+import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
 import static org.hamcrest.CoreMatchers.containsString;
 import static org.hamcrest.CoreMatchers.equalTo;
@@ -12,7 +14,6 @@
 import com.android.tools.r8.JvmTestRunResult;
 import com.android.tools.r8.KotlinTestParameters;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.shaking.ProguardKeepAttributes;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -58,7 +59,7 @@
             .setOutputPath(temp.newFolder().toPath())
             .compile();
     testForJvm()
-        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
+        .addRunClasspathFiles(getKotlinStdlibJar(kotlinc), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG_APP + ".MainKt")
         .assertSuccessWithOutputLines(EXPECTED);
@@ -78,12 +79,12 @@
     Path libJar =
         testForR8(parameters.getBackend())
             .addProgramFiles(
-                ToolHelper.getKotlinStdlibJar(kotlinc),
+                getKotlinStdlibJar(kotlinc),
+                getKotlinAnnotationJar(kotlinc),
                 libJars.getForConfiguration(kotlinc, targetVersion))
             .addKeepAllClassesRuleWithAllowObfuscation()
             .addKeepRules("-keep class " + PKG_LIB + ".LibKt { *; }")
             .addKeepRules("-keep class kotlin.Metadata { *; }")
-            .addDontWarnJetBrainsAnnotations()
             .applyIf(keepUnit, b -> b.addKeepRules("-keep class kotlin.Unit { *; }"))
             .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
             .allowDiagnosticWarningMessages()
@@ -105,7 +106,7 @@
             .compile();
     final JvmTestRunResult runResult =
         testForJvm()
-            .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
+            .addRunClasspathFiles(getKotlinStdlibJar(kotlinc), libJar)
             .addClasspath(output)
             .run(parameters.getRuntime(), PKG_APP + ".MainKt");
     if (keepUnit) {
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAllowAccessModificationTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAllowAccessModificationTest.java
index b4bca5c..a02d225 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAllowAccessModificationTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAllowAccessModificationTest.java
@@ -4,6 +4,8 @@
 
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
+import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static junit.framework.TestCase.assertEquals;
 import static org.hamcrest.MatcherAssert.assertThat;
@@ -11,7 +13,6 @@
 
 import com.android.tools.r8.KotlinTestParameters;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.ToolHelper.ProcessResult;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.StringUtils;
@@ -82,7 +83,7 @@
             .setOutputPath(temp.newFolder().toPath())
             .compile();
     testForJvm()
-        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
+        .addRunClasspathFiles(getKotlinStdlibJar(kotlinc), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG_APP + ".MainKt")
         .assertSuccessWithOutput(EXPECTED);
@@ -96,7 +97,7 @@
     Path libJar =
         testForR8(parameters.getBackend())
             .addProgramFiles(libJars.getForConfiguration(kotlinc, targetVersion))
-            .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+            .addClasspathFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
             .addKeepRules("-keepclassmembers,allowaccessmodification class **.Lib { *; }")
             .addKeepRules("-keep,allowaccessmodification,allowobfuscation class **.Lib { *; }")
             .addKeepRules("-keepclassmembers,allowaccessmodification class **.Lib$Comp { *; }")
@@ -112,7 +113,6 @@
                     "  void staticPrivate() -> staticPrivateReference",
                     "  void staticInternal() -> staticInternalReference"))
             .addKeepRuntimeVisibleAnnotations()
-            .addDontWarnJetBrainsNotNullAnnotation()
             .allowAccessModification()
             .compile()
             .inspect(this::inspect)
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnnotationTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnnotationTest.java
index cb63498..cccbde4 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnnotationTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnnotationTest.java
@@ -4,9 +4,11 @@
 
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
+import static org.hamcrest.CoreMatchers.equalTo;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
 
@@ -96,7 +98,9 @@
   public void testMetadataForLib() throws Exception {
     Path libJar =
         testForR8(parameters.getBackend())
-            .addProgramFiles(libJars.getForConfiguration(kotlinc, targetVersion))
+            .addProgramFiles(
+                libJars.getForConfiguration(kotlinc, targetVersion),
+                getKotlinAnnotationJar(kotlinc))
             .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
             /// Keep the annotations
             .addKeepClassAndMembersRules(PKG_LIB + ".AnnoWithClassAndEnum")
@@ -119,8 +123,10 @@
                 ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS,
                 ProguardKeepAttributes.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS,
                 ProguardKeepAttributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS)
-            .addDontWarnJetBrainsNotNullAnnotation()
+            .allowDiagnosticWarningMessages()
             .compile()
+            .assertAllWarningMessagesMatch(
+                equalTo("Resource 'META-INF/MANIFEST.MF' already exists."))
             .inspect(this::inspect)
             .writeToZip();
     Path output =
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnonymousTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnonymousTest.java
index 374c3fd..0822971 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnonymousTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnonymousTest.java
@@ -4,12 +4,13 @@
 
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
+import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
 import static org.hamcrest.MatcherAssert.assertThat;
 
 import com.android.tools.r8.KotlinTestParameters;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.kotlin.KotlinMetadataWriter;
 import com.android.tools.r8.shaking.ProguardKeepAttributes;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -53,7 +54,7 @@
             .setOutputPath(temp.newFolder().toPath())
             .compile();
     testForJvm()
-        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
+        .addRunClasspathFiles(getKotlinStdlibJar(kotlinc), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".anonymous_app.MainKt")
         .assertSuccessWithOutputLines(EXPECTED);
@@ -63,7 +64,7 @@
   public void testMetadataForLib() throws Exception {
     Path libJar =
         testForR8(parameters.getBackend())
-            .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+            .addClasspathFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
             .addProgramFiles(libJars.getForConfiguration(kotlinc, targetVersion))
             .addKeepAllClassesRuleWithAllowObfuscation()
             .addKeepRules("-keep class " + PKG + ".anonymous_lib.Test$A { *; }")
@@ -73,7 +74,6 @@
                 ProguardKeepAttributes.SIGNATURE,
                 ProguardKeepAttributes.INNER_CLASSES,
                 ProguardKeepAttributes.ENCLOSING_METHOD)
-            .addDontWarnJetBrainsNotNullAnnotation()
             .compile()
             .inspect(this::inspect)
             .writeToZip();
@@ -84,7 +84,7 @@
             .setOutputPath(temp.newFolder().toPath())
             .compile();
     testForJvm()
-        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
+        .addRunClasspathFiles(getKotlinStdlibJar(kotlinc), libJar)
         .addClasspath(main)
         .run(parameters.getRuntime(), PKG + ".anonymous_app.MainKt")
         .assertSuccessWithOutputLines(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteBoxedTypesTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteBoxedTypesTest.java
index 16d3765..1cd0805 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteBoxedTypesTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteBoxedTypesTest.java
@@ -4,6 +4,8 @@
 
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
+import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static junit.framework.TestCase.assertEquals;
 import static junit.framework.TestCase.assertNotNull;
@@ -62,7 +64,7 @@
             .setOutputPath(temp.newFolder().toPath())
             .compile();
     testForJvm()
-        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
+        .addRunClasspathFiles(getKotlinStdlibJar(kotlinc), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".box_primitives_app.MainKt")
         .assertSuccessWithOutput(EXPECTED);
@@ -80,7 +82,7 @@
     testForJvm()
         .addVmArguments("-ea")
         .addRunClasspathFiles(
-            ToolHelper.getKotlinStdlibJar(kotlinc), ToolHelper.getKotlinReflectJar(kotlinc), libJar)
+            getKotlinStdlibJar(kotlinc), ToolHelper.getKotlinReflectJar(kotlinc), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".box_primitives_app.Main_reflectKt")
         .assertSuccessWithOutput(EXPECTED);
@@ -90,7 +92,7 @@
   public void testMetadataForLib() throws Exception {
     Path libJar =
         testForR8(parameters.getBackend())
-            .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+            .addClasspathFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
             .addProgramFiles(libJars.getForConfiguration(kotlinc, targetVersion))
             .addKeepAllClassesRule()
             .addKeepAttributes(
@@ -98,7 +100,6 @@
                 ProguardKeepAttributes.SIGNATURE,
                 ProguardKeepAttributes.INNER_CLASSES,
                 ProguardKeepAttributes.ENCLOSING_METHOD)
-            .addDontWarnJetBrainsAnnotations()
             .compile()
             .inspect(this::inspect)
             .writeToZip();
@@ -110,7 +111,7 @@
             .compile();
     testForJvm()
         .addRunClasspathFiles(
-            ToolHelper.getKotlinStdlibJar(kotlinc), ToolHelper.getKotlinReflectJar(kotlinc), libJar)
+            getKotlinStdlibJar(kotlinc), ToolHelper.getKotlinReflectJar(kotlinc), libJar)
         .addClasspath(main)
         .run(parameters.getRuntime(), PKG + ".box_primitives_app.MainKt")
         .assertSuccessWithOutput(EXPECTED);
@@ -147,7 +148,7 @@
   public void testMetadataForReflect() throws Exception {
     Path libJar =
         testForR8(parameters.getBackend())
-            .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+            .addClasspathFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
             .addProgramFiles(libJars.getForConfiguration(kotlinc, targetVersion))
             .addKeepAllClassesRule()
             .addKeepAttributes(
@@ -155,7 +156,6 @@
                 ProguardKeepAttributes.SIGNATURE,
                 ProguardKeepAttributes.INNER_CLASSES,
                 ProguardKeepAttributes.ENCLOSING_METHOD)
-            .addDontWarnJetBrainsAnnotations()
             .compile()
             .writeToZip();
     Path main =
@@ -167,7 +167,7 @@
     testForJvm()
         .addVmArguments("-ea")
         .addRunClasspathFiles(
-            ToolHelper.getKotlinStdlibJar(kotlinc), ToolHelper.getKotlinReflectJar(kotlinc), libJar)
+            getKotlinStdlibJar(kotlinc), ToolHelper.getKotlinReflectJar(kotlinc), libJar)
         .addClasspath(main)
         .run(parameters.getRuntime(), PKG + ".box_primitives_app.Main_reflectKt")
         .assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteCrossinlineAnonFunctionTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteCrossinlineAnonFunctionTest.java
index a8ccc76..5e64b54 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteCrossinlineAnonFunctionTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteCrossinlineAnonFunctionTest.java
@@ -4,9 +4,11 @@
 
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
+import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
+
 import com.android.tools.r8.KotlinTestParameters;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.StringUtils;
 import java.nio.file.Path;
@@ -51,7 +53,7 @@
             .setOutputPath(temp.newFolder().toPath())
             .compile();
     testForJvm()
-        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
+        .addRunClasspathFiles(getKotlinStdlibJar(kotlinc), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG_APP + ".MainKt")
         .assertSuccessWithOutput(EXPECTED);
@@ -62,10 +64,9 @@
     Path libJar =
         testForR8(parameters.getBackend())
             .addProgramFiles(libJars.getForConfiguration(kotlinc, targetVersion))
-            .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+            .addClasspathFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
             .addKeepAllClassesRule()
             .addKeepAllAttributes()
-            .addDontWarnJetBrainsNotNullAnnotation()
             .compile()
             .writeToZip();
     Path output =
@@ -75,7 +76,7 @@
                 getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
             .compile();
     testForJvm()
-        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
+        .addRunClasspathFiles(getKotlinStdlibJar(kotlinc), libJar)
         .addProgramFiles(output)
         .run(parameters.getRuntime(), PKG_APP + ".MainKt")
         .assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteCrossinlineConcreteFunctionTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteCrossinlineConcreteFunctionTest.java
index 9c138bf..8ca888c 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteCrossinlineConcreteFunctionTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteCrossinlineConcreteFunctionTest.java
@@ -4,9 +4,11 @@
 
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
+import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
+
 import com.android.tools.r8.KotlinTestParameters;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.StringUtils;
 import java.nio.file.Path;
@@ -51,7 +53,7 @@
             .setOutputPath(temp.newFolder().toPath())
             .compile();
     testForJvm()
-        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
+        .addRunClasspathFiles(getKotlinStdlibJar(kotlinc), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG_APP + ".MainKt")
         .assertSuccessWithOutput(EXPECTED);
@@ -62,10 +64,9 @@
     Path libJar =
         testForR8(parameters.getBackend())
             .addProgramFiles(libJars.getForConfiguration(kotlinc, targetVersion))
-            .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+            .addClasspathFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
             .addKeepAllClassesRule()
             .addKeepAllAttributes()
-            .addDontWarnJetBrainsNotNullAnnotation()
             .compile()
             .writeToZip();
     Path output =
@@ -76,7 +77,7 @@
             .setOutputPath(temp.newFolder().toPath())
             .compile();
     testForJvm()
-        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
+        .addRunClasspathFiles(getKotlinStdlibJar(kotlinc), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG_APP + ".MainKt")
         .assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDelegatedPropertyTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDelegatedPropertyTest.java
index 564cd64..3752a9e 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDelegatedPropertyTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDelegatedPropertyTest.java
@@ -4,9 +4,12 @@
 
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
+import static com.android.tools.r8.ToolHelper.getKotlinReflectJar;
+import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
+
 import com.android.tools.r8.KotlinTestParameters;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.shaking.ProguardKeepAttributes;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.StringUtils;
@@ -51,8 +54,7 @@
   @Test
   public void smokeTest() throws Exception {
     testForJvm()
-        .addRunClasspathFiles(
-            ToolHelper.getKotlinStdlibJar(kotlinc), ToolHelper.getKotlinReflectJar(kotlinc))
+        .addRunClasspathFiles(getKotlinStdlibJar(kotlinc), getKotlinReflectJar(kotlinc))
         .addClasspath(jars.getForConfiguration(kotlinc, targetVersion))
         .run(parameters.getRuntime(), PKG_APP + ".MainKt")
         .assertSuccessWithOutput(EXPECTED_MAIN);
@@ -64,11 +66,12 @@
     Path outputJar =
         testForR8(parameters.getBackend())
             .addClasspathFiles(
-                ToolHelper.getKotlinStdlibJar(kotlinc), ToolHelper.getKotlinReflectJar(kotlinc))
+                getKotlinStdlibJar(kotlinc),
+                getKotlinReflectJar(kotlinc),
+                getKotlinAnnotationJar(kotlinc))
             .addProgramFiles(jars.getForConfiguration(kotlinc, targetVersion))
             .addKeepAllClassesRule()
             .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
-            .addDontWarnJetBrainsAnnotations()
             .compile()
             .inspect(
                 inspector ->
@@ -77,8 +80,7 @@
                         inspector))
             .writeToZip();
     testForJvm()
-        .addRunClasspathFiles(
-            ToolHelper.getKotlinStdlibJar(kotlinc), ToolHelper.getKotlinReflectJar(kotlinc))
+        .addRunClasspathFiles(getKotlinStdlibJar(kotlinc), getKotlinReflectJar(kotlinc))
         .addClasspath(outputJar)
         .run(parameters.getRuntime(), PKG_APP + ".MainKt")
         .assertSuccessWithOutput(EXPECTED_MAIN);
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDependentKeep.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDependentKeep.java
index 3f42968..ef9c705 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDependentKeep.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDependentKeep.java
@@ -4,13 +4,15 @@
 
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
+import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
+import static org.hamcrest.CoreMatchers.equalTo;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.KotlinTestParameters;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.shaking.ProguardKeepAttributes;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -43,13 +45,14 @@
   @Test
   public void testR8() throws CompilationFailedException, IOException, ExecutionException {
     testForR8(parameters.getBackend())
-        .addProgramFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+        .addProgramFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
         .setMinApi(parameters.getApiLevel())
         .addKeepKotlinMetadata()
         .addKeepRules(StringUtils.joinLines("-if class *.Metadata", "-keep class <1>.io.** { *; }"))
         .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
-        .addDontWarnJetBrainsAnnotations()
+        .allowDiagnosticWarningMessages()
         .compile()
+        .assertAllWarningMessagesMatch(equalTo("Resource 'META-INF/MANIFEST.MF' already exists."))
         .inspect(this::inspect);
   }
 
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDoNotEmitValuesIfEmpty.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDoNotEmitValuesIfEmpty.java
index 1caec7d..2558cbb 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDoNotEmitValuesIfEmpty.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDoNotEmitValuesIfEmpty.java
@@ -4,12 +4,14 @@
 
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
+import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
+import static org.hamcrest.CoreMatchers.equalTo;
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
 
 import com.android.tools.r8.KotlinTestParameters;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.graph.DexAnnotationElement;
 import com.android.tools.r8.shaking.ProguardKeepAttributes;
 import com.android.tools.r8.utils.codeinspector.AnnotationSubject;
@@ -45,13 +47,14 @@
   @Test
   public void testKotlinStdLib() throws Exception {
     testForR8(parameters.getBackend())
-        .addProgramFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+        .addProgramFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
         .setMinApi(parameters.getApiLevel())
         .addKeepAllClassesRule()
         .addKeepKotlinMetadata()
         .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
-        .addDontWarnJetBrainsAnnotations()
+        .allowDiagnosticWarningMessages()
         .compile()
+        .assertAllWarningMessagesMatch(equalTo("Resource 'META-INF/MANIFEST.MF' already exists."))
         .inspect(this::inspectEmptyValuesAreNotPresent);
   }
 
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteFlexibleUpperBoundTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteFlexibleUpperBoundTest.java
index 91ede26..527269c 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteFlexibleUpperBoundTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteFlexibleUpperBoundTest.java
@@ -4,6 +4,8 @@
 
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
+import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
@@ -64,7 +66,7 @@
             .setOutputPath(temp.newFolder().toPath())
             .compile();
     testForJvm()
-        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
+        .addRunClasspathFiles(getKotlinStdlibJar(kotlinc), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".flexible_upper_bound_app.MainKt")
         .assertSuccessWithOutput(EXPECTED);
@@ -74,7 +76,7 @@
   public void testMetadataForLib() throws Exception {
     Path libJar =
         testForR8(parameters.getBackend())
-            .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+            .addClasspathFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
             .addProgramFiles(libJars.getForConfiguration(kotlinc, targetVersion))
             // Allow renaming A to ensure that we rename in the flexible upper bound type.
             .addKeepRules("-keep,allowobfuscation class " + PKG_LIB + ".A { *; }")
@@ -85,7 +87,6 @@
                 ProguardKeepAttributes.SIGNATURE,
                 ProguardKeepAttributes.INNER_CLASSES,
                 ProguardKeepAttributes.ENCLOSING_METHOD)
-            .addDontWarnJetBrainsNotNullAnnotation()
             .compile()
             .inspect(this::inspect)
             .writeToZip();
@@ -97,7 +98,7 @@
             .compile();
     testForJvm()
         .addRunClasspathFiles(
-            ToolHelper.getKotlinStdlibJar(kotlinc), ToolHelper.getKotlinReflectJar(kotlinc), libJar)
+            getKotlinStdlibJar(kotlinc), ToolHelper.getKotlinReflectJar(kotlinc), libJar)
         .addClasspath(main)
         .run(parameters.getRuntime(), PKG + ".flexible_upper_bound_app.MainKt")
         .assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInClasspathTypeTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInClasspathTypeTest.java
index eebb77f..4c712d3 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInClasspathTypeTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInClasspathTypeTest.java
@@ -3,6 +3,8 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
+import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isExtensionFunction;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
@@ -12,7 +14,6 @@
 
 import com.android.tools.r8.KotlinTestParameters;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.shaking.ProguardKeepAttributes;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -70,7 +71,7 @@
             .compile();
 
     testForJvm()
-        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), baseLibJar, extLibJar)
+        .addRunClasspathFiles(getKotlinStdlibJar(kotlinc), baseLibJar, extLibJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".classpath_app.MainKt")
         .assertSuccessWithOutput(EXPECTED);
@@ -81,7 +82,8 @@
     Path baseLibJar = baseLibJarMap.getForConfiguration(kotlinc, targetVersion);
     Path libJar =
         testForR8(parameters.getBackend())
-            .addClasspathFiles(baseLibJar, ToolHelper.getKotlinStdlibJar(kotlinc))
+            .addClasspathFiles(
+                baseLibJar, getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
             .addProgramFiles(extLibJarMap.getForConfiguration(kotlinc, targetVersion))
             // Keep the Extra class and its interface (which has the method).
             .addKeepRules("-keep class **.Extra")
@@ -91,7 +93,6 @@
             // to be called with Kotlin syntax from other kotlin code.
             .addKeepRules("-keep class **.ImplKt { <methods>; }")
             .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
-            .addDontWarnJetBrainsNotNullAnnotation()
             .compile()
             .inspect(this::inspectRenamed)
             .writeToZip();
@@ -104,7 +105,7 @@
             .compile();
 
     testForJvm()
-        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), baseLibJar, libJar)
+        .addRunClasspathFiles(getKotlinStdlibJar(kotlinc), baseLibJar, libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".classpath_app.MainKt")
         .assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInCompanionTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInCompanionTest.java
index 9106a3b..0cedda8 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInCompanionTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInCompanionTest.java
@@ -3,6 +3,8 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
+import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
@@ -13,7 +15,6 @@
 
 import com.android.tools.r8.KotlinTestParameters;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.shaking.ProguardKeepAttributes;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -70,7 +71,7 @@
             .compile();
 
     testForJvm()
-        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
+        .addRunClasspathFiles(getKotlinStdlibJar(kotlinc), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".companion_app.MainKt")
         .assertSuccessWithOutput(EXPECTED);
@@ -80,7 +81,7 @@
   public void testMetadataInCompanion_kept() throws Exception {
     Path libJar =
         testForR8(parameters.getBackend())
-            .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+            .addClasspathFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
             .addProgramFiles(companionLibJarMap.getForConfiguration(kotlinc, targetVersion))
             // Keep everything
             .addKeepRules("-keep class **.companion_lib.** { *; }")
@@ -90,7 +91,6 @@
             // To keep ...$Companion structure
             .addKeepAttributes(ProguardKeepAttributes.INNER_CLASSES)
             .addKeepAttributes(ProguardKeepAttributes.ENCLOSING_METHOD)
-            .addDontWarnJetBrainsNotNullAnnotation()
             .compile()
             .inspect(codeInspector -> inspect(codeInspector, true))
             .writeToZip();
@@ -103,7 +103,7 @@
             .compile();
 
     testForJvm()
-        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
+        .addRunClasspathFiles(getKotlinStdlibJar(kotlinc), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".companion_app.MainKt")
         .assertSuccessWithOutput(EXPECTED);
@@ -113,7 +113,7 @@
   public void testMetadataInCompanion_renamed() throws Exception {
     Path libJar =
         testForR8(parameters.getBackend())
-            .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+            .addClasspathFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
             .addProgramFiles(companionLibJarMap.getForConfiguration(kotlinc, targetVersion))
             // Keep the B class and its interface (which has the doStuff method).
             .addKeepRules("-keep class **.B")
@@ -133,7 +133,6 @@
             // To keep ...$Companion structure
             .addKeepAttributes(ProguardKeepAttributes.INNER_CLASSES)
             .addKeepAttributes(ProguardKeepAttributes.ENCLOSING_METHOD)
-            .addDontWarnJetBrainsNotNullAnnotation()
             .compile()
             .inspect(codeInspector -> inspect(codeInspector, false))
             .writeToZip();
@@ -146,7 +145,7 @@
             .compile();
 
     testForJvm()
-        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
+        .addRunClasspathFiles(getKotlinStdlibJar(kotlinc), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".companion_app.MainKt")
         .assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionFunctionTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionFunctionTest.java
index f46402b..bc5f909 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionFunctionTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionFunctionTest.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isExtensionFunction;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
@@ -78,7 +79,9 @@
   public void testMetadataInExtensionFunction_merged() throws Exception {
     Path libJar =
         testForR8(parameters.getBackend())
-            .addProgramFiles(extLibJarMap.getForConfiguration(kotlinc, targetVersion))
+            .addProgramFiles(
+                extLibJarMap.getForConfiguration(kotlinc, targetVersion),
+                getKotlinAnnotationJar(kotlinc))
             // Keep the B class and its interface (which has the doStuff method).
             .addKeepRules("-keep class **.B")
             .addKeepRules("-keep class **.I { <methods>; }")
@@ -89,7 +92,6 @@
             .addKeepAttributes(ProguardKeepAttributes.SIGNATURE)
             .addKeepAttributes(ProguardKeepAttributes.INNER_CLASSES)
             .addKeepAttributes(ProguardKeepAttributes.ENCLOSING_METHOD)
-            .addDontWarnJetBrainsNotNullAnnotation()
             .compile()
             .inspect(this::inspectMerged)
             .writeToZip();
@@ -130,7 +132,8 @@
   public void testMetadataInExtensionFunction_renamed() throws Exception {
     Path libJar =
         testForR8(parameters.getBackend())
-            .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+            .addClasspathFiles(
+                ToolHelper.getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
             .addProgramFiles(extLibJarMap.getForConfiguration(kotlinc, targetVersion))
             // Keep the B class and its interface (which has the doStuff method).
             .addKeepRules("-keep class **.B")
@@ -144,7 +147,6 @@
             .addKeepAttributes(ProguardKeepAttributes.SIGNATURE)
             .addKeepAttributes(ProguardKeepAttributes.INNER_CLASSES)
             .addKeepAttributes(ProguardKeepAttributes.ENCLOSING_METHOD)
-            .addDontWarnJetBrainsNotNullAnnotation()
             .compile()
             .inspect(this::inspectRenamed)
             .writeToZip();
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionPropertyTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionPropertyTest.java
index c2a923f..90e914d 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionPropertyTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionPropertyTest.java
@@ -3,6 +3,8 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
+import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isExtensionFunction;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isExtensionProperty;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
@@ -15,7 +17,6 @@
 
 import com.android.tools.r8.KotlinTestParameters;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.shaking.ProguardKeepAttributes;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -66,7 +67,7 @@
             .compile();
 
     testForJvm()
-        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
+        .addRunClasspathFiles(getKotlinStdlibJar(kotlinc), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".extension_property_app.MainKt")
         .assertSuccessWithOutput(EXPECTED);
@@ -77,7 +78,9 @@
   public void testMetadataInExtensionProperty_merged() throws Exception {
     Path libJar =
         testForR8(parameters.getBackend())
-            .addProgramFiles(extLibJarMap.getForConfiguration(kotlinc, targetVersion))
+            .addProgramFiles(
+                extLibJarMap.getForConfiguration(kotlinc, targetVersion),
+                getKotlinAnnotationJar(kotlinc))
             // Keep the B class and its interface (which has the doStuff method).
             .addKeepRules("-keep class **.B")
             .addKeepRules("-keep class **.I { <methods>; }")
@@ -85,7 +88,6 @@
             // to be called with Kotlin syntax from other kotlin code.
             .addKeepRules("-keep class **.BKt { <methods>; }")
             .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
-            .addDontWarnJetBrainsNotNullAnnotation()
             .compile()
             .inspect(this::inspectMerged)
             .writeToZip();
@@ -98,7 +100,7 @@
             .compile();
 
     testForJvm()
-        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
+        .addRunClasspathFiles(getKotlinStdlibJar(kotlinc), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".extension_property_app.MainKt")
         .assertSuccessWithOutput(EXPECTED);
@@ -138,7 +140,7 @@
   public void testMetadataInExtensionProperty_renamed() throws Exception {
     Path libJar =
         testForR8(parameters.getBackend())
-            .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+            .addClasspathFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
             .addProgramFiles(extLibJarMap.getForConfiguration(kotlinc, targetVersion))
             // Keep the B class and its interface (which has the doStuff method).
             .addKeepRules("-keep class **.B")
@@ -149,7 +151,6 @@
             // to be called with Kotlin syntax from other kotlin code.
             .addKeepRules("-keep class **.BKt { <methods>; }")
             .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
-            .addDontWarnJetBrainsNotNullAnnotation()
             .compile()
             .inspect(this::inspectRenamed)
             .writeToZip();
@@ -162,7 +163,7 @@
             .compile();
 
     testForJvm()
-        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
+        .addRunClasspathFiles(getKotlinStdlibJar(kotlinc), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".extension_property_app.MainKt")
         .assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionTest.java
index 48044e2..24a19d3 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionTest.java
@@ -3,6 +3,8 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
+import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isExtensionFunction;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
@@ -14,7 +16,6 @@
 
 import com.android.tools.r8.KotlinTestParameters;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.shaking.ProguardKeepAttributes;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -65,7 +66,7 @@
             .compile();
 
     testForJvm()
-        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
+        .addRunClasspathFiles(getKotlinStdlibJar(kotlinc), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".function_app.MainKt")
         .assertSuccessWithOutput(EXPECTED);
@@ -76,14 +77,15 @@
   public void testMetadataInFunction_merged() throws Exception {
     Path libJar =
         testForR8(parameters.getBackend())
-            .addProgramFiles(funLibJarMap.getForConfiguration(kotlinc, targetVersion))
+            .addProgramFiles(
+                funLibJarMap.getForConfiguration(kotlinc, targetVersion),
+                getKotlinAnnotationJar(kotlinc))
             // Keep the B class and its interface (which has the doStuff method).
             .addKeepRules("-keep class **.B")
             .addKeepRules("-keep class **.I { <methods>; }")
             // Keep the BKt method, which will be called from other kotlin code.
             .addKeepRules("-keep class **.BKt { <methods>; }")
             .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
-            .addDontWarnJetBrainsNotNullAnnotation()
             .compile()
             .inspect(this::inspectMerged)
             .writeToZip();
@@ -96,7 +98,7 @@
             .compile();
 
     testForJvm()
-        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
+        .addRunClasspathFiles(getKotlinStdlibJar(kotlinc), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".function_app.MainKt")
         .assertSuccessWithOutput(EXPECTED);
@@ -135,7 +137,7 @@
   public void testMetadataInFunction_renamed() throws Exception {
     Path libJar =
         testForR8(parameters.getBackend())
-            .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+            .addClasspathFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
             .addProgramFiles(funLibJarMap.getForConfiguration(kotlinc, targetVersion))
             // Keep the B class and its interface (which has the doStuff method).
             .addKeepRules("-keep class **.B")
@@ -145,7 +147,6 @@
             // Keep the BKt method, which will be called from other kotlin code.
             .addKeepRules("-keep class **.BKt { <methods>; }")
             .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
-            .addDontWarnJetBrainsNotNullAnnotation()
             .compile()
             .inspect(this::inspectRenamed)
             .writeToZip();
@@ -158,7 +159,7 @@
             .compile();
 
     testForJvm()
-        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
+        .addRunClasspathFiles(getKotlinStdlibJar(kotlinc), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".function_app.MainKt")
         .assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionWithDefaultValueTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionWithDefaultValueTest.java
index 746c690..dc2ddce 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionWithDefaultValueTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionWithDefaultValueTest.java
@@ -3,6 +3,9 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.ToolHelper.getJava8RuntimeJar;
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
+import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isExtensionFunction;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
@@ -13,7 +16,6 @@
 
 import com.android.tools.r8.KotlinTestParameters;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.shaking.ProguardKeepAttributes;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -65,7 +67,7 @@
             .compile();
 
     testForJvm()
-        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
+        .addRunClasspathFiles(getKotlinStdlibJar(kotlinc), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".default_value_app.MainKt")
         .assertSuccessWithOutput(EXPECTED);
@@ -76,7 +78,7 @@
     Path libJar =
         testForR8(parameters.getBackend())
             .addLibraryFiles(
-                ToolHelper.getJava8RuntimeJar(), ToolHelper.getKotlinStdlibJar(kotlinc))
+                getJava8RuntimeJar(), getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
             .addProgramFiles(defaultValueLibJarMap.getForConfiguration(kotlinc, targetVersion))
             // Keep LibKt and applyMap function, along with applyMap$default
             .addKeepRules("-keep class **.LibKt { *** applyMap*(...); }")
@@ -84,7 +86,6 @@
             .addKeepAttributes(ProguardKeepAttributes.SIGNATURE)
             .addKeepAttributes(ProguardKeepAttributes.INNER_CLASSES)
             .addKeepAttributes(ProguardKeepAttributes.ENCLOSING_METHOD)
-            .addDontWarnJetBrainsNotNullAnnotation()
             .compile()
             .inspect(this::inspect)
             .writeToZip();
@@ -97,7 +98,7 @@
             .compile();
 
     testForJvm()
-        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
+        .addRunClasspathFiles(getKotlinStdlibJar(kotlinc), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".default_value_app.MainKt")
         .assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionWithVarargTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionWithVarargTest.java
index 262d8a2..ec249cb 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionWithVarargTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionWithVarargTest.java
@@ -3,6 +3,8 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
+import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isExtensionFunction;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
@@ -14,7 +16,6 @@
 
 import com.android.tools.r8.KotlinTestParameters;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.shaking.ProguardKeepAttributes;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -66,7 +67,7 @@
             .compile();
 
     testForJvm()
-        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
+        .addRunClasspathFiles(getKotlinStdlibJar(kotlinc), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".vararg_app.MainKt")
         .assertSuccessWithOutput(EXPECTED);
@@ -76,7 +77,7 @@
   public void testMetadataInFunctionWithVararg() throws Exception {
     Path libJar =
         testForR8(parameters.getBackend())
-            .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+            .addClasspathFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
             .addProgramFiles(varargLibJarMap.getForConfiguration(kotlinc, targetVersion))
             // keep SomeClass#foo, since there is a method reference in the app.
             .addKeepRules("-keep class **.SomeClass { *** foo(...); }")
@@ -86,7 +87,6 @@
             .addKeepAttributes(ProguardKeepAttributes.SIGNATURE)
             .addKeepAttributes(ProguardKeepAttributes.INNER_CLASSES)
             .addKeepAttributes(ProguardKeepAttributes.ENCLOSING_METHOD)
-            .addDontWarnJetBrainsNotNullAnnotation()
             .compile()
             .inspect(this::inspect)
             .writeToZip();
@@ -99,7 +99,7 @@
             .compile();
 
     testForJvm()
-        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
+        .addRunClasspathFiles(getKotlinStdlibJar(kotlinc), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".vararg_app.MainKt")
         .assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInLibraryTypeTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInLibraryTypeTest.java
index 5b7d4e6..598087a 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInLibraryTypeTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInLibraryTypeTest.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
 import static org.hamcrest.CoreMatchers.anyOf;
@@ -86,7 +87,8 @@
             // Intentionally not providing baseLibJar as lib file nor classpath file.
             .addProgramFiles(
                 extLibJarMap.getForConfiguration(kotlinc, targetVersion),
-                appJarMap.getForConfiguration(kotlinc, targetVersion))
+                appJarMap.getForConfiguration(kotlinc, targetVersion),
+                getKotlinAnnotationJar(kotlinc))
             // Keep Ext extension method which requires metadata to be called with Kotlin syntax
             // from other kotlin code.
             .addKeepRules("-keep class **.ExtKt { <methods>; }")
@@ -94,7 +96,6 @@
             .addKeepMainRule(main)
             .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
             .addDontWarn(PKG + ".**")
-            .addDontWarnJetBrainsNotNullAnnotation()
             .allowDiagnosticWarningMessages()
             // -dontoptimize so that basic code structure is kept.
             .noOptimization()
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInMultifileClassTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInMultifileClassTest.java
index 6411cfc..593b124 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInMultifileClassTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInMultifileClassTest.java
@@ -3,6 +3,8 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
+import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isExtensionFunction;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
@@ -17,7 +19,6 @@
 
 import com.android.tools.r8.KotlinTestParameters;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.ToolHelper.ProcessResult;
 import com.android.tools.r8.shaking.ProguardKeepAttributes;
 import com.android.tools.r8.utils.DescriptorUtils;
@@ -72,7 +73,7 @@
             .compile();
 
     testForJvm()
-        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
+        .addRunClasspathFiles(getKotlinStdlibJar(kotlinc), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".multifileclass_app.MainKt")
         .assertSuccessWithOutput(EXPECTED);
@@ -82,13 +83,12 @@
   public void testMetadataInMultifileClass_merged() throws Exception {
     Path libJar =
         testForR8(parameters.getBackend())
-            .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+            .addClasspathFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
             .addProgramFiles(multifileLibJarMap.getForConfiguration(kotlinc, targetVersion))
             // Keep UtilKt#comma*Join*(). Let R8 optimize (inline) others, such as joinOf*(String).
             .addKeepRules("-keep class **.UtilKt")
             .addKeepRules("-keepclassmembers class * { ** comma*Join*(...); }")
             .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
-            .addDontWarnJetBrainsNotNullAnnotation()
             .compile()
             .inspect(this::inspectMerged)
             .writeToZip();
@@ -124,7 +124,7 @@
   public void testMetadataInMultifileClass_renamed() throws Exception {
     Path libJar =
         testForR8(parameters.getBackend())
-            .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+            .addClasspathFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
             .addProgramFiles(multifileLibJarMap.getForConfiguration(kotlinc, targetVersion))
             // Keep UtilKt#comma*Join*().
             .addKeepRules("-keep class **.UtilKt")
@@ -133,7 +133,6 @@
             // Keep yet rename joinOf*(String).
             .addKeepRules("-keepclassmembers,allowobfuscation class * { ** joinOf*(...); }")
             .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
-            .addDontWarnJetBrainsNotNullAnnotation()
             .compile()
             .inspect(this::inspectRenamed)
             .writeToZip();
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInParameterTypeTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInParameterTypeTest.java
index abce684..27ee400 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInParameterTypeTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInParameterTypeTest.java
@@ -3,6 +3,8 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
+import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
@@ -11,7 +13,6 @@
 
 import com.android.tools.r8.KotlinTestParameters;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.shaking.ProguardKeepAttributes;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -58,7 +59,7 @@
             .compile();
 
     testForJvm()
-        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
+        .addRunClasspathFiles(getKotlinStdlibJar(kotlinc), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".parametertype_app.MainKt")
         .assertSuccessWithOutput(EXPECTED);
@@ -68,14 +69,13 @@
   public void testMetadataInParameterType_renamed() throws Exception {
     Path libJar =
         testForR8(parameters.getBackend())
-            .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+            .addClasspathFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
             .addProgramFiles(parameterTypeLibJarMap.getForConfiguration(kotlinc, targetVersion))
             // Keep non-private members of Impl
             .addKeepRules("-keep public class **.Impl { !private *; }")
             // Keep Itf, but allow minification.
             .addKeepRules("-keep,allowobfuscation class **.Itf")
             .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
-            .addDontWarnJetBrainsNotNullAnnotation()
             .compile()
             .inspect(this::inspect)
             .writeToZip();
@@ -88,7 +88,7 @@
             .compile();
 
     testForJvm()
-        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
+        .addRunClasspathFiles(getKotlinStdlibJar(kotlinc), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".parametertype_app.MainKt")
         .assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTest.java
index 693c7fc..401087b 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTest.java
@@ -3,6 +3,8 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
+import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isExtensionProperty;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
@@ -15,7 +17,6 @@
 
 import com.android.tools.r8.KotlinTestParameters;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.shaking.ProguardKeepAttributes;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -65,7 +66,7 @@
             .compile();
 
     testForJvm()
-        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
+        .addRunClasspathFiles(getKotlinStdlibJar(kotlinc), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".fragile_property_only_getter.Getter_userKt")
         .assertSuccessWithOutput(EXPECTED_GETTER);
@@ -75,13 +76,12 @@
   public void testMetadataInProperty_getterOnly() throws Exception {
     Path libJar =
         testForR8(parameters.getBackend())
-            .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+            .addClasspathFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
             .addProgramFiles(propertyTypeLibJarMap.getForConfiguration(kotlinc, targetVersion))
             // Keep property getters
             .addKeepRules("-keep class **.Person { <init>(...); }")
             .addKeepRules("-keepclassmembers class **.Person { *** get*(); }")
             .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
-            .addDontWarnJetBrainsNotNullAnnotation()
             .compile()
             .inspect(this::inspectGetterOnly)
             .writeToZip();
@@ -95,7 +95,7 @@
             .compile();
 
     testForJvm()
-        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
+        .addRunClasspathFiles(getKotlinStdlibJar(kotlinc), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".fragile_property_only_getter.Getter_userKt")
         .assertSuccessWithOutput(EXPECTED_GETTER);
@@ -157,7 +157,7 @@
             .compile();
 
     testForJvm()
-        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
+        .addRunClasspathFiles(getKotlinStdlibJar(kotlinc), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".fragile_property_only_setter.Setter_userKt")
         .assertSuccessWithOutputLines();
@@ -167,7 +167,7 @@
   public void testMetadataInProperty_setterOnly() throws Exception {
     Path libJar =
         testForR8(parameters.getBackend())
-            .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+            .addClasspathFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
             .addProgramFiles(propertyTypeLibJarMap.getForConfiguration(kotlinc, targetVersion))
             // Keep property setters (and users)
             .addKeepRules("-keep class **.Person { <init>(...); }")
@@ -177,7 +177,6 @@
             // Keep LibKt extension methods
             .addKeepRules("-keep class **.LibKt { <methods>; }")
             .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
-            .addDontWarnJetBrainsNotNullAnnotation()
             .compile()
             .inspect(this::inspectSetterOnly)
             .writeToZip();
@@ -191,7 +190,7 @@
             .compile();
 
     testForJvm()
-        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
+        .addRunClasspathFiles(getKotlinStdlibJar(kotlinc), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".fragile_property_only_setter.Setter_userKt")
         .assertSuccessWithOutputLines();
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTypeTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTypeTest.java
index cb18acb..28721c8 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTypeTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTypeTest.java
@@ -3,6 +3,8 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
+import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
@@ -11,7 +13,6 @@
 
 import com.android.tools.r8.KotlinTestParameters;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.shaking.ProguardKeepAttributes;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -58,7 +59,7 @@
             .compile();
 
     testForJvm()
-        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
+        .addRunClasspathFiles(getKotlinStdlibJar(kotlinc), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".propertytype_app.MainKt")
         .assertSuccessWithOutput(EXPECTED);
@@ -68,12 +69,11 @@
   public void testMetadataInProperty_renamed() throws Exception {
     Path libJar =
         testForR8(parameters.getBackend())
-            .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+            .addClasspathFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
             .addProgramFiles(propertyTypeLibJarMap.getForConfiguration(kotlinc, targetVersion))
             // Keep non-private members of Impl
             .addKeepRules("-keep public class **.Impl { !private *; }")
             .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
-            .addDontWarnJetBrainsNotNullAnnotation()
             .compile()
             .inspect(this::inspect)
             .writeToZip();
@@ -86,7 +86,7 @@
             .compile();
 
     testForJvm()
-        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
+        .addRunClasspathFiles(getKotlinStdlibJar(kotlinc), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".propertytype_app.MainKt")
         .assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInReturnTypeTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInReturnTypeTest.java
index dbaf933..225ac74 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInReturnTypeTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInReturnTypeTest.java
@@ -3,6 +3,8 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
+import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
@@ -11,7 +13,6 @@
 
 import com.android.tools.r8.KotlinTestParameters;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.shaking.ProguardKeepAttributes;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -58,7 +59,7 @@
             .compile();
 
     testForJvm()
-        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
+        .addRunClasspathFiles(getKotlinStdlibJar(kotlinc), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".returntype_app.MainKt")
         .assertSuccessWithOutput(EXPECTED);
@@ -68,14 +69,13 @@
   public void testMetadataInReturnType_renamed() throws Exception {
     Path libJar =
         testForR8(parameters.getBackend())
-            .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+            .addClasspathFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
             .addProgramFiles(returnTypeLibJarMap.getForConfiguration(kotlinc, targetVersion))
             // Keep non-private members of Impl
             .addKeepRules("-keep public class **.Impl { !private *; }")
             // Keep Itf, but allow minification.
             .addKeepRules("-keep,allowobfuscation class **.Itf")
             .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
-            .addDontWarnJetBrainsNotNullAnnotation()
             .compile()
             .inspect(this::inspect)
             .writeToZip();
@@ -88,7 +88,7 @@
             .compile();
 
     testForJvm()
-        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
+        .addRunClasspathFiles(getKotlinStdlibJar(kotlinc), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".returntype_app.MainKt")
         .assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSealedClassNestedTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSealedClassNestedTest.java
index e479bba..defd730 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSealedClassNestedTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSealedClassNestedTest.java
@@ -3,6 +3,9 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
+import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
+
 import com.android.tools.r8.KotlinTestParameters;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.ToolHelper;
@@ -57,7 +60,7 @@
             .compile();
     testForJvm()
         .addRunClasspathFiles(
-            ToolHelper.getKotlinStdlibJar(kotlinc), ToolHelper.getKotlinReflectJar(kotlinc), libJar)
+            getKotlinStdlibJar(kotlinc), ToolHelper.getKotlinReflectJar(kotlinc), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG_APP + ".MainKt")
         .assertSuccessWithOutput(EXPECTED);
@@ -67,13 +70,12 @@
   public void testMetadataInSealedClass_nested() throws Exception {
     Path libJar =
         testForR8(parameters.getBackend())
-            .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+            .addClasspathFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
             .addProgramFiles(sealedLibJarMap.getForConfiguration(kotlinc, targetVersion))
             .addKeepAllClassesRule()
             .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
             .addKeepAttributes(
                 ProguardKeepAttributes.INNER_CLASSES, ProguardKeepAttributes.ENCLOSING_METHOD)
-            .addDontWarnJetBrainsAnnotations()
             .compile()
             .writeToZip();
     Path output =
@@ -85,7 +87,7 @@
             .compile();
     testForJvm()
         .addRunClasspathFiles(
-            ToolHelper.getKotlinStdlibJar(kotlinc), ToolHelper.getKotlinReflectJar(kotlinc), libJar)
+            getKotlinStdlibJar(kotlinc), ToolHelper.getKotlinReflectJar(kotlinc), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG_APP + ".MainKt")
         .assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSealedClassTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSealedClassTest.java
index 5156b72..90907da 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSealedClassTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSealedClassTest.java
@@ -3,6 +3,8 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
+import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
 import static com.android.tools.r8.utils.DescriptorUtils.descriptorToJavaType;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isExtensionFunction;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
@@ -16,7 +18,6 @@
 
 import com.android.tools.r8.KotlinTestParameters;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.ToolHelper.ProcessResult;
 import com.android.tools.r8.shaking.ProguardKeepAttributes;
 import com.android.tools.r8.utils.StringUtils;
@@ -65,7 +66,7 @@
             .compile();
 
     testForJvm()
-        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
+        .addRunClasspathFiles(getKotlinStdlibJar(kotlinc), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".sealed_app.ValidKt")
         .assertSuccessWithOutput(EXPECTED);
@@ -75,7 +76,7 @@
   public void testMetadataInSealedClass_valid() throws Exception {
     Path libJar =
         testForR8(parameters.getBackend())
-            .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+            .addClasspathFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
             .addProgramFiles(sealedLibJarMap.getForConfiguration(kotlinc, targetVersion))
             // Keep the Expr class
             .addKeepRules("-keep class **.Expr")
@@ -84,7 +85,6 @@
             // Keep the factory object and utils
             .addKeepRules("-keep class **.ExprFactory { *; }")
             .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
-            .addDontWarnJetBrainsAnnotations()
             .compile()
             .inspect(this::inspectValid)
             .writeToZip();
@@ -97,7 +97,7 @@
             .compile();
 
     testForJvm()
-        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
+        .addRunClasspathFiles(getKotlinStdlibJar(kotlinc), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".sealed_app.ValidKt")
         .assertSuccessWithOutput(EXPECTED);
@@ -143,14 +143,13 @@
   public void testMetadataInSealedClass_invalid() throws Exception {
     Path libJar =
         testForR8(parameters.getBackend())
-            .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+            .addClasspathFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
             .addProgramFiles(sealedLibJarMap.getForConfiguration(kotlinc, targetVersion))
             // Keep the Expr class
             .addKeepRules("-keep class **.Expr")
             // Keep the extension function
             .addKeepRules("-keep class **.LibKt { <methods>; }")
             .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
-            .addDontWarnJetBrainsNotNullAnnotation()
             .compile()
             .inspect(this::inspectInvalid)
             .writeToZip();
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeAliasTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeAliasTest.java
index 98102c5..0585af6 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeAliasTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeAliasTest.java
@@ -3,6 +3,9 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
+import static com.android.tools.r8.ToolHelper.getKotlinReflectJar;
+import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isDexClass;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
@@ -14,7 +17,6 @@
 
 import com.android.tools.r8.KotlinTestParameters;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.kotlin.Kotlin.ClassClassifiers;
 import com.android.tools.r8.shaking.ProguardKeepAttributes;
 import com.android.tools.r8.utils.DescriptorUtils;
@@ -89,8 +91,7 @@
             .compile();
 
     testForJvm()
-        .addRunClasspathFiles(
-            ToolHelper.getKotlinStdlibJar(kotlinc), ToolHelper.getKotlinReflectJar(kotlinc), libJar)
+        .addRunClasspathFiles(getKotlinStdlibJar(kotlinc), getKotlinReflectJar(kotlinc), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".typealias_app.MainKt")
         .assertSuccessWithOutput(EXPECTED);
@@ -103,7 +104,9 @@
     Path libJar =
         testForR8(parameters.getBackend())
             .addClasspathFiles(
-                ToolHelper.getKotlinStdlibJar(kotlinc), ToolHelper.getKotlinReflectJar(kotlinc))
+                getKotlinStdlibJar(kotlinc),
+                getKotlinReflectJar(kotlinc),
+                getKotlinAnnotationJar(kotlinc))
             .addProgramFiles(typeAliasLibJarMap.getForConfiguration(kotlinc, targetVersion))
             // Keep non-private members of Impl
             .addKeepRules("-keep class **.Impl { !private *; }")
@@ -126,7 +129,6 @@
                 ProguardKeepAttributes.SIGNATURE,
                 ProguardKeepAttributes.INNER_CLASSES,
                 ProguardKeepAttributes.ENCLOSING_METHOD)
-            .addDontWarnJetBrainsNotNullAnnotation()
             .compile()
             .inspect(this::inspect)
             .writeToZip();
@@ -138,8 +140,7 @@
             .compile();
 
     testForJvm()
-        .addRunClasspathFiles(
-            ToolHelper.getKotlinStdlibJar(kotlinc), ToolHelper.getKotlinReflectJar(kotlinc), libJar)
+        .addRunClasspathFiles(getKotlinStdlibJar(kotlinc), getKotlinReflectJar(kotlinc), libJar)
         .addClasspath(appJar)
         .run(parameters.getRuntime(), PKG + ".typealias_app.MainKt")
         .assertSuccessWithOutput(EXPECTED.replace(superTypeName, renamedSuperTypeName));
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeArgumentsTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeArgumentsTest.java
index 097c832..eddf514 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeArgumentsTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeArgumentsTest.java
@@ -3,6 +3,8 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
+import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isDexClass;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isExtensionFunction;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
@@ -13,7 +15,6 @@
 
 import com.android.tools.r8.KotlinTestParameters;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.shaking.ProguardKeepAttributes;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -103,7 +104,7 @@
             .compile();
 
     testForJvm()
-        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
+        .addRunClasspathFiles(getKotlinStdlibJar(kotlinc), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".typeargument_app.MainKt")
         .assertSuccessWithOutput(EXPECTED);
@@ -113,7 +114,7 @@
   public void testMetadataInTypeAliasWithR8() throws Exception {
     Path libJar =
         testForR8(parameters.getBackend())
-            .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+            .addClasspathFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
             .addProgramFiles(jarMap.getForConfiguration(kotlinc, targetVersion))
             // Keep ClassThatWillBeObfuscated, but allow minification.
             .addKeepRules("-keep,allowobfuscation class **ClassThatWillBeObfuscated")
@@ -130,7 +131,6 @@
                 ProguardKeepAttributes.SIGNATURE,
                 ProguardKeepAttributes.INNER_CLASSES,
                 ProguardKeepAttributes.ENCLOSING_METHOD)
-            .addDontWarnJetBrainsNotNullAnnotation()
             .compile()
             .inspect(this::inspect)
             .writeToZip();
@@ -140,7 +140,7 @@
             .addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/typeargument_app", "main"))
             .compile();
     testForJvm()
-        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
+        .addRunClasspathFiles(getKotlinStdlibJar(kotlinc), libJar)
         .addClasspath(mainJar)
         .run(parameters.getRuntime(), PKG + ".typeargument_app.MainKt")
         .assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInlinePropertyTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInlinePropertyTest.java
index d5e9e1a..ab449b7 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInlinePropertyTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInlinePropertyTest.java
@@ -4,6 +4,8 @@
 
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
+import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertNull;
@@ -59,7 +61,7 @@
             .setOutputPath(temp.newFolder().toPath())
             .compile();
     testForJvm()
-        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
+        .addRunClasspathFiles(getKotlinStdlibJar(kotlinc), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG + ".inline_property_app.MainKt")
         .assertSuccessWithOutput(EXPECTED);
@@ -69,7 +71,7 @@
   public void testMetadataForLib() throws Exception {
     Path libJar =
         testForR8(parameters.getBackend())
-            .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+            .addClasspathFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
             .addProgramFiles(libJars.getForConfiguration(kotlinc, targetVersion))
             // Allow renaming A to ensure that we rename in the flexible upper bound type.
             .addKeepAllClassesRule()
@@ -78,7 +80,6 @@
                 ProguardKeepAttributes.SIGNATURE,
                 ProguardKeepAttributes.INNER_CLASSES,
                 ProguardKeepAttributes.ENCLOSING_METHOD)
-            .addDontWarnJetBrainsNotNullAnnotation()
             .compile()
             .inspect(this::inspect)
             .writeToZip();
@@ -90,7 +91,7 @@
             .compile();
     testForJvm()
         .addRunClasspathFiles(
-            ToolHelper.getKotlinStdlibJar(kotlinc), ToolHelper.getKotlinReflectJar(kotlinc), libJar)
+            getKotlinStdlibJar(kotlinc), ToolHelper.getKotlinReflectJar(kotlinc), libJar)
         .addClasspath(main)
         .run(parameters.getRuntime(), PKG + ".inline_property_app.MainKt")
         .assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteJvmStaticTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteJvmStaticTest.java
index b31c838..605b16c 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteJvmStaticTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteJvmStaticTest.java
@@ -3,13 +3,14 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
+import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
 
 import com.android.tools.r8.KotlinTestParameters;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
 import com.android.tools.r8.kotlin.metadata.jvmstatic_app.MainJava;
 import com.android.tools.r8.shaking.ProguardKeepAttributes;
@@ -69,8 +70,7 @@
             .compile();
     testForJvm()
         .addRunClasspathFiles(
-            ToolHelper.getKotlinStdlibJar(kotlinc),
-            kotlincLibJar.getForConfiguration(kotlinc, targetVersion))
+            getKotlinStdlibJar(kotlinc), kotlincLibJar.getForConfiguration(kotlinc, targetVersion))
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG_APP + ".MainKt")
         .assertSuccessWithOutput(EXPECTED);
@@ -80,8 +80,7 @@
   public void smokeTestJava() throws Exception {
     testForJvm()
         .addRunClasspathFiles(
-            ToolHelper.getKotlinStdlibJar(kotlinc),
-            kotlincLibJar.getForConfiguration(kotlinc, targetVersion))
+            getKotlinStdlibJar(kotlinc), kotlincLibJar.getForConfiguration(kotlinc, targetVersion))
         .addProgramClassFileData(MainJava.dump())
         .run(parameters.getRuntime(), MainJava.class)
         .assertSuccessWithOutput(EXPECTED);
@@ -92,10 +91,9 @@
     Path libJar =
         testForR8(parameters.getBackend())
             .addProgramFiles(kotlincLibJar.getForConfiguration(kotlinc, targetVersion))
-            .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+            .addClasspathFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
             .addKeepAllClassesRule()
             .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
-            .addDontWarnJetBrainsNotNullAnnotation()
             .compile()
             .inspect(this::inspect)
             .writeToZip();
@@ -112,7 +110,7 @@
             .setOutputPath(temp.newFolder().toPath())
             .compile();
     testForJvm()
-        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
+        .addRunClasspathFiles(getKotlinStdlibJar(kotlinc), libJar)
         .addClasspath(output)
         .run(parameters.getRuntime(), PKG_APP + ".MainKt")
         .assertSuccessWithOutput(EXPECTED);
@@ -120,7 +118,7 @@
 
   private void testJava(Path libJar) throws Exception {
     testForJvm()
-        .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
+        .addRunClasspathFiles(getKotlinStdlibJar(kotlinc), libJar)
         .addProgramClassFileData(MainJava.dump())
         .run(parameters.getRuntime(), MainJava.class)
         .assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteKeepPathTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteKeepPathTest.java
index 1d6a41f..8d01e2e 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteKeepPathTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteKeepPathTest.java
@@ -4,6 +4,8 @@
 
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
+import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static org.hamcrest.CoreMatchers.equalTo;
 import static org.hamcrest.MatcherAssert.assertThat;
@@ -49,12 +51,11 @@
   public void testProgramPath() throws Exception {
     testForR8(parameters.getBackend())
         .addProgramFiles(libJars.getForConfiguration(kotlinc, targetVersion))
-        .addProgramFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+        .addProgramFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
         .addKeepRules("-keep class " + LIB_CLASS_NAME)
         .applyIf(keepMetadata, TestShrinkerBuilder::addKeepKotlinMetadata)
         .addKeepRuntimeVisibleAnnotations()
         .allowDiagnosticWarningMessages()
-        .addDontWarnJetBrainsAnnotations()
         .compile()
         .assertAllWarningMessagesMatch(equalTo("Resource 'META-INF/MANIFEST.MF' already exists."))
         .inspect(inspector -> inspect(inspector, keepMetadata));
@@ -64,10 +65,9 @@
   public void testClassPathPath() throws Exception {
     testForR8(parameters.getBackend())
         .addProgramFiles(libJars.getForConfiguration(kotlinc, targetVersion))
-        .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+        .addClasspathFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
         .addKeepRules("-keep class " + LIB_CLASS_NAME)
         .addKeepRuntimeVisibleAnnotations()
-        .addDontWarnJetBrainsNotNullAnnotation()
         .compile()
         .inspect(inspector -> inspect(inspector, true));
   }
@@ -76,11 +76,10 @@
   public void testLibraryPath() throws Exception {
     testForR8(parameters.getBackend())
         .addProgramFiles(libJars.getForConfiguration(kotlinc, targetVersion))
-        .addLibraryFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+        .addLibraryFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
         .addLibraryFiles(ToolHelper.getJava8RuntimeJar())
         .addKeepRules("-keep class " + LIB_CLASS_NAME)
         .addKeepRuntimeVisibleAnnotations()
-        .addDontWarnJetBrainsNotNullAnnotation()
         .compile()
         .inspect(inspector -> inspect(inspector, true));
   }
@@ -89,10 +88,9 @@
   public void testMissing() throws Exception {
     testForR8(parameters.getBackend())
         .addProgramFiles(libJars.getForConfiguration(kotlinc, targetVersion))
-        .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+        .addClasspathFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
         .addKeepRules("-keep class " + LIB_CLASS_NAME)
         .addKeepRuntimeVisibleAnnotations()
-        .addDontWarnJetBrainsNotNullAnnotation()
         .compile()
         .inspect(inspector -> inspect(inspector, true));
   }
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteKeepTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteKeepTest.java
index c8dd873..b49f740 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteKeepTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteKeepTest.java
@@ -4,12 +4,14 @@
 
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
+import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
+import static org.hamcrest.CoreMatchers.equalTo;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 
 import com.android.tools.r8.KotlinTestParameters;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.shaking.ProguardKeepAttributes;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
@@ -38,26 +40,28 @@
   @Test
   public void testR8() throws Exception {
     testForR8(parameters.getBackend())
-        .addProgramFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+        .addProgramFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
         .setMinApi(parameters.getApiLevel())
         .addKeepKotlinMetadata()
         .addKeepRules("-keep class kotlin.io.** { *; }")
         .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
-        .addDontWarnJetBrainsAnnotations()
+        .allowDiagnosticWarningMessages()
         .compile()
+        .assertAllWarningMessagesMatch(equalTo("Resource 'META-INF/MANIFEST.MF' already exists."))
         .inspect(this::inspect);
   }
 
   @Test
   public void testR8KeepIf() throws Exception {
     testForR8(parameters.getBackend())
-        .addProgramFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+        .addProgramFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
         .setMinApi(parameters.getApiLevel())
         .addKeepRules("-keep class kotlin.io.** { *; }")
         .addKeepRules("-if class *", "-keep class kotlin.Metadata { *; }")
         .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
-        .addDontWarnJetBrainsAnnotations()
+        .allowDiagnosticWarningMessages()
         .compile()
+        .assertAllWarningMessagesMatch(equalTo("Resource 'META-INF/MANIFEST.MF' already exists."))
         .inspect(this::inspect);
   }
 
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePassThroughTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePassThroughTest.java
index 99586b1..137d6f5 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePassThroughTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePassThroughTest.java
@@ -4,9 +4,12 @@
 
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
+import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
+import static org.hamcrest.CoreMatchers.equalTo;
+
 import com.android.tools.r8.KotlinTestParameters;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.shaking.ProguardKeepAttributes;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import java.util.Collection;
@@ -35,16 +38,16 @@
   @Test
   public void testKotlinStdLib() throws Exception {
     testForR8(parameters.getBackend())
-        .addProgramFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+        .addProgramFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
         .setMinApi(parameters.getApiLevel())
         .addKeepAllClassesRule()
         .addKeepKotlinMetadata()
         .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
-        .addDontWarnJetBrainsAnnotations()
+        .allowDiagnosticWarningMessages()
         .compile()
+        .assertAllWarningMessagesMatch(equalTo("Resource 'META-INF/MANIFEST.MF' already exists."))
         .inspect(
             inspector ->
-                assertEqualMetadata(
-                    new CodeInspector(ToolHelper.getKotlinStdlibJar(kotlinc)), inspector));
+                assertEqualMetadata(new CodeInspector(getKotlinStdlibJar(kotlinc)), inspector));
   }
 }
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataStripTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataStripTest.java
index 7afbd44..0e03e02 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataStripTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataStripTest.java
@@ -4,6 +4,8 @@
 package com.android.tools.r8.kotlin.metadata;
 
 import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.KOTLINC_1_4_20;
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
+import static com.android.tools.r8.ToolHelper.getKotlinReflectJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
@@ -13,7 +15,6 @@
 import com.android.tools.r8.KotlinTestParameters;
 import com.android.tools.r8.R8TestRunResult;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.shaking.ProguardKeepAttributes;
 import com.android.tools.r8.utils.codeinspector.AnnotationSubject;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -53,11 +54,10 @@
         testForR8(parameters.getBackend())
             .addProgramFiles(compiledJars.getForConfiguration(kotlinc, targetVersion))
             .addProgramFiles(getJavaJarFile(FOLDER))
-            .addProgramFiles(ToolHelper.getKotlinReflectJar(kotlinc))
+            .addProgramFiles(getKotlinReflectJar(kotlinc), getKotlinAnnotationJar(kotlinc))
             .addKeepMainRule(mainClassName)
             .addKeepKotlinMetadata()
             .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
-            .addDontWarnJetBrainsAnnotations()
             .allowDiagnosticWarningMessages()
             .setMinApi(parameters.getApiLevel())
             .allowUnusedDontWarnKotlinReflectJvmInternal(kotlinc.is(KOTLINC_1_4_20))
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataVersionNumberBumpTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataVersionNumberBumpTest.java
index a7886b2..4cf9124 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataVersionNumberBumpTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataVersionNumberBumpTest.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.kotlin.metadata;
 
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
 import static com.android.tools.r8.ToolHelper.getKotlinC_1_3_72;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
@@ -60,10 +61,10 @@
     final R8FullTestBuilder testBuilder = testForR8(parameters.getBackend());
     rewriteMetadataVersion(testBuilder::addProgramClassFileData, new int[] {1, 1, 16});
     testBuilder
+        .addProgramFiles(getKotlinAnnotationJar(kotlinc))
         .setMinApi(parameters.getApiLevel())
         .addKeepAllClassesRule()
         .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
-        .addDontWarnJetBrainsAnnotations()
         .compile()
         .inspect(inspector -> inspectMetadataVersion(inspector, "1.4.0"));
   }
@@ -73,10 +74,10 @@
     final R8FullTestBuilder testBuilder = testForR8(parameters.getBackend());
     rewriteMetadataVersion(testBuilder::addProgramClassFileData, new int[] {1, 4, 0});
     testBuilder
+        .addProgramFiles(getKotlinAnnotationJar(kotlinc))
         .setMinApi(parameters.getApiLevel())
         .addKeepAllClassesRule()
         .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
-        .addDontWarnJetBrainsAnnotations()
         .compile()
         .inspect(inspector -> inspectMetadataVersion(inspector, "1.4.0"));
   }
@@ -86,10 +87,10 @@
     final R8FullTestBuilder testBuilder = testForR8(parameters.getBackend());
     rewriteMetadataVersion(testBuilder::addProgramClassFileData, new int[] {1, 4, 2});
     testBuilder
+        .addProgramFiles(getKotlinAnnotationJar(kotlinc))
         .setMinApi(parameters.getApiLevel())
         .addKeepAllClassesRule()
         .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
-        .addDontWarnJetBrainsAnnotations()
         .compile()
         .inspect(inspector -> inspectMetadataVersion(inspector, "1.4.2"));
   }
diff --git a/src/test/java/com/android/tools/r8/kotlin/optimize/switches/KotlinEnumSwitchTest.java b/src/test/java/com/android/tools/r8/kotlin/optimize/switches/KotlinEnumSwitchTest.java
index fe05714..265aa24 100644
--- a/src/test/java/com/android/tools/r8/kotlin/optimize/switches/KotlinEnumSwitchTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/optimize/switches/KotlinEnumSwitchTest.java
@@ -4,7 +4,9 @@
 
 package com.android.tools.r8.kotlin.optimize.switches;
 
+import static com.android.tools.r8.ToolHelper.getMostRecentKotlinAnnotationJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.CoreMatchers.equalTo;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertNotEquals;
 
@@ -28,7 +30,8 @@
 
   @Parameters(name = "{1}, enable switch map removal: {0}")
   public static List<Object[]> data() {
-    return buildParameters(BooleanUtils.values(), getTestParameters().withAllRuntimes().build());
+    return buildParameters(
+        BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
   }
 
   public KotlinEnumSwitchTest(boolean enableSwitchMapRemoval, TestParameters parameters) {
@@ -39,17 +42,20 @@
   @Test
   public void test() throws Exception {
     testForR8(parameters.getBackend())
-        .addProgramFiles(Paths.get(ToolHelper.EXAMPLES_KOTLIN_BUILD_DIR, "enumswitch.jar"))
+        .addProgramFiles(
+            Paths.get(ToolHelper.EXAMPLES_KOTLIN_BUILD_DIR, "enumswitch.jar"),
+            getMostRecentKotlinAnnotationJar())
         .addKeepMainRule("enumswitch.EnumSwitchKt")
         .addOptionsModification(
             options -> {
               options.enableEnumValueOptimization = enableSwitchMapRemoval;
               options.enableEnumSwitchMapRemoval = enableSwitchMapRemoval;
             })
-        .addDontWarnJetBrainsNotNullAnnotation()
-        .setMinApi(parameters.getRuntime())
+        .allowDiagnosticWarningMessages()
+        .setMinApi(parameters.getApiLevel())
         .noMinification()
         .compile()
+        .assertAllWarningMessagesMatch(equalTo("Resource 'META-INF/MANIFEST.MF' already exists."))
         .inspect(
             inspector -> {
               ClassSubject classSubject = inspector.clazz("enumswitch.EnumSwitchKt");
diff --git a/src/test/java/com/android/tools/r8/kotlin/sealed/SealedClassTest.java b/src/test/java/com/android/tools/r8/kotlin/sealed/SealedClassTest.java
index 47f9463..3422030 100644
--- a/src/test/java/com/android/tools/r8/kotlin/sealed/SealedClassTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/sealed/SealedClassTest.java
@@ -4,15 +4,15 @@
 
 package com.android.tools.r8.kotlin.sealed;
 
-import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
 import static com.android.tools.r8.ToolHelper.getFilesInTestFolderRelativeToClass;
-import static org.hamcrest.CoreMatchers.containsString;
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
+import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
+import static org.hamcrest.CoreMatchers.equalTo;
 
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.KotlinTestBase;
 import com.android.tools.r8.KotlinTestParameters;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper;
 import java.io.IOException;
 import java.nio.file.Path;
 import java.util.Collection;
@@ -58,7 +58,7 @@
   public void testRuntime() throws ExecutionException, CompilationFailedException, IOException {
     testForRuntime(parameters)
         .addProgramFiles(compilationResults.getForConfiguration(kotlinc, targetVersion))
-        .addRunClasspathFiles(buildOnDexRuntime(parameters, ToolHelper.getKotlinStdlibJar(kotlinc)))
+        .addRunClasspathFiles(buildOnDexRuntime(parameters, getKotlinStdlibJar(kotlinc)))
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutputLines(EXPECTED);
   }
@@ -67,17 +67,14 @@
   public void testR8() throws ExecutionException, CompilationFailedException, IOException {
     testForR8(parameters.getBackend())
         .addProgramFiles(compilationResults.getForConfiguration(kotlinc, targetVersion))
-        .addProgramFiles(buildOnDexRuntime(parameters, ToolHelper.getKotlinStdlibJar(kotlinc)))
+        .addProgramFiles(buildOnDexRuntime(parameters, getKotlinStdlibJar(kotlinc)))
+        .addProgramFiles(getKotlinAnnotationJar(kotlinc))
         .setMinApi(parameters.getApiLevel())
         .allowAccessModification()
-        .allowDiagnosticWarningMessages(parameters.isCfRuntime())
+        .allowDiagnosticWarningMessages()
         .addKeepMainRule(MAIN)
-        .addDontWarnJetBrainsNotNullAnnotation()
-        .compileWithExpectedDiagnostics(
-            diagnostics ->
-                diagnostics.assertAllWarningsMatch(
-                    diagnosticMessage(
-                        containsString("Resource 'META-INF/MANIFEST.MF' already exists."))))
+        .compile()
+        .assertAllWarningMessagesMatch(equalTo("Resource 'META-INF/MANIFEST.MF' already exists."))
         .run(parameters.getRuntime(), MAIN)
         .assertSuccessWithOutputLines(EXPECTED);
   }
diff --git a/src/test/java/com/android/tools/r8/maindexlist/b72312389/B72312389.java b/src/test/java/com/android/tools/r8/maindexlist/b72312389/B72312389.java
index 1978867..05e769d 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/b72312389/B72312389.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/b72312389/B72312389.java
@@ -6,6 +6,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeFalse;
 
 import com.android.tools.r8.BaseCommand;
 import com.android.tools.r8.CompatProguardCommandBuilder;
@@ -18,7 +19,6 @@
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.ToolHelper.DexVm;
-import com.android.tools.r8.VmTestRunner;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.Box;
@@ -28,9 +28,7 @@
 import java.util.ArrayList;
 import java.util.List;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
-@RunWith(VmTestRunner.class)
 public class B72312389 extends TestBase {
   // TODO(120884788): Remove this when default is true.
   private static boolean lookupLibraryBeforeProgram = false;
@@ -53,6 +51,7 @@
 
   @Test
   public void testGenerateMainDexList() throws Exception {
+    assumeFalse(ToolHelper.isWindows());
     CollectingDiagnosticHandler diagnostics = new CollectingDiagnosticHandler();
     GenerateMainDexListCommand.Builder builder = GenerateMainDexListCommand.builder(diagnostics);
     buildInstrumentationTestCaseApplication(builder);
@@ -70,6 +69,7 @@
 
   @Test
   public void testR8ForceProguardCompatibility() throws Exception {
+    assumeFalse(ToolHelper.isWindows());
     Box<String> mainDexList = new Box<>();
     // Build a app with a class extending InstrumentationTestCase and including both the junit
     // and the Android library.
@@ -98,6 +98,7 @@
 
   @Test
   public void testR8() throws Exception {
+    assumeFalse(ToolHelper.isWindows());
     testForR8(Backend.DEX)
         .apply(b -> buildInstrumentationTestCaseApplication(b.getBuilder()))
         .setMinApi(AndroidApiLevel.B)
diff --git a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromCatchHandlerTest.java b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromCatchHandlerTest.java
index e9bc43b..f45220d 100644
--- a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromCatchHandlerTest.java
+++ b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromCatchHandlerTest.java
@@ -7,15 +7,18 @@
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.TestDiagnosticMessages;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.references.MethodReference;
-import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.internal.MissingDefinitionMethodContextImpl;
 import com.android.tools.r8.utils.MethodReferenceUtils;
 import org.junit.Test;
 
 public class MissingClassReferencedFromCatchHandlerTest extends MissingClassesTestBase {
 
-  private static final MethodReference referencedFrom =
-      MethodReferenceUtils.mainMethod(Reference.classFromClass(Main.class));
+  private static final MissingDefinitionContext referencedFrom =
+      MissingDefinitionMethodContextImpl.builder()
+          .setMethodContext(MethodReferenceUtils.mainMethod(Main.class))
+          .setOrigin(getOrigin(Main.class))
+          .build();
 
   public MissingClassReferencedFromCatchHandlerTest(TestParameters parameters) {
     super(parameters);
diff --git a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromCheckCastTest.java b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromCheckCastTest.java
index b10a231..37df585 100644
--- a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromCheckCastTest.java
+++ b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromCheckCastTest.java
@@ -7,15 +7,18 @@
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.TestDiagnosticMessages;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.references.MethodReference;
-import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.internal.MissingDefinitionMethodContextImpl;
 import com.android.tools.r8.utils.MethodReferenceUtils;
 import org.junit.Test;
 
 public class MissingClassReferencedFromCheckCastTest extends MissingClassesTestBase {
 
-  private static final MethodReference referencedFrom =
-      MethodReferenceUtils.mainMethod(Reference.classFromClass(Main.class));
+  private static final MissingDefinitionContext referencedFrom =
+      MissingDefinitionMethodContextImpl.builder()
+          .setMethodContext(MethodReferenceUtils.mainMethod(Main.class))
+          .setOrigin(getOrigin(Main.class))
+          .build();
 
   public MissingClassReferencedFromCheckCastTest(TestParameters parameters) {
     super(parameters);
diff --git a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromClassAnnotationTest.java b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromClassAnnotationTest.java
index 0af31a3..d114dc0 100644
--- a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromClassAnnotationTest.java
+++ b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromClassAnnotationTest.java
@@ -7,6 +7,8 @@
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.TestDiagnosticMessages;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.internal.MissingDefinitionClassContextImpl;
 import com.android.tools.r8.references.ClassReference;
 import com.android.tools.r8.references.Reference;
 import org.junit.Test;
@@ -15,7 +17,11 @@
 //  we retain missing annotations even if there is no -keepattributes *Annotations*.
 public class MissingClassReferencedFromClassAnnotationTest extends MissingClassesTestBase {
 
-  private static final ClassReference referencedFrom = Reference.classFromClass(Main.class);
+  private static final MissingDefinitionContext referencedFrom =
+      MissingDefinitionClassContextImpl.builder()
+          .setClassContext(Reference.classFromClass(Main.class))
+          .setOrigin(getOrigin(Main.class))
+          .build();
 
   public MissingClassReferencedFromClassAnnotationTest(TestParameters parameters) {
     super(parameters);
diff --git a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromClassAnnotationWithDataTest.java b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromClassAnnotationWithDataTest.java
index 0918d76..10663fa 100644
--- a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromClassAnnotationWithDataTest.java
+++ b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromClassAnnotationWithDataTest.java
@@ -9,7 +9,8 @@
 import com.android.tools.r8.TestDiagnosticMessages;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.ThrowableConsumer;
-import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.internal.MissingDefinitionClassContextImpl;
 import com.android.tools.r8.references.Reference;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -17,7 +18,11 @@
 
 public class MissingClassReferencedFromClassAnnotationWithDataTest extends MissingClassesTestBase {
 
-  private static final ClassReference referencedFrom = Reference.classFromClass(Main.class);
+  private static final MissingDefinitionContext referencedFrom =
+      MissingDefinitionClassContextImpl.builder()
+          .setClassContext(Reference.classFromClass(Main.class))
+          .setOrigin(getOrigin(Main.class))
+          .build();
 
   public MissingClassReferencedFromClassAnnotationWithDataTest(TestParameters parameters) {
     super(parameters);
diff --git a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromConstClassTest.java b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromConstClassTest.java
index cb6287c..94550b8 100644
--- a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromConstClassTest.java
+++ b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromConstClassTest.java
@@ -7,15 +7,18 @@
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.TestDiagnosticMessages;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.references.MethodReference;
-import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.internal.MissingDefinitionMethodContextImpl;
 import com.android.tools.r8.utils.MethodReferenceUtils;
 import org.junit.Test;
 
 public class MissingClassReferencedFromConstClassTest extends MissingClassesTestBase {
 
-  private static final MethodReference referencedFrom =
-      MethodReferenceUtils.mainMethod(Reference.classFromClass(Main.class));
+  private static final MissingDefinitionContext referencedFrom =
+      MissingDefinitionMethodContextImpl.builder()
+          .setMethodContext(MethodReferenceUtils.mainMethod(Main.class))
+          .setOrigin(getOrigin(Main.class))
+          .build();
 
   public MissingClassReferencedFromConstClassTest(TestParameters parameters) {
     super(parameters);
diff --git a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromEnclosingMethodAttributeTest.java b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromEnclosingMethodAttributeTest.java
index 74f00d4..40408ee 100644
--- a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromEnclosingMethodAttributeTest.java
+++ b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromEnclosingMethodAttributeTest.java
@@ -11,6 +11,8 @@
 import com.android.tools.r8.R8TestBuilder;
 import com.android.tools.r8.TestDiagnosticMessages;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.internal.MissingDefinitionClassContextImpl;
 import com.android.tools.r8.references.ClassReference;
 import com.android.tools.r8.references.Reference;
 import com.android.tools.r8.utils.BooleanUtils;
@@ -20,7 +22,11 @@
 
 public class MissingClassReferencedFromEnclosingMethodAttributeTest extends MissingClassesTestBase {
 
-  private static final ClassReference referencedFrom = Reference.classFromClass(getMainClass());
+  private static final MissingDefinitionContext referencedFrom =
+      MissingDefinitionClassContextImpl.builder()
+          .setClassContext(Reference.classFromClass(getMainClass()))
+          .setOrigin(getOrigin(getMainClass()))
+          .build();
 
   @Parameters(name = "{1}, report: {0}")
   public static List<Object[]> data() {
diff --git a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromFieldAnnotationTest.java b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromFieldAnnotationTest.java
index 7788831..7638885 100644
--- a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromFieldAnnotationTest.java
+++ b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromFieldAnnotationTest.java
@@ -7,17 +7,22 @@
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.TestDiagnosticMessages;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.internal.MissingDefinitionFieldContextImpl;
 import com.android.tools.r8.references.ClassReference;
-import com.android.tools.r8.references.FieldReference;
 import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.utils.FieldReferenceUtils;
 import org.junit.Test;
 
 // TODO(b/179456539): This test should fail without -keepattributes RuntimeVisibleAnnotations, but
 //  we retain missing annotations even if there is no -keepattributes *Annotations*.
 public class MissingClassReferencedFromFieldAnnotationTest extends MissingClassesTestBase {
 
-  private static final FieldReference referencedFrom =
-      Reference.field(Reference.classFromClass(Main.class), "FIELD", Reference.INT);
+  private static final MissingDefinitionContext referencedFrom =
+      MissingDefinitionFieldContextImpl.builder()
+          .setFieldContext(FieldReferenceUtils.fieldFromField(Main.class, "FIELD"))
+          .setOrigin(getOrigin(Main.class))
+          .build();
 
   public MissingClassReferencedFromFieldAnnotationTest(TestParameters parameters) {
     super(parameters);
diff --git a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromImplementsClauseTest.java b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromImplementsClauseTest.java
index 490efdc..51da805 100644
--- a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromImplementsClauseTest.java
+++ b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromImplementsClauseTest.java
@@ -8,13 +8,19 @@
 import com.android.tools.r8.TestCompilerBuilder;
 import com.android.tools.r8.TestDiagnosticMessages;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.internal.MissingDefinitionClassContextImpl;
 import com.android.tools.r8.references.ClassReference;
 import com.android.tools.r8.references.Reference;
 import org.junit.Test;
 
 public class MissingClassReferencedFromImplementsClauseTest extends MissingClassesTestBase {
 
-  private static final ClassReference referencedFrom = Reference.classFromClass(Main.class);
+  private static final MissingDefinitionContext referencedFrom =
+      MissingDefinitionClassContextImpl.builder()
+          .setClassContext(Reference.classFromClass(Main.class))
+          .setOrigin(getOrigin(Main.class))
+          .build();
 
   public MissingClassReferencedFromImplementsClauseTest(TestParameters parameters) {
     super(parameters);
diff --git a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromInnerClassAttributeTest.java b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromInnerClassAttributeTest.java
index aa64ab8..f421eb1 100644
--- a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromInnerClassAttributeTest.java
+++ b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromInnerClassAttributeTest.java
@@ -11,6 +11,8 @@
 import com.android.tools.r8.R8TestBuilder;
 import com.android.tools.r8.TestDiagnosticMessages;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.internal.MissingDefinitionClassContextImpl;
 import com.android.tools.r8.references.ClassReference;
 import com.android.tools.r8.references.Reference;
 import com.android.tools.r8.utils.BooleanUtils;
@@ -20,7 +22,11 @@
 
 public class MissingClassReferencedFromInnerClassAttributeTest extends MissingClassesTestBase {
 
-  private static final ClassReference referencedFrom = Reference.classFromClass(Main.class);
+  private static final MissingDefinitionContext referencedFrom =
+      MissingDefinitionClassContextImpl.builder()
+          .setClassContext(Reference.classFromClass(Main.class))
+          .setOrigin(getOrigin(Main.class))
+          .build();
 
   @Parameters(name = "{1}, report: {0}")
   public static List<Object[]> data() {
diff --git a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromInstanceGetToExistingFieldTest.java b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromInstanceGetToExistingFieldTest.java
index 6c7f620..1ce5f9f 100644
--- a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromInstanceGetToExistingFieldTest.java
+++ b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromInstanceGetToExistingFieldTest.java
@@ -7,8 +7,9 @@
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.TestDiagnosticMessages;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.references.FieldReference;
-import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.internal.MissingDefinitionFieldContextImpl;
+import com.android.tools.r8.utils.FieldReferenceUtils;
 import org.junit.Test;
 
 /**
@@ -18,11 +19,11 @@
 public class MissingClassReferencedFromInstanceGetToExistingFieldTest
     extends MissingClassesTestBase {
 
-  private static final FieldReference referencedFrom =
-      Reference.field(
-          Reference.classFromClass(Main.class),
-          "field",
-          Reference.classFromClass(MissingClass.class));
+  private static final MissingDefinitionContext referencedFrom =
+      MissingDefinitionFieldContextImpl.builder()
+          .setFieldContext(FieldReferenceUtils.fieldFromField(Main.class, "field"))
+          .setOrigin(getOrigin(Main.class))
+          .build();
 
   public MissingClassReferencedFromInstanceGetToExistingFieldTest(TestParameters parameters) {
     super(parameters);
diff --git a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromInstanceGetToMissingFieldTest.java b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromInstanceGetToMissingFieldTest.java
index 851d65d..f367fed 100644
--- a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromInstanceGetToMissingFieldTest.java
+++ b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromInstanceGetToMissingFieldTest.java
@@ -7,8 +7,8 @@
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.TestDiagnosticMessages;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.references.MethodReference;
-import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.internal.MissingDefinitionMethodContextImpl;
 import com.android.tools.r8.utils.MethodReferenceUtils;
 import org.junit.Test;
 
@@ -19,8 +19,11 @@
 public class MissingClassReferencedFromInstanceGetToMissingFieldTest
     extends MissingClassesTestBase {
 
-  private static final MethodReference referencedFrom =
-      MethodReferenceUtils.mainMethod(Reference.classFromClass(Main.class));
+  private static final MissingDefinitionContext referencedFrom =
+      MissingDefinitionMethodContextImpl.builder()
+          .setMethodContext(MethodReferenceUtils.mainMethod(Main.class))
+          .setOrigin(getOrigin(Main.class))
+          .build();
 
   public MissingClassReferencedFromInstanceGetToMissingFieldTest(TestParameters parameters) {
     super(parameters);
diff --git a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromInstanceOfTest.java b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromInstanceOfTest.java
index 2d05aac..7ec1e09 100644
--- a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromInstanceOfTest.java
+++ b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromInstanceOfTest.java
@@ -7,15 +7,18 @@
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.TestDiagnosticMessages;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.references.MethodReference;
-import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.internal.MissingDefinitionMethodContextImpl;
 import com.android.tools.r8.utils.MethodReferenceUtils;
 import org.junit.Test;
 
 public class MissingClassReferencedFromInstanceOfTest extends MissingClassesTestBase {
 
-  private static final MethodReference referencedFrom =
-      MethodReferenceUtils.mainMethod(Reference.classFromClass(Main.class));
+  private static final MissingDefinitionContext referencedFrom =
+      MissingDefinitionMethodContextImpl.builder()
+          .setMethodContext(MethodReferenceUtils.mainMethod(Main.class))
+          .setOrigin(getOrigin(Main.class))
+          .build();
 
   public MissingClassReferencedFromInstanceOfTest(TestParameters parameters) {
     super(parameters);
diff --git a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromInstancePutToExistingFieldTest.java b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromInstancePutToExistingFieldTest.java
index b69625e..1f0e5a7 100644
--- a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromInstancePutToExistingFieldTest.java
+++ b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromInstancePutToExistingFieldTest.java
@@ -7,8 +7,9 @@
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.TestDiagnosticMessages;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.references.FieldReference;
-import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.internal.MissingDefinitionFieldContextImpl;
+import com.android.tools.r8.utils.FieldReferenceUtils;
 import org.junit.Test;
 
 /**
@@ -18,11 +19,11 @@
 public class MissingClassReferencedFromInstancePutToExistingFieldTest
     extends MissingClassesTestBase {
 
-  private static final FieldReference referencedFrom =
-      Reference.field(
-          Reference.classFromClass(Main.class),
-          "field",
-          Reference.classFromClass(MissingClass.class));
+  private static final MissingDefinitionContext referencedFrom =
+      MissingDefinitionFieldContextImpl.builder()
+          .setFieldContext(FieldReferenceUtils.fieldFromField(Main.class, "field"))
+          .setOrigin(getOrigin(Main.class))
+          .build();
 
   public MissingClassReferencedFromInstancePutToExistingFieldTest(TestParameters parameters) {
     super(parameters);
diff --git a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromInstancePutToMissingFieldTest.java b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromInstancePutToMissingFieldTest.java
index ec615f1..b4dd5a1 100644
--- a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromInstancePutToMissingFieldTest.java
+++ b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromInstancePutToMissingFieldTest.java
@@ -7,8 +7,8 @@
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.TestDiagnosticMessages;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.references.MethodReference;
-import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.internal.MissingDefinitionMethodContextImpl;
 import com.android.tools.r8.utils.MethodReferenceUtils;
 import org.junit.Test;
 
@@ -19,8 +19,11 @@
 public class MissingClassReferencedFromInstancePutToMissingFieldTest
     extends MissingClassesTestBase {
 
-  private static final MethodReference referencedFrom =
-      MethodReferenceUtils.mainMethod(Reference.classFromClass(Main.class));
+  private static final MissingDefinitionContext referencedFrom =
+      MissingDefinitionMethodContextImpl.builder()
+          .setMethodContext(MethodReferenceUtils.mainMethod(Main.class))
+          .setOrigin(getOrigin(Main.class))
+          .build();
 
   public MissingClassReferencedFromInstancePutToMissingFieldTest(TestParameters parameters) {
     super(parameters);
diff --git a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromInvokeVirtualToAbsentMethodParameterTest.java b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromInvokeVirtualToAbsentMethodParameterTest.java
index 21e18bf..31e1942 100644
--- a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromInvokeVirtualToAbsentMethodParameterTest.java
+++ b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromInvokeVirtualToAbsentMethodParameterTest.java
@@ -9,9 +9,8 @@
 import com.android.tools.r8.TestDiagnosticMessages;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.ThrowableConsumer;
-import com.android.tools.r8.missingclasses.MissingClassReferencedFromNestMemberAttributeTest.Main;
-import com.android.tools.r8.references.MethodReference;
-import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.internal.MissingDefinitionMethodContextImpl;
 import com.android.tools.r8.utils.MethodReferenceUtils;
 import com.google.common.collect.ImmutableList;
 import java.io.IOException;
@@ -25,8 +24,11 @@
 public class MissingClassReferencedFromInvokeVirtualToAbsentMethodParameterTest
     extends MissingClassesTestBase {
 
-  private static final MethodReference referencedFrom =
-      MethodReferenceUtils.mainMethod(Reference.classFromClass(Main.class));
+  private static final MissingDefinitionContext referencedFrom =
+      MissingDefinitionMethodContextImpl.builder()
+          .setMethodContext(MethodReferenceUtils.mainMethod(Main.class))
+          .setOrigin(getOrigin(Main.class))
+          .build();
 
   public MissingClassReferencedFromInvokeVirtualToAbsentMethodParameterTest(
       TestParameters parameters) {
diff --git a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromInvokeVirtualToAbsentMethodReturnTest.java b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromInvokeVirtualToAbsentMethodReturnTest.java
index d40d191..4c62ad2 100644
--- a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromInvokeVirtualToAbsentMethodReturnTest.java
+++ b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromInvokeVirtualToAbsentMethodReturnTest.java
@@ -9,8 +9,8 @@
 import com.android.tools.r8.TestDiagnosticMessages;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.ThrowableConsumer;
-import com.android.tools.r8.references.MethodReference;
-import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.internal.MissingDefinitionMethodContextImpl;
 import com.android.tools.r8.utils.MethodReferenceUtils;
 import com.google.common.collect.ImmutableList;
 import java.io.IOException;
@@ -24,8 +24,11 @@
 public class MissingClassReferencedFromInvokeVirtualToAbsentMethodReturnTest
     extends MissingClassesTestBase {
 
-  private static final MethodReference referencedFrom =
-      MethodReferenceUtils.mainMethod(Reference.classFromClass(Main.class));
+  private static final MissingDefinitionContext referencedFrom =
+      MissingDefinitionMethodContextImpl.builder()
+          .setMethodContext(MethodReferenceUtils.mainMethod(Main.class))
+          .setOrigin(getOrigin(Main.class))
+          .build();
 
   public MissingClassReferencedFromInvokeVirtualToAbsentMethodReturnTest(
       TestParameters parameters) {
diff --git a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromInvokeVirtualToPresentMethodParameterTest.java b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromInvokeVirtualToPresentMethodParameterTest.java
index f5b82ad..28c1a79 100644
--- a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromInvokeVirtualToPresentMethodParameterTest.java
+++ b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromInvokeVirtualToPresentMethodParameterTest.java
@@ -7,9 +7,9 @@
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.TestDiagnosticMessages;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.references.MethodReference;
-import com.android.tools.r8.references.Reference;
-import com.google.common.collect.ImmutableList;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.internal.MissingDefinitionMethodContextImpl;
+import com.android.tools.r8.utils.MethodReferenceUtils;
 import org.junit.Test;
 
 /**
@@ -19,12 +19,12 @@
 public class MissingClassReferencedFromInvokeVirtualToPresentMethodParameterTest
     extends MissingClassesTestBase {
 
-  private static final MethodReference referencedFrom =
-      Reference.method(
-          Reference.classFromClass(Main.class),
-          "get",
-          ImmutableList.of(Reference.classFromClass(MissingClass.class)),
-          null);
+  private static final MissingDefinitionContext referencedFrom =
+      MissingDefinitionMethodContextImpl.builder()
+          .setMethodContext(
+              MethodReferenceUtils.methodFromMethod(Main.class, "get", MissingClass.class))
+          .setOrigin(getOrigin(Main.class))
+          .build();
 
   public MissingClassReferencedFromInvokeVirtualToPresentMethodParameterTest(
       TestParameters parameters) {
diff --git a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromInvokeVirtualToPresentMethodReturnTest.java b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromInvokeVirtualToPresentMethodReturnTest.java
index b675c8a..396117f 100644
--- a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromInvokeVirtualToPresentMethodReturnTest.java
+++ b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromInvokeVirtualToPresentMethodReturnTest.java
@@ -7,9 +7,9 @@
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.TestDiagnosticMessages;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.references.MethodReference;
-import com.android.tools.r8.references.Reference;
-import java.util.Collections;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.internal.MissingDefinitionMethodContextImpl;
+import com.android.tools.r8.utils.MethodReferenceUtils;
 import org.junit.Test;
 
 /**
@@ -19,12 +19,11 @@
 public class MissingClassReferencedFromInvokeVirtualToPresentMethodReturnTest
     extends MissingClassesTestBase {
 
-  private static final MethodReference referencedFrom =
-      Reference.method(
-          Reference.classFromClass(Main.class),
-          "get",
-          Collections.emptyList(),
-          Reference.classFromClass(MissingClass.class));
+  private static final MissingDefinitionContext referencedFrom =
+      MissingDefinitionMethodContextImpl.builder()
+          .setMethodContext(MethodReferenceUtils.methodFromMethod(Main.class, "get"))
+          .setOrigin(getOrigin(Main.class))
+          .build();
 
   public MissingClassReferencedFromInvokeVirtualToPresentMethodReturnTest(
       TestParameters parameters) {
diff --git a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromKeptFieldTest.java b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromKeptFieldTest.java
index 19dfdea..c212d86 100644
--- a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromKeptFieldTest.java
+++ b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromKeptFieldTest.java
@@ -8,18 +8,19 @@
 import com.android.tools.r8.R8FullTestBuilder;
 import com.android.tools.r8.TestDiagnosticMessages;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.references.FieldReference;
-import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.internal.MissingDefinitionFieldContextImpl;
+import com.android.tools.r8.utils.FieldReferenceUtils;
 import org.junit.Test;
 
 /** If a field definition refers to a missing class, then the field definition is to be blamed. */
 public class MissingClassReferencedFromKeptFieldTest extends MissingClassesTestBase {
 
-  private static final FieldReference referencedFrom =
-      Reference.field(
-          Reference.classFromClass(Main.class),
-          "FIELD",
-          Reference.classFromClass(MissingClass.class));
+  private static final MissingDefinitionContext referencedFrom =
+      MissingDefinitionFieldContextImpl.builder()
+          .setFieldContext(FieldReferenceUtils.fieldFromField(Main.class, "FIELD"))
+          .setOrigin(getOrigin(Main.class))
+          .build();
 
   public MissingClassReferencedFromKeptFieldTest(TestParameters parameters) {
     super(parameters);
diff --git a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromKeptMethodParameterTest.java b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromKeptMethodParameterTest.java
index a86e57a..fc2d8d3 100644
--- a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromKeptMethodParameterTest.java
+++ b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromKeptMethodParameterTest.java
@@ -8,20 +8,20 @@
 import com.android.tools.r8.R8FullTestBuilder;
 import com.android.tools.r8.TestDiagnosticMessages;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.references.MethodReference;
-import com.android.tools.r8.references.Reference;
-import com.google.common.collect.ImmutableList;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.internal.MissingDefinitionMethodContextImpl;
+import com.android.tools.r8.utils.MethodReferenceUtils;
 import org.junit.Test;
 
 /** If a method definition refers to a missing class, then the method definition is to be blamed. */
 public class MissingClassReferencedFromKeptMethodParameterTest extends MissingClassesTestBase {
 
-  private static final MethodReference referencedFrom =
-      Reference.method(
-          Reference.classFromClass(Main.class),
-          "get",
-          ImmutableList.of(Reference.classFromClass(MissingClass.class)),
-          null);
+  private static final MissingDefinitionContext referencedFrom =
+      MissingDefinitionMethodContextImpl.builder()
+          .setMethodContext(
+              MethodReferenceUtils.methodFromMethod(Main.class, "get", MissingClass.class))
+          .setOrigin(getOrigin(Main.class))
+          .build();
 
   public MissingClassReferencedFromKeptMethodParameterTest(TestParameters parameters) {
     super(parameters);
diff --git a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromKeptMethodReturnTest.java b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromKeptMethodReturnTest.java
index f211d14..6dc3edb 100644
--- a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromKeptMethodReturnTest.java
+++ b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromKeptMethodReturnTest.java
@@ -8,20 +8,19 @@
 import com.android.tools.r8.R8FullTestBuilder;
 import com.android.tools.r8.TestDiagnosticMessages;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.references.MethodReference;
-import com.android.tools.r8.references.Reference;
-import java.util.Collections;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.internal.MissingDefinitionMethodContextImpl;
+import com.android.tools.r8.utils.MethodReferenceUtils;
 import org.junit.Test;
 
 /** If a method definition refers to a missing class, then the method definition is to be blamed. */
 public class MissingClassReferencedFromKeptMethodReturnTest extends MissingClassesTestBase {
 
-  private static final MethodReference referencedFrom =
-      Reference.method(
-          Reference.classFromClass(Main.class),
-          "get",
-          Collections.emptyList(),
-          Reference.classFromClass(MissingClass.class));
+  private static final MissingDefinitionContext referencedFrom =
+      MissingDefinitionMethodContextImpl.builder()
+          .setMethodContext(MethodReferenceUtils.methodFromMethod(Main.class, "get"))
+          .setOrigin(getOrigin(Main.class))
+          .build();
 
   public MissingClassReferencedFromKeptMethodReturnTest(TestParameters parameters) {
     super(parameters);
diff --git a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromLibraryInstanceFieldTest.java b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromLibraryInstanceFieldTest.java
new file mode 100644
index 0000000..860bce2
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromLibraryInstanceFieldTest.java
@@ -0,0 +1,89 @@
+// 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.missingclasses;
+
+import static com.android.tools.r8.ToolHelper.getMostRecentAndroidJar;
+
+import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.R8FullTestBuilder;
+import com.android.tools.r8.TestDiagnosticMessages;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ThrowableConsumer;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.internal.MissingDefinitionFieldContextImpl;
+import com.android.tools.r8.utils.FieldReferenceUtils;
+import org.junit.Test;
+
+public class MissingClassReferencedFromLibraryInstanceFieldTest extends MissingClassesTestBase {
+
+  private static final MissingDefinitionContext referencedFrom =
+      MissingDefinitionFieldContextImpl.builder()
+          .setFieldContext(FieldReferenceUtils.fieldFromField(Library.class, "field"))
+          .setOrigin(getOrigin(Library.class))
+          .build();
+
+  public MissingClassReferencedFromLibraryInstanceFieldTest(TestParameters parameters) {
+    super(parameters);
+  }
+
+  @Test(expected = CompilationFailedException.class)
+  public void testNoRules() throws Exception {
+    compileWithExpectedDiagnostics(
+        Main.class,
+        diagnostics -> inspectDiagnosticsWithNoRules(diagnostics, referencedFrom),
+        addLibrary());
+  }
+
+  /**
+   * Main is the closest program context to the missing class reference, but it is not the context
+   * of the missing class reference (Library is). Therefore, compilation still fails in this case.
+   */
+  @Test(expected = CompilationFailedException.class)
+  public void testDontWarnMainClass() throws Exception {
+    compileWithExpectedDiagnostics(
+        Main.class,
+        diagnostics -> inspectDiagnosticsWithNoRules(diagnostics, referencedFrom),
+        addLibrary().andThen(addDontWarn(Main.class)));
+  }
+
+  @Test
+  public void testDontWarnLibraryClass() throws Exception {
+    compileWithExpectedDiagnostics(
+        Main.class,
+        TestDiagnosticMessages::assertNoMessages,
+        addLibrary().andThen(addDontWarn(Library.class)));
+  }
+
+  @Test
+  public void testDontWarnMissingClass() throws Exception {
+    compileWithExpectedDiagnostics(
+        Main.class,
+        TestDiagnosticMessages::assertNoMessages,
+        addLibrary().andThen(addDontWarn(MissingClass.class)));
+  }
+
+  @Test
+  public void testIgnoreWarnings() throws Exception {
+    compileWithExpectedDiagnostics(
+        Main.class,
+        diagnostics -> inspectDiagnosticsWithIgnoreWarnings(diagnostics, referencedFrom),
+        addLibrary().andThen(addIgnoreWarnings()));
+  }
+
+  private ThrowableConsumer<R8FullTestBuilder> addLibrary() {
+    return builder ->
+        builder.addLibraryClasses(Library.class).addLibraryFiles(getMostRecentAndroidJar());
+  }
+
+  static class Main extends Library {
+
+    public static void main(String[] args) {}
+  }
+
+  public static class Library {
+
+    public MissingClass field;
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromLibraryStaticFieldTest.java b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromLibraryStaticFieldTest.java
new file mode 100644
index 0000000..c5c7950
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromLibraryStaticFieldTest.java
@@ -0,0 +1,89 @@
+// 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.missingclasses;
+
+import static com.android.tools.r8.ToolHelper.getMostRecentAndroidJar;
+
+import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.R8FullTestBuilder;
+import com.android.tools.r8.TestDiagnosticMessages;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ThrowableConsumer;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.internal.MissingDefinitionFieldContextImpl;
+import com.android.tools.r8.utils.FieldReferenceUtils;
+import org.junit.Test;
+
+public class MissingClassReferencedFromLibraryStaticFieldTest extends MissingClassesTestBase {
+
+  private static final MissingDefinitionContext referencedFrom =
+      MissingDefinitionFieldContextImpl.builder()
+          .setFieldContext(FieldReferenceUtils.fieldFromField(Library.class, "field"))
+          .setOrigin(getOrigin(Library.class))
+          .build();
+
+  public MissingClassReferencedFromLibraryStaticFieldTest(TestParameters parameters) {
+    super(parameters);
+  }
+
+  @Test(expected = CompilationFailedException.class)
+  public void testNoRules() throws Exception {
+    compileWithExpectedDiagnostics(
+        Main.class,
+        diagnostics -> inspectDiagnosticsWithNoRules(diagnostics, referencedFrom),
+        addLibrary());
+  }
+
+  /**
+   * Main is the closest program context to the missing class reference, but it is not the context
+   * of the missing class reference (Library is). Therefore, compilation still fails in this case.
+   */
+  @Test(expected = CompilationFailedException.class)
+  public void testDontWarnMainClass() throws Exception {
+    compileWithExpectedDiagnostics(
+        Main.class,
+        diagnostics -> inspectDiagnosticsWithNoRules(diagnostics, referencedFrom),
+        addLibrary().andThen(addDontWarn(Main.class)));
+  }
+
+  @Test
+  public void testDontWarnLibraryClass() throws Exception {
+    compileWithExpectedDiagnostics(
+        Main.class,
+        TestDiagnosticMessages::assertNoMessages,
+        addLibrary().andThen(addDontWarn(Library.class)));
+  }
+
+  @Test
+  public void testDontWarnMissingClass() throws Exception {
+    compileWithExpectedDiagnostics(
+        Main.class,
+        TestDiagnosticMessages::assertNoMessages,
+        addLibrary().andThen(addDontWarn(MissingClass.class)));
+  }
+
+  @Test
+  public void testIgnoreWarnings() throws Exception {
+    compileWithExpectedDiagnostics(
+        Main.class,
+        diagnostics -> inspectDiagnosticsWithIgnoreWarnings(diagnostics, referencedFrom),
+        addLibrary().andThen(addIgnoreWarnings()));
+  }
+
+  private ThrowableConsumer<R8FullTestBuilder> addLibrary() {
+    return builder ->
+        builder.addLibraryClasses(Library.class).addLibraryFiles(getMostRecentAndroidJar());
+  }
+
+  static class Main extends Library {
+
+    public static void main(String[] args) {}
+  }
+
+  public static class Library {
+
+    public static MissingClass field;
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromLibraryVirtualMethodParameterTest.java b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromLibraryVirtualMethodParameterTest.java
new file mode 100644
index 0000000..4a56add
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromLibraryVirtualMethodParameterTest.java
@@ -0,0 +1,91 @@
+// 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.missingclasses;
+
+import static com.android.tools.r8.ToolHelper.getMostRecentAndroidJar;
+
+import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.R8FullTestBuilder;
+import com.android.tools.r8.TestDiagnosticMessages;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ThrowableConsumer;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.internal.MissingDefinitionMethodContextImpl;
+import com.android.tools.r8.utils.MethodReferenceUtils;
+import org.junit.Test;
+
+public class MissingClassReferencedFromLibraryVirtualMethodParameterTest
+    extends MissingClassesTestBase {
+
+  private static final MissingDefinitionContext referencedFrom =
+      MissingDefinitionMethodContextImpl.builder()
+          .setMethodContext(
+              MethodReferenceUtils.methodFromMethod(Library.class, "method", MissingClass.class))
+          .setOrigin(getOrigin(Library.class))
+          .build();
+
+  public MissingClassReferencedFromLibraryVirtualMethodParameterTest(TestParameters parameters) {
+    super(parameters);
+  }
+
+  @Test(expected = CompilationFailedException.class)
+  public void testNoRules() throws Exception {
+    compileWithExpectedDiagnostics(
+        Main.class,
+        diagnostics -> inspectDiagnosticsWithNoRules(diagnostics, referencedFrom),
+        addLibrary());
+  }
+
+  /**
+   * Main is the closest program context to the missing class reference, but it is not the context
+   * of the missing class reference (Library is). Therefore, compilation still fails in this case.
+   */
+  @Test(expected = CompilationFailedException.class)
+  public void testDontWarnMainClass() throws Exception {
+    compileWithExpectedDiagnostics(
+        Main.class,
+        diagnostics -> inspectDiagnosticsWithNoRules(diagnostics, referencedFrom),
+        addLibrary().andThen(addDontWarn(Main.class)));
+  }
+
+  @Test
+  public void testDontWarnLibraryClass() throws Exception {
+    compileWithExpectedDiagnostics(
+        Main.class,
+        TestDiagnosticMessages::assertNoMessages,
+        addLibrary().andThen(addDontWarn(Library.class)));
+  }
+
+  @Test
+  public void testDontWarnMissingClass() throws Exception {
+    compileWithExpectedDiagnostics(
+        Main.class,
+        TestDiagnosticMessages::assertNoMessages,
+        addLibrary().andThen(addDontWarn(MissingClass.class)));
+  }
+
+  @Test
+  public void testIgnoreWarnings() throws Exception {
+    compileWithExpectedDiagnostics(
+        Main.class,
+        diagnostics -> inspectDiagnosticsWithIgnoreWarnings(diagnostics, referencedFrom),
+        addLibrary().andThen(addIgnoreWarnings()));
+  }
+
+  private ThrowableConsumer<R8FullTestBuilder> addLibrary() {
+    return builder ->
+        builder.addLibraryClasses(Library.class).addLibraryFiles(getMostRecentAndroidJar());
+  }
+
+  static class Main extends Library {
+
+    public static void main(String[] args) {}
+  }
+
+  public static class Library {
+
+    public void method(MissingClass mc) {}
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromLibraryVirtualMethodReturnTest.java b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromLibraryVirtualMethodReturnTest.java
new file mode 100644
index 0000000..5c627ef
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromLibraryVirtualMethodReturnTest.java
@@ -0,0 +1,92 @@
+// 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.missingclasses;
+
+import static com.android.tools.r8.ToolHelper.getMostRecentAndroidJar;
+
+import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.R8FullTestBuilder;
+import com.android.tools.r8.TestDiagnosticMessages;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ThrowableConsumer;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.internal.MissingDefinitionMethodContextImpl;
+import com.android.tools.r8.utils.MethodReferenceUtils;
+import org.junit.Test;
+
+public class MissingClassReferencedFromLibraryVirtualMethodReturnTest
+    extends MissingClassesTestBase {
+
+  private static final MissingDefinitionContext referencedFrom =
+      MissingDefinitionMethodContextImpl.builder()
+          .setMethodContext(MethodReferenceUtils.methodFromMethod(Library.class, "method"))
+          .setOrigin(getOrigin(Library.class))
+          .build();
+
+  public MissingClassReferencedFromLibraryVirtualMethodReturnTest(TestParameters parameters) {
+    super(parameters);
+  }
+
+  @Test(expected = CompilationFailedException.class)
+  public void testNoRules() throws Exception {
+    compileWithExpectedDiagnostics(
+        Main.class,
+        diagnostics -> inspectDiagnosticsWithNoRules(diagnostics, referencedFrom),
+        addLibrary());
+  }
+
+  /**
+   * Main is the closest program context to the missing class reference, but it is not the context
+   * of the missing class reference (Library is). Therefore, compilation still fails in this case.
+   */
+  @Test(expected = CompilationFailedException.class)
+  public void testDontWarnMainClass() throws Exception {
+    compileWithExpectedDiagnostics(
+        Main.class,
+        diagnostics -> inspectDiagnosticsWithNoRules(diagnostics, referencedFrom),
+        addLibrary().andThen(addDontWarn(Main.class)));
+  }
+
+  @Test
+  public void testDontWarnLibraryClass() throws Exception {
+    compileWithExpectedDiagnostics(
+        Main.class,
+        TestDiagnosticMessages::assertNoMessages,
+        addLibrary().andThen(addDontWarn(Library.class)));
+  }
+
+  @Test
+  public void testDontWarnMissingClass() throws Exception {
+    compileWithExpectedDiagnostics(
+        Main.class,
+        TestDiagnosticMessages::assertNoMessages,
+        addLibrary().andThen(addDontWarn(MissingClass.class)));
+  }
+
+  @Test
+  public void testIgnoreWarnings() throws Exception {
+    compileWithExpectedDiagnostics(
+        Main.class,
+        diagnostics -> inspectDiagnosticsWithIgnoreWarnings(diagnostics, referencedFrom),
+        addLibrary().andThen(addIgnoreWarnings()));
+  }
+
+  private ThrowableConsumer<R8FullTestBuilder> addLibrary() {
+    return builder ->
+        builder.addLibraryClasses(Library.class).addLibraryFiles(getMostRecentAndroidJar());
+  }
+
+  static class Main extends Library {
+
+    public static void main(String[] args) {}
+  }
+
+  public static class Library {
+
+    public MissingClass method() {
+      return null;
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromMethodAnnotationTest.java b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromMethodAnnotationTest.java
index 189b49e..5130304 100644
--- a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromMethodAnnotationTest.java
+++ b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromMethodAnnotationTest.java
@@ -7,8 +7,9 @@
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.TestDiagnosticMessages;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.internal.MissingDefinitionMethodContextImpl;
 import com.android.tools.r8.references.ClassReference;
-import com.android.tools.r8.references.MethodReference;
 import com.android.tools.r8.references.Reference;
 import com.android.tools.r8.utils.MethodReferenceUtils;
 import org.junit.Test;
@@ -17,8 +18,11 @@
 //  we retain missing annotations even if there is no -keepattributes *Annotations*.
 public class MissingClassReferencedFromMethodAnnotationTest extends MissingClassesTestBase {
 
-  private static final MethodReference referencedFrom =
-      MethodReferenceUtils.mainMethod(Reference.classFromClass(Main.class));
+  private static final MissingDefinitionContext referencedFrom =
+      MissingDefinitionMethodContextImpl.builder()
+          .setMethodContext(MethodReferenceUtils.mainMethod(Main.class))
+          .setOrigin(getOrigin(Main.class))
+          .build();
 
   public MissingClassReferencedFromMethodAnnotationTest(TestParameters parameters) {
     super(parameters);
diff --git a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromNestHostAttributeTest.java b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromNestHostAttributeTest.java
index fc1ac99..194e12d 100644
--- a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromNestHostAttributeTest.java
+++ b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromNestHostAttributeTest.java
@@ -9,6 +9,8 @@
 import com.android.tools.r8.TestDiagnosticMessages;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.ThrowableConsumer;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.internal.MissingDefinitionClassContextImpl;
 import com.android.tools.r8.missingclasses.MissingClassReferencedFromNestHostAttributeTest.MissingClass.Main;
 import com.android.tools.r8.references.ClassReference;
 import com.android.tools.r8.references.Reference;
@@ -19,7 +21,11 @@
 
 public class MissingClassReferencedFromNestHostAttributeTest extends MissingClassesTestBase {
 
-  private static final ClassReference referencedFrom = Reference.classFromClass(Main.class);
+  private static final MissingDefinitionContext referencedFrom =
+      MissingDefinitionClassContextImpl.builder()
+          .setClassContext(Reference.classFromClass(Main.class))
+          .setOrigin(getOrigin(Main.class))
+          .build();
 
   public MissingClassReferencedFromNestHostAttributeTest(TestParameters parameters) {
     super(parameters);
diff --git a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromNestMemberAttributeTest.java b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromNestMemberAttributeTest.java
index a151dce..540620e 100644
--- a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromNestMemberAttributeTest.java
+++ b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromNestMemberAttributeTest.java
@@ -9,6 +9,8 @@
 import com.android.tools.r8.TestDiagnosticMessages;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.ThrowableConsumer;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.internal.MissingDefinitionClassContextImpl;
 import com.android.tools.r8.references.ClassReference;
 import com.android.tools.r8.references.Reference;
 import com.google.common.collect.ImmutableList;
@@ -18,7 +20,11 @@
 
 public class MissingClassReferencedFromNestMemberAttributeTest extends MissingClassesTestBase {
 
-  private static final ClassReference referencedFrom = Reference.classFromClass(Main.class);
+  private static final MissingDefinitionContext referencedFrom =
+      MissingDefinitionClassContextImpl.builder()
+          .setClassContext(Reference.classFromClass(Main.class))
+          .setOrigin(getOrigin(Main.class))
+          .build();
 
   public MissingClassReferencedFromNestMemberAttributeTest(TestParameters parameters) {
     super(parameters);
diff --git a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromNewArrayTest.java b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromNewArrayTest.java
index 66242bf..003b28e 100644
--- a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromNewArrayTest.java
+++ b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromNewArrayTest.java
@@ -7,15 +7,18 @@
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.TestDiagnosticMessages;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.references.MethodReference;
-import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.internal.MissingDefinitionMethodContextImpl;
 import com.android.tools.r8.utils.MethodReferenceUtils;
 import org.junit.Test;
 
 public class MissingClassReferencedFromNewArrayTest extends MissingClassesTestBase {
 
-  private static final MethodReference referencedFrom =
-      MethodReferenceUtils.mainMethod(Reference.classFromClass(Main.class));
+  private static final MissingDefinitionContext referencedFrom =
+      MissingDefinitionMethodContextImpl.builder()
+          .setMethodContext(MethodReferenceUtils.mainMethod(Main.class))
+          .setOrigin(getOrigin(Main.class))
+          .build();
 
   public MissingClassReferencedFromNewArrayTest(TestParameters parameters) {
     super(parameters);
diff --git a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromNewInstanceTest.java b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromNewInstanceTest.java
index 2af5045..ee919b2 100644
--- a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromNewInstanceTest.java
+++ b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromNewInstanceTest.java
@@ -7,15 +7,18 @@
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.TestDiagnosticMessages;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.references.MethodReference;
-import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.internal.MissingDefinitionMethodContextImpl;
 import com.android.tools.r8.utils.MethodReferenceUtils;
 import org.junit.Test;
 
 public class MissingClassReferencedFromNewInstanceTest extends MissingClassesTestBase {
 
-  private static final MethodReference referencedFrom =
-      MethodReferenceUtils.mainMethod(Reference.classFromClass(Main.class));
+  private static final MissingDefinitionContext referencedFrom =
+      MissingDefinitionMethodContextImpl.builder()
+          .setMethodContext(MethodReferenceUtils.mainMethod(Main.class))
+          .setOrigin(getOrigin(Main.class))
+          .build();
 
   public MissingClassReferencedFromNewInstanceTest(TestParameters parameters) {
     super(parameters);
diff --git a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromOuterClassAttributeTest.java b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromOuterClassAttributeTest.java
index d707f74..21d5683 100644
--- a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromOuterClassAttributeTest.java
+++ b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromOuterClassAttributeTest.java
@@ -11,6 +11,8 @@
 import com.android.tools.r8.R8TestBuilder;
 import com.android.tools.r8.TestDiagnosticMessages;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.internal.MissingDefinitionClassContextImpl;
 import com.android.tools.r8.missingclasses.MissingClassReferencedFromOuterClassAttributeTest.MissingClass.Main;
 import com.android.tools.r8.references.ClassReference;
 import com.android.tools.r8.references.Reference;
@@ -21,7 +23,11 @@
 
 public class MissingClassReferencedFromOuterClassAttributeTest extends MissingClassesTestBase {
 
-  private static final ClassReference referencedFrom = Reference.classFromClass(Main.class);
+  private static final MissingDefinitionContext referencedFrom =
+      MissingDefinitionClassContextImpl.builder()
+          .setClassContext(Reference.classFromClass(Main.class))
+          .setOrigin(getOrigin(Main.class))
+          .build();
 
   @Parameters(name = "{1}, report: {0}")
   public static List<Object[]> data() {
diff --git a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromParameterAnnotationTest.java b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromParameterAnnotationTest.java
index 0017aa7..a5b5432 100644
--- a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromParameterAnnotationTest.java
+++ b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromParameterAnnotationTest.java
@@ -7,8 +7,9 @@
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.TestDiagnosticMessages;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.internal.MissingDefinitionMethodContextImpl;
 import com.android.tools.r8.references.ClassReference;
-import com.android.tools.r8.references.MethodReference;
 import com.android.tools.r8.references.Reference;
 import com.android.tools.r8.utils.MethodReferenceUtils;
 import org.junit.Test;
@@ -17,8 +18,11 @@
 //  we retain missing annotations even if there is no -keepattributes *Annotations*.
 public class MissingClassReferencedFromParameterAnnotationTest extends MissingClassesTestBase {
 
-  private static final MethodReference referencedFrom =
-      MethodReferenceUtils.mainMethod(Reference.classFromClass(Main.class));
+  private static final MissingDefinitionContext referencedFrom =
+      MissingDefinitionMethodContextImpl.builder()
+          .setMethodContext(MethodReferenceUtils.mainMethod(Main.class))
+          .setOrigin(getOrigin(Main.class))
+          .build();
 
   public MissingClassReferencedFromParameterAnnotationTest(TestParameters parameters) {
     super(parameters);
diff --git a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromStaticGetToExistingFieldTest.java b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromStaticGetToExistingFieldTest.java
index e76c4c9..332da9c 100644
--- a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromStaticGetToExistingFieldTest.java
+++ b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromStaticGetToExistingFieldTest.java
@@ -7,8 +7,9 @@
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.TestDiagnosticMessages;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.references.FieldReference;
-import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.internal.MissingDefinitionFieldContextImpl;
+import com.android.tools.r8.utils.FieldReferenceUtils;
 import org.junit.Test;
 
 /**
@@ -17,11 +18,11 @@
  */
 public class MissingClassReferencedFromStaticGetToExistingFieldTest extends MissingClassesTestBase {
 
-  private static final FieldReference referencedFrom =
-      Reference.field(
-          Reference.classFromClass(Main.class),
-          "FIELD",
-          Reference.classFromClass(MissingClass.class));
+  private static final MissingDefinitionContext referencedFrom =
+      MissingDefinitionFieldContextImpl.builder()
+          .setFieldContext(FieldReferenceUtils.fieldFromField(Main.class, "FIELD"))
+          .setOrigin(getOrigin(Main.class))
+          .build();
 
   public MissingClassReferencedFromStaticGetToExistingFieldTest(TestParameters parameters) {
     super(parameters);
diff --git a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromStaticGetToMissingFieldTest.java b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromStaticGetToMissingFieldTest.java
index 36f8a29..9028167 100644
--- a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromStaticGetToMissingFieldTest.java
+++ b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromStaticGetToMissingFieldTest.java
@@ -7,8 +7,8 @@
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.TestDiagnosticMessages;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.references.MethodReference;
-import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.internal.MissingDefinitionMethodContextImpl;
 import com.android.tools.r8.utils.MethodReferenceUtils;
 import org.junit.Test;
 
@@ -18,8 +18,11 @@
  */
 public class MissingClassReferencedFromStaticGetToMissingFieldTest extends MissingClassesTestBase {
 
-  private static final MethodReference referencedFrom =
-      MethodReferenceUtils.mainMethod(Reference.classFromClass(Main.class));
+  private static final MissingDefinitionContext referencedFrom =
+      MissingDefinitionMethodContextImpl.builder()
+          .setMethodContext(MethodReferenceUtils.mainMethod(Main.class))
+          .setOrigin(getOrigin(Main.class))
+          .build();
 
   public MissingClassReferencedFromStaticGetToMissingFieldTest(TestParameters parameters) {
     super(parameters);
diff --git a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromStaticPutToExistingFieldTest.java b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromStaticPutToExistingFieldTest.java
index 542c928..cbbd217 100644
--- a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromStaticPutToExistingFieldTest.java
+++ b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromStaticPutToExistingFieldTest.java
@@ -7,8 +7,9 @@
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.TestDiagnosticMessages;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.references.FieldReference;
-import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.internal.MissingDefinitionFieldContextImpl;
+import com.android.tools.r8.utils.FieldReferenceUtils;
 import org.junit.Test;
 
 /**
@@ -17,11 +18,11 @@
  */
 public class MissingClassReferencedFromStaticPutToExistingFieldTest extends MissingClassesTestBase {
 
-  private static final FieldReference referencedFrom =
-      Reference.field(
-          Reference.classFromClass(Main.class),
-          "FIELD",
-          Reference.classFromClass(MissingClass.class));
+  private static final MissingDefinitionContext referencedFrom =
+      MissingDefinitionFieldContextImpl.builder()
+          .setFieldContext(FieldReferenceUtils.fieldFromField(Main.class, "FIELD"))
+          .setOrigin(getOrigin(Main.class))
+          .build();
 
   public MissingClassReferencedFromStaticPutToExistingFieldTest(TestParameters parameters) {
     super(parameters);
diff --git a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromStaticPutToMissingFieldTest.java b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromStaticPutToMissingFieldTest.java
index 542d509..e1ba4c6 100644
--- a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromStaticPutToMissingFieldTest.java
+++ b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromStaticPutToMissingFieldTest.java
@@ -7,8 +7,8 @@
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.TestDiagnosticMessages;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.references.MethodReference;
-import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.internal.MissingDefinitionMethodContextImpl;
 import com.android.tools.r8.utils.MethodReferenceUtils;
 import org.junit.Test;
 
@@ -18,8 +18,11 @@
  */
 public class MissingClassReferencedFromStaticPutToMissingFieldTest extends MissingClassesTestBase {
 
-  private static final MethodReference referencedFrom =
-      MethodReferenceUtils.mainMethod(Reference.classFromClass(Main.class));
+  private static final MissingDefinitionContext referencedFrom =
+      MissingDefinitionMethodContextImpl.builder()
+          .setMethodContext(MethodReferenceUtils.mainMethod(Main.class))
+          .setOrigin(getOrigin(Main.class))
+          .build();
 
   public MissingClassReferencedFromStaticPutToMissingFieldTest(TestParameters parameters) {
     super(parameters);
diff --git a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromSuperClassTest.java b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromSuperClassTest.java
index 7aeb068..79cff47 100644
--- a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromSuperClassTest.java
+++ b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromSuperClassTest.java
@@ -8,13 +8,18 @@
 import com.android.tools.r8.TestCompilerBuilder;
 import com.android.tools.r8.TestDiagnosticMessages;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.internal.MissingDefinitionClassContextImpl;
 import com.android.tools.r8.references.Reference;
 import org.junit.Test;
 
 public class MissingClassReferencedFromSuperClassTest extends MissingClassesTestBase {
 
-  private static final ClassReference referencedFrom = Reference.classFromClass(Main.class);
+  private static final MissingDefinitionContext referencedFrom =
+      MissingDefinitionClassContextImpl.builder()
+          .setClassContext(Reference.classFromClass(Main.class))
+          .setOrigin(getOrigin(Main.class))
+          .build();
 
   public MissingClassReferencedFromSuperClassTest(TestParameters parameters) {
     super(parameters);
diff --git a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromThrowsClauseTest.java b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromThrowsClauseTest.java
index 1708330..275e6f2 100644
--- a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromThrowsClauseTest.java
+++ b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromThrowsClauseTest.java
@@ -8,15 +8,18 @@
 import com.android.tools.r8.TestDiagnosticMessages;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestShrinkerBuilder;
-import com.android.tools.r8.references.MethodReference;
-import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.internal.MissingDefinitionMethodContextImpl;
 import com.android.tools.r8.utils.MethodReferenceUtils;
 import org.junit.Test;
 
 public class MissingClassReferencedFromThrowsClauseTest extends MissingClassesTestBase {
 
-  private static final MethodReference referencedFrom =
-      MethodReferenceUtils.mainMethod(Reference.classFromClass(Main.class));
+  private static final MissingDefinitionContext referencedFrom =
+      MissingDefinitionMethodContextImpl.builder()
+          .setMethodContext(MethodReferenceUtils.mainMethod(Main.class))
+          .setOrigin(getOrigin(Main.class))
+          .build();
 
   public MissingClassReferencedFromThrowsClauseTest(TestParameters parameters) {
     super(parameters);
diff --git a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromUnusedLambdaParameterTest.java b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromUnusedLambdaParameterTest.java
new file mode 100644
index 0000000..31ca7d1
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromUnusedLambdaParameterTest.java
@@ -0,0 +1,125 @@
+// 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.missingclasses;
+
+import static com.android.tools.r8.utils.codeinspector.AssertUtils.assertFailsCompilationIf;
+
+import com.android.tools.r8.R8FullTestBuilder;
+import com.android.tools.r8.R8TestBuilder;
+import com.android.tools.r8.TestDiagnosticMessages;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ThrowableConsumer;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.internal.MissingDefinitionMethodContextImpl;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.utils.MethodReferenceUtils;
+import com.google.common.collect.ImmutableList;
+import org.junit.Test;
+
+public class MissingClassReferencedFromUnusedLambdaParameterTest extends MissingClassesTestBase {
+
+  private static final MissingDefinitionContext[] referencedFrom =
+      new MissingDefinitionContext[] {
+        MissingDefinitionMethodContextImpl.builder()
+            .setMethodContext(
+                Reference.method(
+                    Reference.classFromClass(Main.class),
+                    "lambda$main$0",
+                    ImmutableList.of(Reference.classFromClass(MissingClass.class)),
+                    null))
+            .setOrigin(getOrigin(Main.class))
+            .build(),
+        MissingDefinitionMethodContextImpl.builder()
+            .setMethodContext(MethodReferenceUtils.mainMethod(Main.class))
+            .setOrigin(getOrigin(Main.class))
+            .build(),
+      };
+
+  public MissingClassReferencedFromUnusedLambdaParameterTest(TestParameters parameters) {
+    super(parameters);
+  }
+
+  @Test
+  public void testNoRules() throws Exception {
+    assertFailsCompilationIf(
+        parameters.isCfRuntime(),
+        () ->
+            compileWithExpectedDiagnostics(
+                Main.class,
+                parameters.isCfRuntime()
+                    ? diagnostics -> inspectDiagnosticsWithNoRules(diagnostics, referencedFrom)
+                    : TestDiagnosticMessages::assertNoMessages,
+                addInterface()));
+  }
+
+  // The lambda is never called, therefore the lambda class' virtual method is dead, and therefore
+  // we never trace into lambda$main$0(). Therefore, we need allowUnusedDontWarnPatterns() here.
+  @Test
+  public void testDontWarnMainClass() throws Exception {
+    compileWithExpectedDiagnostics(
+        Main.class,
+        TestDiagnosticMessages::assertNoMessages,
+        addInterface()
+            .andThen(
+                builder ->
+                    builder
+                        .addDontWarn(Main.class)
+                        .applyIf(
+                            parameters.isDexRuntime(),
+                            R8TestBuilder::allowUnusedDontWarnPatterns)));
+  }
+
+  // The lambda is never called, therefore the lambda class' virtual method is dead, and therefore
+  // we never trace into lambda$main$0(). Therefore, we need allowUnusedDontWarnPatterns() here.
+  @Test
+  public void testDontWarnMissingClass() throws Exception {
+    compileWithExpectedDiagnostics(
+        Main.class,
+        TestDiagnosticMessages::assertNoMessages,
+        addInterface()
+            .andThen(
+                builder ->
+                    builder
+                        .addDontWarn(Main.class)
+                        .applyIf(
+                            parameters.isDexRuntime(),
+                            R8TestBuilder::allowUnusedDontWarnPatterns)));
+  }
+
+  @Test
+  public void testIgnoreWarnings() throws Exception {
+    compileWithExpectedDiagnostics(
+        Main.class,
+        parameters.isCfRuntime()
+            ? diagnostics -> inspectDiagnosticsWithIgnoreWarnings(diagnostics, referencedFrom)
+            : TestDiagnosticMessages::assertNoMessages,
+        addInterface()
+            .andThen(
+                builder ->
+                    builder
+                        .addIgnoreWarnings()
+                        .applyIf(
+                            parameters.isCfRuntime(),
+                            R8TestBuilder::allowDiagnosticWarningMessages)));
+  }
+
+  ThrowableConsumer<R8FullTestBuilder> addInterface() {
+    return builder -> builder.addProgramClasses(I.class);
+  }
+
+  static class Main {
+
+    public static void main(String[] args) {
+      I ignore = mc -> {};
+    }
+
+    /* private static synthetic void lambda$main$0(MissingClass mc) {} */
+  }
+
+  interface I {
+
+    void m(MissingClass mc);
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromUnusedLambdaReturnTest.java b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromUnusedLambdaReturnTest.java
new file mode 100644
index 0000000..8859780
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromUnusedLambdaReturnTest.java
@@ -0,0 +1,125 @@
+// 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.missingclasses;
+
+import static com.android.tools.r8.utils.codeinspector.AssertUtils.assertFailsCompilationIf;
+
+import com.android.tools.r8.R8FullTestBuilder;
+import com.android.tools.r8.R8TestBuilder;
+import com.android.tools.r8.TestDiagnosticMessages;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ThrowableConsumer;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.internal.MissingDefinitionMethodContextImpl;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.utils.MethodReferenceUtils;
+import java.util.Collections;
+import org.junit.Test;
+
+public class MissingClassReferencedFromUnusedLambdaReturnTest extends MissingClassesTestBase {
+
+  private static final MissingDefinitionContext[] referencedFrom =
+      new MissingDefinitionContext[] {
+        MissingDefinitionMethodContextImpl.builder()
+            .setMethodContext(
+                Reference.method(
+                    Reference.classFromClass(Main.class),
+                    "lambda$main$0",
+                    Collections.emptyList(),
+                    Reference.classFromClass(MissingClass.class)))
+            .setOrigin(getOrigin(Main.class))
+            .build(),
+        MissingDefinitionMethodContextImpl.builder()
+            .setMethodContext(MethodReferenceUtils.mainMethod(Main.class))
+            .setOrigin(getOrigin(Main.class))
+            .build(),
+      };
+
+  public MissingClassReferencedFromUnusedLambdaReturnTest(TestParameters parameters) {
+    super(parameters);
+  }
+
+  @Test
+  public void testNoRules() throws Exception {
+    assertFailsCompilationIf(
+        parameters.isCfRuntime(),
+        () ->
+            compileWithExpectedDiagnostics(
+                Main.class,
+                parameters.isCfRuntime()
+                    ? diagnostics -> inspectDiagnosticsWithNoRules(diagnostics, referencedFrom)
+                    : TestDiagnosticMessages::assertNoMessages,
+                addInterface()));
+  }
+
+  // The lambda is never called, therefore the lambda class' virtual method is dead, and therefore
+  // we never trace into lambda$main$0(). Therefore, we need allowUnusedDontWarnPatterns() here.
+  @Test
+  public void testDontWarnMainClass() throws Exception {
+    compileWithExpectedDiagnostics(
+        Main.class,
+        TestDiagnosticMessages::assertNoMessages,
+        addInterface()
+            .andThen(
+                builder ->
+                    builder
+                        .addDontWarn(Main.class)
+                        .applyIf(
+                            parameters.isDexRuntime(),
+                            R8TestBuilder::allowUnusedDontWarnPatterns)));
+  }
+
+  // The lambda is never called, therefore the lambda class' virtual method is dead, and therefore
+  // we never trace into lambda$main$0(). Therefore, we need allowUnusedDontWarnPatterns() here.
+  @Test
+  public void testDontWarnMissingClass() throws Exception {
+    compileWithExpectedDiagnostics(
+        Main.class,
+        TestDiagnosticMessages::assertNoMessages,
+        addInterface()
+            .andThen(
+                builder ->
+                    builder
+                        .addDontWarn(MissingClass.class)
+                        .applyIf(
+                            parameters.isDexRuntime(),
+                            R8TestBuilder::allowUnusedDontWarnPatterns)));
+  }
+
+  @Test
+  public void testIgnoreWarnings() throws Exception {
+    compileWithExpectedDiagnostics(
+        Main.class,
+        parameters.isCfRuntime()
+            ? diagnostics -> inspectDiagnosticsWithIgnoreWarnings(diagnostics, referencedFrom)
+            : TestDiagnosticMessages::assertNoMessages,
+        addInterface()
+            .andThen(
+                builder ->
+                    builder
+                        .addIgnoreWarnings()
+                        .applyIf(
+                            parameters.isCfRuntime(),
+                            R8TestBuilder::allowDiagnosticWarningMessages)));
+  }
+
+  ThrowableConsumer<R8FullTestBuilder> addInterface() {
+    return builder -> builder.addProgramClasses(I.class);
+  }
+
+  static class Main {
+
+    public static void main(String[] args) {
+      I ignore = () -> null;
+    }
+
+    /* private static synthetic MissingClass lambda$main$0() { return null; } */
+  }
+
+  interface I {
+
+    MissingClass m();
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromUsedLambdaParameterTest.java b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromUsedLambdaParameterTest.java
new file mode 100644
index 0000000..a9ece97
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromUsedLambdaParameterTest.java
@@ -0,0 +1,97 @@
+// 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.missingclasses;
+
+import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.R8FullTestBuilder;
+import com.android.tools.r8.TestDiagnosticMessages;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ThrowableConsumer;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.internal.MissingDefinitionMethodContextImpl;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.utils.MethodReferenceUtils;
+import com.google.common.collect.ImmutableList;
+import org.junit.Test;
+
+public class MissingClassReferencedFromUsedLambdaParameterTest extends MissingClassesTestBase {
+
+  private final MissingDefinitionContext[] referencedFrom =
+      new MissingDefinitionContext[] {
+        MissingDefinitionMethodContextImpl.builder()
+            .setMethodContext(
+                MethodReferenceUtils.methodFromMethod(I.class, "m", MissingClass.class))
+            .setOrigin(getOrigin(I.class))
+            .build(),
+        MissingDefinitionMethodContextImpl.builder()
+            .setMethodContext(
+                Reference.method(
+                    Reference.classFromClass(Main.class),
+                    "lambda$main$0",
+                    ImmutableList.of(Reference.classFromClass(MissingClass.class)),
+                    null))
+            .setOrigin(getOrigin(Main.class))
+            .build(),
+        MissingDefinitionMethodContextImpl.builder()
+            .setMethodContext(MethodReferenceUtils.mainMethod(Main.class))
+            .setOrigin(getOrigin(Main.class))
+            .build()
+      };
+
+  public MissingClassReferencedFromUsedLambdaParameterTest(TestParameters parameters) {
+    super(parameters);
+  }
+
+  @Test(expected = CompilationFailedException.class)
+  public void testNoRules() throws Exception {
+    compileWithExpectedDiagnostics(
+        Main.class,
+        diagnostics -> inspectDiagnosticsWithNoRules(diagnostics, referencedFrom),
+        addInterface());
+  }
+
+  @Test
+  public void testDontWarnMainClassAndInterface() throws Exception {
+    compileWithExpectedDiagnostics(
+        Main.class,
+        TestDiagnosticMessages::assertNoMessages,
+        addInterface().andThen(addDontWarn(Main.class, I.class)));
+  }
+
+  @Test
+  public void testDontWarnMissingClass() throws Exception {
+    compileWithExpectedDiagnostics(
+        Main.class,
+        TestDiagnosticMessages::assertNoMessages,
+        addInterface().andThen(addDontWarn(MissingClass.class)));
+  }
+
+  @Test
+  public void testIgnoreWarnings() throws Exception {
+    compileWithExpectedDiagnostics(
+        Main.class,
+        diagnostics -> inspectDiagnosticsWithIgnoreWarnings(diagnostics, referencedFrom),
+        addInterface().andThen(addIgnoreWarnings()));
+  }
+
+  ThrowableConsumer<R8FullTestBuilder> addInterface() {
+    return builder -> builder.addProgramClasses(I.class);
+  }
+
+  static class Main {
+
+    public static void main(String[] args) {
+      I i = mc -> {};
+      i.m(null);
+    }
+
+    /* private static synthetic void lambda$main$0(MissingClass mc) {} */
+  }
+
+  interface I {
+
+    void m(MissingClass mc);
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromUsedLambdaReturnTest.java b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromUsedLambdaReturnTest.java
new file mode 100644
index 0000000..ba46bfc
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/missingclasses/MissingClassReferencedFromUsedLambdaReturnTest.java
@@ -0,0 +1,96 @@
+// 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.missingclasses;
+
+import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.R8FullTestBuilder;
+import com.android.tools.r8.TestDiagnosticMessages;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ThrowableConsumer;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.internal.MissingDefinitionMethodContextImpl;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.utils.MethodReferenceUtils;
+import java.util.Collections;
+import org.junit.Test;
+
+public class MissingClassReferencedFromUsedLambdaReturnTest extends MissingClassesTestBase {
+
+  private final MissingDefinitionContext[] referencedFrom =
+      new MissingDefinitionContext[] {
+        MissingDefinitionMethodContextImpl.builder()
+            .setMethodContext(MethodReferenceUtils.methodFromMethod(I.class, "m"))
+            .setOrigin(getOrigin(I.class))
+            .build(),
+        MissingDefinitionMethodContextImpl.builder()
+            .setMethodContext(
+                Reference.method(
+                    Reference.classFromClass(Main.class),
+                    "lambda$main$0",
+                    Collections.emptyList(),
+                    Reference.classFromClass(MissingClass.class)))
+            .setOrigin(getOrigin(Main.class))
+            .build(),
+        MissingDefinitionMethodContextImpl.builder()
+            .setMethodContext(MethodReferenceUtils.mainMethod(Main.class))
+            .setOrigin(getOrigin(Main.class))
+            .build()
+      };
+
+  public MissingClassReferencedFromUsedLambdaReturnTest(TestParameters parameters) {
+    super(parameters);
+  }
+
+  @Test(expected = CompilationFailedException.class)
+  public void testNoRules() throws Exception {
+    compileWithExpectedDiagnostics(
+        Main.class,
+        diagnostics -> inspectDiagnosticsWithNoRules(diagnostics, referencedFrom),
+        addInterface());
+  }
+
+  @Test
+  public void testDontWarnMainClassAndInterface() throws Exception {
+    compileWithExpectedDiagnostics(
+        Main.class,
+        TestDiagnosticMessages::assertNoMessages,
+        addInterface().andThen(addDontWarn(Main.class, I.class)));
+  }
+
+  @Test
+  public void testDontWarnMissingClass() throws Exception {
+    compileWithExpectedDiagnostics(
+        Main.class,
+        TestDiagnosticMessages::assertNoMessages,
+        addInterface().andThen(addDontWarn(MissingClass.class)));
+  }
+
+  @Test
+  public void testIgnoreWarnings() throws Exception {
+    compileWithExpectedDiagnostics(
+        Main.class,
+        diagnostics -> inspectDiagnosticsWithIgnoreWarnings(diagnostics, referencedFrom),
+        addInterface().andThen(addIgnoreWarnings()));
+  }
+
+  ThrowableConsumer<R8FullTestBuilder> addInterface() {
+    return builder -> builder.addProgramClasses(I.class);
+  }
+
+  static class Main {
+
+    public static void main(String[] args) {
+      I i = () -> null;
+      i.m();
+    }
+
+    /* private static synthetic MissingClass lambda$main$0() { return null; } */
+  }
+
+  interface I {
+
+    MissingClass m();
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/missingclasses/MissingClassesTestBase.java b/src/test/java/com/android/tools/r8/missingclasses/MissingClassesTestBase.java
index 3968b75..f9941c0 100644
--- a/src/test/java/com/android/tools/r8/missingclasses/MissingClassesTestBase.java
+++ b/src/test/java/com/android/tools/r8/missingclasses/MissingClassesTestBase.java
@@ -4,8 +4,7 @@
 
 package com.android.tools.r8.missingclasses;
 
-import static com.android.tools.r8.DiagnosticsMatcher.diagnosticType;
-import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.R8FullTestBuilder;
@@ -14,19 +13,14 @@
 import com.android.tools.r8.TestDiagnosticMessages;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.ThrowableConsumer;
-import com.android.tools.r8.diagnostic.internal.MissingDefinitionsDiagnosticImpl;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
+import com.android.tools.r8.diagnostic.internal.MissingDefinitionContextUtils;
 import com.android.tools.r8.references.ClassReference;
-import com.android.tools.r8.references.FieldReference;
-import com.android.tools.r8.references.MethodReference;
 import com.android.tools.r8.references.Reference;
-import com.android.tools.r8.utils.FieldReferenceUtils;
 import com.android.tools.r8.utils.InternalOptions.TestingOptions;
-import com.android.tools.r8.utils.MethodReferenceUtils;
-import com.google.common.collect.ImmutableSet;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.List;
-import java.util.function.Function;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
 import org.junit.runners.Parameterized.Parameters;
@@ -46,7 +40,7 @@
 
   interface MissingInterface {}
 
-  private final TestParameters parameters;
+  protected final TestParameters parameters;
 
   @Parameters(name = "{0}")
   public static List<Object[]> data() {
@@ -57,8 +51,8 @@
     this.parameters = parameters;
   }
 
-  public ThrowableConsumer<R8FullTestBuilder> addDontWarn(Class<?> clazz) {
-    return builder -> builder.addDontWarn(clazz);
+  public ThrowableConsumer<R8FullTestBuilder> addDontWarn(Class<?>... classes) {
+    return builder -> builder.addDontWarn(classes);
   }
 
   public ThrowableConsumer<R8FullTestBuilder> addIgnoreWarnings() {
@@ -109,92 +103,79 @@
   }
 
   void inspectDiagnosticsWithIgnoreWarnings(
-      TestDiagnosticMessages diagnostics, ClassReference referencedFrom) {
+      TestDiagnosticMessages diagnostics, MissingDefinitionContext... referencedFrom) {
+    assertTrue(referencedFrom.length > 0);
     inspectDiagnosticsWithIgnoreWarnings(
         diagnostics,
-        getExpectedDiagnosticMessageWithIgnoreWarnings(
-            referencedFrom, ClassReference::getTypeName));
+        referencedFrom,
+        getExpectedDiagnosticMessage(
+            MissingDefinitionContextUtils.toSourceString(referencedFrom[0]),
+            referencedFrom.length));
   }
 
   void inspectDiagnosticsWithIgnoreWarnings(
-      TestDiagnosticMessages diagnostics, FieldReference referencedFrom) {
-    inspectDiagnosticsWithIgnoreWarnings(
-        diagnostics,
-        getExpectedDiagnosticMessageWithIgnoreWarnings(
-            referencedFrom, FieldReferenceUtils::toSourceString));
-  }
-
-  void inspectDiagnosticsWithIgnoreWarnings(
-      TestDiagnosticMessages diagnostics, MethodReference referencedFrom) {
-    inspectDiagnosticsWithIgnoreWarnings(
-        diagnostics,
-        getExpectedDiagnosticMessageWithIgnoreWarnings(
-            referencedFrom, MethodReferenceUtils::toSourceString));
-  }
-
-  void inspectDiagnosticsWithIgnoreWarnings(
-      TestDiagnosticMessages diagnostics, String expectedDiagnosticMessage) {
-    MissingDefinitionsDiagnosticImpl diagnostic =
-        diagnostics
-            .assertOnlyWarnings()
-            .assertWarningsCount(1)
-            .assertAllWarningsMatch(diagnosticType(MissingDefinitionsDiagnosticImpl.class))
-            .getWarning(0);
-    assertEquals(ImmutableSet.of(getMissingClassReference()), diagnostic.getMissingClasses());
-    assertEquals(expectedDiagnosticMessage, diagnostic.getDiagnosticMessage());
-  }
-
-  private <T> String getExpectedDiagnosticMessageWithIgnoreWarnings(
-      T referencedFrom, Function<T, String> toSourceStringFunction) {
-    return "Missing class "
-        + getMissingClassReference().getTypeName()
-        + " (referenced from: "
-        + toSourceStringFunction.apply(referencedFrom)
-        + ")";
+      TestDiagnosticMessages diagnostics,
+      MissingDefinitionContext[] referencedFrom,
+      String expectedDiagnosticMessage) {
+    diagnostics
+        .assertOnlyWarnings()
+        .inspectWarnings(
+            diagnostic ->
+                diagnostic
+                    .assertIsMissingDefinitionsDiagnostic()
+                    .applyIf(
+                        referencedFrom != null,
+                        checker ->
+                            checker.assertIsMissingClassWithExactContexts(
+                                getMissingClassReference(), referencedFrom),
+                        checker -> checker.assertIsMissingClass(getMissingClassReference()))
+                    .assertHasMessage(expectedDiagnosticMessage)
+                    .assertNumberOfMissingClasses(1));
   }
 
   void inspectDiagnosticsWithNoRules(
-      TestDiagnosticMessages diagnostics, ClassReference referencedFrom) {
+      TestDiagnosticMessages diagnostics, MissingDefinitionContext... referencedFrom) {
+    assertTrue(referencedFrom.length > 0);
     inspectDiagnosticsWithNoRules(
         diagnostics,
-        getExpectedDiagnosticMessageWithNoRules(referencedFrom, ClassReference::getTypeName));
+        referencedFrom,
+        getExpectedDiagnosticMessage(
+            MissingDefinitionContextUtils.toSourceString(referencedFrom[0]),
+            referencedFrom.length));
   }
 
   void inspectDiagnosticsWithNoRules(
-      TestDiagnosticMessages diagnostics, FieldReference referencedFrom) {
-    inspectDiagnosticsWithNoRules(
-        diagnostics,
-        getExpectedDiagnosticMessageWithNoRules(
-            referencedFrom, FieldReferenceUtils::toSourceString));
+      TestDiagnosticMessages diagnostics,
+      MissingDefinitionContext[] referencedFrom,
+      String expectedDiagnosticMessage) {
+    diagnostics
+        .assertOnlyErrors()
+        .inspectErrors(
+            diagnostic ->
+                diagnostic
+                    .assertIsMissingDefinitionsDiagnostic()
+                    .applyIf(
+                        referencedFrom != null,
+                        checker ->
+                            checker.assertIsMissingClassWithExactContexts(
+                                getMissingClassReference(), referencedFrom),
+                        checker -> checker.assertIsMissingClass(getMissingClassReference()))
+                    .assertHasMessage(expectedDiagnosticMessage)
+                    .assertNumberOfMissingClasses(1));
   }
 
-  void inspectDiagnosticsWithNoRules(
-      TestDiagnosticMessages diagnostics, MethodReference referencedFrom) {
-    inspectDiagnosticsWithNoRules(
-        diagnostics,
-        getExpectedDiagnosticMessageWithNoRules(
-            referencedFrom, MethodReferenceUtils::toSourceString));
-  }
-
-  void inspectDiagnosticsWithNoRules(
-      TestDiagnosticMessages diagnostics, String expectedDiagnosticMessage) {
-    MissingDefinitionsDiagnosticImpl diagnostic =
-        diagnostics
-            .assertOnlyErrors()
-            .assertErrorsCount(1)
-            .assertAllErrorsMatch(diagnosticType(MissingDefinitionsDiagnosticImpl.class))
-            .getError(0);
-    assertEquals(ImmutableSet.of(getMissingClassReference()), diagnostic.getMissingClasses());
-    assertEquals(expectedDiagnosticMessage, diagnostic.getDiagnosticMessage());
-  }
-
-  private <T> String getExpectedDiagnosticMessageWithNoRules(
-      T referencedFrom, Function<T, String> toSourceStringFunction) {
-    return "Compilation can't be completed because the following class is missing: "
-        + getMissingClassReference().getTypeName()
-        + " (referenced from: "
-        + toSourceStringFunction.apply(referencedFrom)
-        + ")"
-        + ".";
+  private String getExpectedDiagnosticMessage(String referencedFrom, int numberOfContexts) {
+    StringBuilder builder =
+        new StringBuilder("Missing class ")
+            .append(getMissingClassReference().getTypeName())
+            .append(" (referenced from: ")
+            .append(referencedFrom);
+    if (numberOfContexts > 1) {
+      builder.append(", and ").append(numberOfContexts - 1).append(" other context");
+      if (numberOfContexts > 2) {
+        builder.append("s");
+      }
+    }
+    return builder.append(")").toString();
   }
 }
diff --git a/src/test/java/com/android/tools/r8/naming/EnumMinificationKotlinTest.java b/src/test/java/com/android/tools/r8/naming/EnumMinificationKotlinTest.java
index f911ce6..413a4fd 100644
--- a/src/test/java/com/android/tools/r8/naming/EnumMinificationKotlinTest.java
+++ b/src/test/java/com/android/tools/r8/naming/EnumMinificationKotlinTest.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.naming;
 
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static org.hamcrest.CoreMatchers.equalTo;
@@ -52,11 +53,12 @@
   public void b121221542() throws Exception {
     CodeInspector inspector =
         testForR8(parameters.getBackend())
-            .addProgramFiles(compiledJars.getForConfiguration(kotlinc, targetVersion))
+            .addProgramFiles(
+                compiledJars.getForConfiguration(kotlinc, targetVersion),
+                getKotlinAnnotationJar(kotlinc))
             .addProgramFiles(getJavaJarFile(FOLDER))
             .addKeepMainRule(MAIN_CLASS_NAME)
             .addKeepClassRulesWithAllowObfuscation(ENUM_CLASS_NAME)
-            .addDontWarnJetBrainsAnnotations()
             .allowDiagnosticWarningMessages()
             .minification(minify)
             .setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/naming/IdentifierMinifierTest.java b/src/test/java/com/android/tools/r8/naming/IdentifierMinifierTest.java
index 8775bd7..6597cb0 100644
--- a/src/test/java/com/android/tools/r8/naming/IdentifierMinifierTest.java
+++ b/src/test/java/com/android/tools/r8/naming/IdentifierMinifierTest.java
@@ -72,8 +72,11 @@
             .enableProguardTestOptions()
             .setMinApi(parameters.getApiLevel())
             .compile()
-            .assertAllWarningMessagesMatch(
-                containsString("Cannot determine what identifier string flows to"))
+            .applyIf(
+                hasWarning,
+                result ->
+                    result.assertAllWarningMessagesMatch(
+                        containsString("Cannot determine what identifier string flows to")))
             .inspector();
     inspection.accept(parameters, codeInspector);
   }
diff --git a/src/test/java/com/android/tools/r8/naming/InterfaceRenamingTestRunner.java b/src/test/java/com/android/tools/r8/naming/InterfaceRenamingTestRunner.java
index ecbafd6..f40e8b3 100644
--- a/src/test/java/com/android/tools/r8/naming/InterfaceRenamingTestRunner.java
+++ b/src/test/java/com/android/tools/r8/naming/InterfaceRenamingTestRunner.java
@@ -22,7 +22,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-@RunWith(VmTestRunner.class)
 public class InterfaceRenamingTestRunner extends TestBase {
 
   private static final Class<?> CLASS = InterfaceRenamingTest.class;
diff --git a/src/test/java/com/android/tools/r8/naming/KotlinIntrinsicsIdentifierTest.java b/src/test/java/com/android/tools/r8/naming/KotlinIntrinsicsIdentifierTest.java
index 3aff7c9..3c52044 100644
--- a/src/test/java/com/android/tools/r8/naming/KotlinIntrinsicsIdentifierTest.java
+++ b/src/test/java/com/android/tools/r8/naming/KotlinIntrinsicsIdentifierTest.java
@@ -4,6 +4,7 @@
 package com.android.tools.r8.naming;
 
 import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.KOTLINC_1_3_72;
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static org.hamcrest.CoreMatchers.equalTo;
 import static org.hamcrest.MatcherAssert.assertThat;
@@ -91,10 +92,11 @@
     String mainClassName = ex3.getClassName();
     TestCompileResult<?, ?> result =
         testForR8(Backend.DEX)
-            .addProgramFiles(compiledJars.getForConfiguration(kotlinc, targetVersion))
+            .addProgramFiles(
+                compiledJars.getForConfiguration(kotlinc, targetVersion),
+                getKotlinAnnotationJar(kotlinc))
             .addProgramFiles(getJavaJarFile(FOLDER))
             .addKeepMainRule(mainClassName)
-            .addDontWarnJetBrainsNotNullAnnotation()
             .allowDiagnosticWarningMessages()
             .minification(minification)
             .compile()
@@ -145,7 +147,9 @@
     String mainClassName = testMain.getClassName();
     SingleTestRunResult<?> result =
         testForR8(Backend.DEX)
-            .addProgramFiles(compiledJars.getForConfiguration(kotlinc, targetVersion))
+            .addProgramFiles(
+                compiledJars.getForConfiguration(kotlinc, targetVersion),
+                getKotlinAnnotationJar(kotlinc))
             .addProgramFiles(getJavaJarFile(FOLDER))
             .enableProguardTestOptions()
             .addKeepMainRule(mainClassName)
@@ -155,7 +159,6 @@
                     "-" + NoVerticalClassMergingRule.RULE_NAME + " class **." + targetClassName,
                     "-" + NoHorizontalClassMergingRule.RULE_NAME + " class **." + targetClassName,
                     "-neverinline class **." + targetClassName + " { <methods>; }"))
-            .addDontWarnJetBrainsNotNullAnnotation()
             .allowDiagnosticWarningMessages()
             .minification(minification)
             .compile()
diff --git a/src/test/java/com/android/tools/r8/naming/LambdaRenamingTestRunner.java b/src/test/java/com/android/tools/r8/naming/LambdaRenamingTestRunner.java
index 7c25445..bdd3603 100644
--- a/src/test/java/com/android/tools/r8/naming/LambdaRenamingTestRunner.java
+++ b/src/test/java/com/android/tools/r8/naming/LambdaRenamingTestRunner.java
@@ -5,126 +5,106 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.ByteDataView;
-import com.android.tools.r8.ClassFileConsumer;
 import com.android.tools.r8.ClassFileConsumer.ArchiveConsumer;
-import com.android.tools.r8.CompilationMode;
-import com.android.tools.r8.DexIndexedConsumer;
-import com.android.tools.r8.ProgramConsumer;
-import com.android.tools.r8.R8Command;
-import com.android.tools.r8.R8Command.Builder;
 import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.ToolHelper.ProcessResult;
-import com.android.tools.r8.VmTestRunner;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.FileUtils;
+import com.android.tools.r8.utils.StringUtils;
 import java.io.IOException;
 import java.nio.file.Path;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
 
-@RunWith(VmTestRunner.class)
+@RunWith(Parameterized.class)
 public class LambdaRenamingTestRunner extends TestBase {
-  static final Class CLASS = LambdaRenamingTest.class;
-  static final Class[] CLASSES = LambdaRenamingTest.CLASSES;
+
+  private static final Class<?> CLASS = LambdaRenamingTest.class;
+  private static final Class<?>[] CLASSES = LambdaRenamingTest.CLASSES;
+  private static final String EXPECTED =
+      StringUtils.lines(
+          "null", "null", "null", "null", "10", "null", "null", "null", "null", "11", "10", "30",
+          "10", "30", "101", "301", "101", "301", "102", "302", "102", "302");
+
+  private final TestParameters parameters;
 
   private Path inputJar;
-  private ProcessResult runInput;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  public LambdaRenamingTestRunner(TestParameters parameters) {
+    this.parameters = parameters;
+  }
 
   @Before
   public void writeAndRunInputJar() throws IOException {
     inputJar = temp.getRoot().toPath().resolve("input.jar");
     ArchiveConsumer buildInput = new ArchiveConsumer(inputJar);
-    for (Class clazz : CLASSES) {
+    for (Class<?> clazz : CLASSES) {
       buildInput.accept(
           ByteDataView.of(ToolHelper.getClassAsBytes(clazz)),
           DescriptorUtils.javaTypeToDescriptor(clazz.getName()),
           null);
     }
     buildInput.finished(null);
-    runInput = ToolHelper.runJava(inputJar, CLASS.getCanonicalName());
-    assertEquals(0, runInput.exitCode);
-  }
-
-  private Path writeProguardRules(boolean aggressive) throws IOException {
-    Path pgConfig = temp.getRoot().toPath().resolve("keep.txt");
-    FileUtils.writeTextFile(
-        pgConfig,
-        "-keep public class " + CLASS.getCanonicalName() + " {",
-        "  public static void main(...);",
-        "}",
-        "-keep interface " + CLASS.getCanonicalName() + "$ReservedNameObjectInterface1 {",
-        "  public java.lang.Object reservedMethod1();",
-        "}",
-        "-keep interface " + CLASS.getCanonicalName() + "$ReservedNameIntegerInterface2 {",
-        "  public java.lang.Integer reservedMethod2();",
-        "}",
-        aggressive ? "-overloadaggressively" : "# Not overloading aggressively");
-    return pgConfig;
   }
 
   @Test
   public void testProguard() throws Exception {
+    assumeTrue(parameters.isCfRuntime());
     buildAndRunProguard("pg.jar", false);
   }
 
   @Test
   public void testProguardAggressive() throws Exception {
+    assumeTrue(parameters.isCfRuntime());
     buildAndRunProguard("pg-aggressive.jar", true);
   }
 
   @Test
-  public void testCf() throws Exception {
-    buildAndRunCf("cf.zip", false);
+  public void testR8() throws Exception {
+    testR8(false);
   }
 
   @Test
-  public void testCfAggressive() throws Exception {
-    buildAndRunCf("cf-aggressive.zip", true);
+  public void testR8Aggressive() throws Exception {
+    testR8(true);
   }
 
-  @Test
-  public void testDex() throws Exception {
-    buildAndRunDex("dex.zip", false);
-  }
-
-  @Test
-  public void testDexAggressive() throws Exception {
-    buildAndRunDex("dex-aggressive.zip", true);
-  }
-
-  private void buildAndRunCf(String outName, boolean aggressive) throws Exception {
-    Path outCf = temp.getRoot().toPath().resolve(outName);
-    build(new ClassFileConsumer.ArchiveConsumer(outCf), aggressive);
-    ProcessResult runCf = ToolHelper.runJava(outCf, CLASS.getCanonicalName());
-    assertEquals(runInput.toString(), runCf.toString());
-  }
-
-  private void buildAndRunDex(String outName, boolean aggressive) throws Exception {
-    Path outDex = temp.getRoot().toPath().resolve(outName);
-    build(new DexIndexedConsumer.ArchiveConsumer(outDex), aggressive);
-    ProcessResult runDex =
-        ToolHelper.runArtNoVerificationErrorsRaw(outDex.toString(), CLASS.getCanonicalName());
-    assertEquals(runInput.stdout, runDex.stdout);
-    assertEquals(runInput.exitCode, runDex.exitCode);
-  }
-
-  private void build(ProgramConsumer consumer, boolean aggressive) throws Exception {
-    Builder builder =
-        ToolHelper.addProguardConfigurationConsumer(
-                R8Command.builder(), configuration -> configuration.setPrintMapping(true))
-            .setMode(CompilationMode.DEBUG)
-            .addLibraryFiles(ToolHelper.getAndroidJar(ToolHelper.getMinApiLevelForDexVm()))
-            .addProgramFiles(inputJar)
-            .setProgramConsumer(consumer)
-            .addProguardConfigurationFiles(writeProguardRules(aggressive));
-    if (!(consumer instanceof ClassFileConsumer)) {
-      builder.setMinApiLevel(ToolHelper.getMinApiLevelForDexVm().getLevel());
-    }
-    ToolHelper.runR8(builder.build());
+  private void testR8(boolean aggressive) throws Exception {
+    testForR8(parameters.getBackend())
+        .addProgramFiles(inputJar)
+        .addKeepMainRule(CLASS)
+        .addKeepRules(
+            "-keep interface " + CLASS.getCanonicalName() + "$ReservedNameObjectInterface1 {",
+            "  public java.lang.Object reservedMethod1();",
+            "}",
+            "-keep interface " + CLASS.getCanonicalName() + "$ReservedNameIntegerInterface2 {",
+            "  public java.lang.Integer reservedMethod2();",
+            "}")
+        .applyIf(aggressive, builder -> builder.addKeepRules("-overloadaggressively"))
+        .debug()
+        .setMinApi(parameters.getApiLevel())
+        .compile()
+        .apply(
+            compileResult ->
+                compileResult.run(parameters.getRuntime(), CLASS).assertSuccessWithOutput(EXPECTED))
+        .applyIf(
+            parameters.isDexRuntime(),
+            compileResult ->
+                compileResult.runDex2Oat(parameters.getRuntime()).assertNoVerificationErrors());
   }
 
   private void buildAndRunProguard(String outName, boolean aggressive) throws Exception {
@@ -144,4 +124,21 @@
     assertNotEquals(-1, runPg.stderr.indexOf("AbstractMethodError"));
     assertNotEquals(0, runPg.exitCode);
   }
+
+  private Path writeProguardRules(boolean aggressive) throws IOException {
+    Path pgConfig = temp.getRoot().toPath().resolve("keep.txt");
+    FileUtils.writeTextFile(
+        pgConfig,
+        "-keep public class " + CLASS.getCanonicalName() + " {",
+        "  public static void main(...);",
+        "}",
+        "-keep interface " + CLASS.getCanonicalName() + "$ReservedNameObjectInterface1 {",
+        "  public java.lang.Object reservedMethod1();",
+        "}",
+        "-keep interface " + CLASS.getCanonicalName() + "$ReservedNameIntegerInterface2 {",
+        "  public java.lang.Integer reservedMethod2();",
+        "}",
+        aggressive ? "-overloadaggressively" : "# Not overloading aggressively");
+    return pgConfig;
+  }
 }
diff --git a/src/test/java/com/android/tools/r8/naming/NamingTestBase.java b/src/test/java/com/android/tools/r8/naming/NamingTestBase.java
index e461666..087e5d2 100644
--- a/src/test/java/com/android/tools/r8/naming/NamingTestBase.java
+++ b/src/test/java/com/android/tools/r8/naming/NamingTestBase.java
@@ -3,6 +3,8 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.naming;
 
+import static com.android.tools.r8.ToolHelper.getMostRecentAndroidJar;
+
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.graph.AppView;
@@ -43,7 +45,10 @@
   protected NamingLens runMinifier(List<Path> configPaths) throws Exception {
     AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-            AndroidApp.builder().addProgramFile(Paths.get(appFileName)).build(),
+            AndroidApp.builder()
+                .addProgramFile(Paths.get(appFileName))
+                .addLibraryFile(getMostRecentAndroidJar())
+                .build(),
             factory -> ToolHelper.loadProguardConfiguration(factory, configPaths));
     dexItemFactory = appView.dexItemFactory();
     ExecutorService executor = Executors.newSingleThreadExecutor();
diff --git a/src/test/java/com/android/tools/r8/naming/b116840216/ReserveOuterClassNameTest.java b/src/test/java/com/android/tools/r8/naming/b116840216/ReserveOuterClassNameTest.java
index a5a165b..a55e7da 100644
--- a/src/test/java/com/android/tools/r8/naming/b116840216/ReserveOuterClassNameTest.java
+++ b/src/test/java/com/android/tools/r8/naming/b116840216/ReserveOuterClassNameTest.java
@@ -50,6 +50,7 @@
 
 @RunWith(Parameterized.class)
 public class ReserveOuterClassNameTest extends TestBase {
+
   private Backend backend;
 
   @Parameters(name = "Backend: {0}")
@@ -68,7 +69,8 @@
         ToolHelper.getClassFileForTestClass(mainClass),
         ToolHelper.getClassFileForTestClass(Outer.class),
         ToolHelper.getClassFileForTestClass(Outer.Inner.class),
-        ToolHelper.getClassFileForTestClass(NeverInline.class));
+        ToolHelper.getClassFileForTestClass(NeverInline.class),
+        ToolHelper.getClassFileForTestClass(NoHorizontalClassMerging.class));
     builder.setProgramConsumer(emptyConsumer(backend));
     builder.addLibraryFiles(runtimeJar(backend));
     builder.addProguardConfiguration(
diff --git a/src/test/java/com/android/tools/r8/naming/b139991218/TestRunner.java b/src/test/java/com/android/tools/r8/naming/b139991218/TestRunner.java
index 665e410..10ce37d 100644
--- a/src/test/java/com/android/tools/r8/naming/b139991218/TestRunner.java
+++ b/src/test/java/com/android/tools/r8/naming/b139991218/TestRunner.java
@@ -4,7 +4,9 @@
 
 package com.android.tools.r8.naming.b139991218;
 
+import static com.android.tools.r8.ToolHelper.getMostRecentKotlinAnnotationJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.CoreMatchers.equalTo;
 import static org.hamcrest.MatcherAssert.assertThat;
 
 import com.android.tools.r8.CompilationFailedException;
@@ -54,7 +56,8 @@
                 ToolHelper.TESTS_BUILD_DIR,
                 "kotlinR8TestResources",
                 "JAVA_8",
-                "lambdas_kstyle_generics" + FileUtils.JAR_EXTENSION))
+                "lambdas_kstyle_generics" + FileUtils.JAR_EXTENSION),
+            getMostRecentKotlinAnnotationJar())
         .addKeepMainRule(Main.class)
         .addKeepAllAttributes()
         .addOptionsModification(
@@ -67,13 +70,15 @@
                       .skipNoClassesOrMembersWithAnnotationsPolicyForTesting =
                   true;
             })
-        .addDontWarnJetBrainsAnnotations()
         .addHorizontallyMergedClassesInspector(
             inspector ->
                 inspector.assertIsCompleteMergeGroup(
                     "com.android.tools.r8.naming.b139991218.Lambda1",
                     "com.android.tools.r8.naming.b139991218.Lambda2"))
+        .allowDiagnosticWarningMessages()
         .setMinApi(parameters.getApiLevel())
+        .compile()
+        .assertAllWarningMessagesMatch(equalTo("Resource 'META-INF/MANIFEST.MF' already exists."))
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLines("11", "12")
         .inspect(
diff --git a/src/test/java/com/android/tools/r8/naming/b173184123/ClassExtendsInterfaceNamingTest.java b/src/test/java/com/android/tools/r8/naming/b173184123/ClassExtendsInterfaceNamingTest.java
index fccc7b2..470b542 100644
--- a/src/test/java/com/android/tools/r8/naming/b173184123/ClassExtendsInterfaceNamingTest.java
+++ b/src/test/java/com/android/tools/r8/naming/b173184123/ClassExtendsInterfaceNamingTest.java
@@ -54,6 +54,7 @@
             parameters.getBackend(),
             parameters.isCfRuntime() ? parameters.getRuntime() : TestRuntime.getCheckedInJdk11())
         .addProgramFiles(classFiles)
+        .addTestingAnnotationsAsProgramClasses()
         .enableAssertions(false)
         .useR8WithRelocatedDeps()
         .setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/naming/b80083341/B80083341.java b/src/test/java/com/android/tools/r8/naming/b80083341/B80083341.java
index e192b8e..3f77e2b 100644
--- a/src/test/java/com/android/tools/r8/naming/b80083341/B80083341.java
+++ b/src/test/java/com/android/tools/r8/naming/b80083341/B80083341.java
@@ -19,7 +19,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-@RunWith(VmTestRunner.class)
 public class B80083341 extends TestBase {
 
   @Test
diff --git a/src/test/java/com/android/tools/r8/proguard/configuration/RepackagingCompatibilityTest.java b/src/test/java/com/android/tools/r8/proguard/configuration/RepackagingCompatibilityTest.java
index b078b2f..c09d730 100644
--- a/src/test/java/com/android/tools/r8/proguard/configuration/RepackagingCompatibilityTest.java
+++ b/src/test/java/com/android/tools/r8/proguard/configuration/RepackagingCompatibilityTest.java
@@ -62,7 +62,7 @@
 
   @Test
   public void testProguard() throws Exception {
-    runTest(testForProguard().addKeepRules("-dontwarn " + getClass().getTypeName()), "Proguard");
+    runTest(testForProguard().addDontWarn(getClass()), "Proguard");
   }
 
   private void runTest(TestShrinkerBuilder<?, ?, ?, ?, ?> builder, String shrinker)
diff --git a/src/test/java/com/android/tools/r8/regress/b111080693/B111080693.java b/src/test/java/com/android/tools/r8/regress/b111080693/B111080693.java
index 46700f1..542e7e5 100644
--- a/src/test/java/com/android/tools/r8/regress/b111080693/B111080693.java
+++ b/src/test/java/com/android/tools/r8/regress/b111080693/B111080693.java
@@ -23,7 +23,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-@RunWith(VmTestRunner.class)
 public class B111080693 extends TestBase {
   @Test
   public void test() throws Exception {
diff --git a/src/test/java/com/android/tools/r8/regress/b72485384/Regress72485384Test.java b/src/test/java/com/android/tools/r8/regress/b72485384/Regress72485384Test.java
index 57e7343..2a7889d 100644
--- a/src/test/java/com/android/tools/r8/regress/b72485384/Regress72485384Test.java
+++ b/src/test/java/com/android/tools/r8/regress/b72485384/Regress72485384Test.java
@@ -3,68 +3,64 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.regress.b72485384;
 
-import static org.hamcrest.CoreMatchers.containsString;
-import static org.hamcrest.MatcherAssert.assertThat;
 
 import com.android.tools.r8.TestBase;
-import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.regress.b72485384.GenericOuter.GenericInner;
-import com.android.tools.r8.utils.AndroidApp;
-import com.google.common.collect.ImmutableList;
-import java.util.Arrays;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
-import org.junit.Rule;
 import org.junit.Test;
-import org.junit.rules.ExpectedException;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
 import org.junit.runners.Parameterized.Parameters;
 
 @RunWith(Parameterized.class)
 public class Regress72485384Test extends TestBase {
-  @Rule public ExpectedException thrown = ExpectedException.none();
 
-  @Parameters(name = "{0}")
+  @Parameters(name = "{1}, allowUnusedProguardConfigurationRules: {0}")
   public static Collection<Object[]> getParameters() {
     String baseConfig =
         keepMainProguardConfiguration(Main.class)
             + "-keepattributes Signature,InnerClasses,EnclosingMethod ";
-    return Arrays.asList(
-        new Object[][] {
-          {baseConfig, null},
-          {baseConfig + "-dontshrink", null},
-          {baseConfig + "-dontshrink -dontobfuscate", null},
-          {baseConfig + "-dontobfuscate", null},
-          {"-keep class DoesNotExist -dontshrink", "ClassNotFoundException"}
-        });
+    TestParametersCollection parametersCollection =
+        getTestParameters()
+            .withDexRuntimes()
+            .withApiLevelsStartingAtIncluding(AndroidApiLevel.N)
+            .build();
+    List<Object[]> tests = new ArrayList<>();
+    for (TestParameters parameters : parametersCollection) {
+      Collections.addAll(
+          tests,
+          new Object[][] {
+            {parameters, baseConfig},
+            {parameters, baseConfig + "-dontshrink"},
+            {parameters, baseConfig + "-dontshrink -dontobfuscate"},
+            {parameters, baseConfig + "-dontobfuscate"}
+          });
+    }
+    return tests;
   }
 
-  private static final List<Class<?>> CLASSES =
-      ImmutableList.of(GenericOuter.class, GenericInner.class, Main.class);
-
+  private final TestParameters parameters;
   private final String proguardConfig;
-  private final String expectedErrorMessage;
 
-  public Regress72485384Test(String proguardConfig, String expectedErrorMessage) {
+  public Regress72485384Test(TestParameters parameters, String proguardConfig) {
+    this.parameters = parameters;
     this.proguardConfig = proguardConfig;
-    this.expectedErrorMessage = expectedErrorMessage;
   }
 
   @Test
   public void testSignatureRewrite() throws Exception {
-    AndroidApp app = compileWithR8(CLASSES, proguardConfig);
-
-    if (expectedErrorMessage == null) {
-      if (ToolHelper.getDexVm().getVersion().isOlderThanOrEqual(ToolHelper.DexVm.Version.V6_0_1)) {
-        // Resolution of java.util.function.Function fails.
-        thrown.expect(AssertionError.class);
-      }
-
-      runOnArt(app, Main.class.getCanonicalName());
-    } else {
-      ToolHelper.ProcessResult result = runOnArtRaw(app, Main.class.getCanonicalName());
-      assertThat(result.stderr, containsString(expectedErrorMessage));
-    }
+    testForR8(parameters.getBackend())
+        .addProgramClasses(GenericOuter.class, GenericInner.class, Main.class)
+        .addKeepRules(proguardConfig)
+        .setMinApi(parameters.getApiLevel())
+        .compile()
+        .run(parameters.getRuntime(), Main.class)
+        .assertSuccessWithOutputLines("Hello World!", "Hello World!");
   }
 }
diff --git a/src/test/java/com/android/tools/r8/regress/b77496850/B77496850.java b/src/test/java/com/android/tools/r8/regress/b77496850/B77496850.java
index 84e470e..f3ab264 100644
--- a/src/test/java/com/android/tools/r8/regress/b77496850/B77496850.java
+++ b/src/test/java/com/android/tools/r8/regress/b77496850/B77496850.java
@@ -406,7 +406,7 @@
 
     public static void main(String[] args) {
       for (int i = 0; i < 100; i++) {
-        System.out.println(new Reproduction().test());
+        System.out.println(new ReproductionWithExceptionHandler().test());
       }
     }
   }
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageFeatureWithSyntheticsTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageFeatureWithSyntheticsTest.java
new file mode 100644
index 0000000..a203729
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/repackage/RepackageFeatureWithSyntheticsTest.java
@@ -0,0 +1,147 @@
+// Copyright (c) 2021, 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.repackage;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.R8TestCompileResult;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class RepackageFeatureWithSyntheticsTest extends RepackageTestBase {
+
+  public RepackageFeatureWithSyntheticsTest(
+      String flattenPackageHierarchyOrRepackageClasses, TestParameters parameters) {
+    super(flattenPackageHierarchyOrRepackageClasses, parameters);
+  }
+
+  private static final Class<?> FIRST_FOO =
+      com.android.tools.r8.repackage.testclasses.repackagefeaturewithsynthetics.first.Foo.class;
+
+  private static final Class<?> FIRST_PKG_PRIVATE =
+      com.android.tools.r8.repackage.testclasses.repackagefeaturewithsynthetics.first
+          .PkgProtectedMethod.class;
+
+  private static final List<Class<?>> FIRST_CLASSES =
+      ImmutableList.of(FIRST_FOO, FIRST_PKG_PRIVATE);
+
+  private static final List<Class<?>> FIRST_FIRST_CLASSES =
+      ImmutableList.of(
+          com.android.tools.r8.repackage.testclasses.repackagefeaturewithsynthetics.first.first.Foo
+              .class,
+          com.android.tools.r8.repackage.testclasses.repackagefeaturewithsynthetics.first.first
+              .PkgProtectedMethod.class);
+
+  private static List<Class<?>> getTestClasses() {
+    return ImmutableList.<Class<?>>builder()
+        .addAll(getBaseClasses())
+        .add(TestClass.class)
+        .add(I.class)
+        .build();
+  }
+
+  private static List<Class<?>> getBaseClasses() {
+    return FIRST_CLASSES;
+  }
+
+  private static List<Class<?>> getFeatureClasses() {
+    return FIRST_FIRST_CLASSES;
+  }
+
+  private static String EXPECTED = StringUtils.lines("first.Foo", "first.first.Foo");
+
+  @Override
+  public String getRepackagePackage() {
+    return "dest";
+  }
+
+  @Test
+  public void testReference() throws Exception {
+    testForRuntime(parameters)
+        .addProgramClasses(getTestClasses())
+        .addProgramClasses(getFeatureClasses())
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutput(EXPECTED);
+  }
+
+  @Test
+  public void test() throws Exception {
+    assumeTrue("Feature splits require DEX output.", parameters.isDexRuntime());
+    R8TestCompileResult compileResult =
+        testForR8(parameters.getBackend())
+            .addProgramClasses(getTestClasses())
+            .addFeatureSplit(getFeatureClasses().toArray(new Class<?>[0]))
+            .addKeepMainRule(TestClass.class)
+            .addKeepClassAndMembersRules(
+                com.android.tools.r8.repackage.testclasses.repackagefeaturewithsynthetics.first
+                    .PkgProtectedMethod.class,
+                com.android.tools.r8.repackage.testclasses.repackagefeaturewithsynthetics.first
+                    .first.PkgProtectedMethod.class)
+            .addKeepClassAndMembersRules(I.class)
+            .addKeepMethodRules(
+                Reference.methodFromMethod(TestClass.class.getDeclaredMethod("run", I.class)))
+            .addKeepAttributeInnerClassesAndEnclosingMethod()
+            .noMinification()
+            .apply(this::configureRepackaging)
+            .enableNeverClassInliningAnnotations()
+            .setMinApi(parameters.getApiLevel())
+            .compile();
+
+    // Each Foo class will give rise to a single lambda.
+    int expectedSyntheticsInBase = 1;
+    int expectedSyntheticsInFeature = 1;
+
+    // Check that the first.Foo is repackaged but that the pkg private access class is not.
+    // The implies that the lambda which is doing a package private access cannot be repackaged.
+    // If it is, the access will fail resulting in a runtime exception.
+    CodeInspector baseInspector = compileResult.inspector();
+    assertThat(FIRST_FOO, isRepackagedAsExpected(baseInspector, "first"));
+    assertThat(FIRST_PKG_PRIVATE, isNotRepackaged(baseInspector));
+    assertEquals(
+        getTestClasses().size() + expectedSyntheticsInBase, baseInspector.allClasses().size());
+
+    // The feature first.first.Foo is not repackaged and neither is the lambda.
+    // TODO(b/180086194): first.first.Foo should have been repackaged, but is currently identified
+    //   as being in 'base' when inlining takes place.
+    CodeInspector featureInspector = new CodeInspector(compileResult.getFeature(0));
+    getFeatureClasses().forEach(c -> assertThat(c, isNotRepackaged(featureInspector)));
+    assertEquals(
+        getFeatureClasses().size() + expectedSyntheticsInFeature,
+        featureInspector.allClasses().size());
+
+    compileResult
+        .addFeatureSplitsToRunClasspathFiles()
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutputLines("first.Foo", "first.first.Foo");
+  }
+
+  public interface I {
+    void run();
+  }
+
+  public static class TestClass {
+
+    // Public kept run method to accept a lambda ensuring desugaring which cannot be optimized out.
+    public static void run(I i) {
+      i.run();
+    }
+
+    public static void main(String[] args) {
+      new com.android.tools.r8.repackage.testclasses.repackagefeaturewithsynthetics.first.Foo();
+      new com.android.tools.r8.repackage.testclasses.repackagefeaturewithsynthetics.first.first
+          .Foo();
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagefeaturewithsynthetics/first/Foo.java b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagefeaturewithsynthetics/first/Foo.java
new file mode 100644
index 0000000..e7b1cf9
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagefeaturewithsynthetics/first/Foo.java
@@ -0,0 +1,16 @@
+// Copyright (c) 2021, 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.repackage.testclasses.repackagefeaturewithsynthetics.first;
+
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.repackage.RepackageFeatureWithSyntheticsTest.TestClass;
+
+@NeverClassInline
+public class Foo {
+
+  public Foo() {
+    TestClass.run(() -> PkgProtectedMethod.getStream().println("first.Foo"));
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagefeaturewithsynthetics/first/PkgProtectedMethod.java b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagefeaturewithsynthetics/first/PkgProtectedMethod.java
new file mode 100644
index 0000000..10ddc99
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagefeaturewithsynthetics/first/PkgProtectedMethod.java
@@ -0,0 +1,14 @@
+// Copyright (c) 2021, 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.repackage.testclasses.repackagefeaturewithsynthetics.first;
+
+import java.io.PrintStream;
+
+public class PkgProtectedMethod {
+
+  /* package protected */
+  static PrintStream getStream() {
+    return System.out;
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagefeaturewithsynthetics/first/first/Foo.java b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagefeaturewithsynthetics/first/first/Foo.java
new file mode 100644
index 0000000..dcee445
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagefeaturewithsynthetics/first/first/Foo.java
@@ -0,0 +1,16 @@
+// Copyright (c) 2021, 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.repackage.testclasses.repackagefeaturewithsynthetics.first.first;
+
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.repackage.RepackageFeatureWithSyntheticsTest.TestClass;
+
+@NeverClassInline
+public class Foo {
+
+  public Foo() {
+    TestClass.run(() -> PkgProtectedMethod.getStream().println("first.first.Foo"));
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagefeaturewithsynthetics/first/first/PkgProtectedMethod.java b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagefeaturewithsynthetics/first/first/PkgProtectedMethod.java
new file mode 100644
index 0000000..0473a26
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagefeaturewithsynthetics/first/first/PkgProtectedMethod.java
@@ -0,0 +1,14 @@
+// Copyright (c) 2021, 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.repackage.testclasses.repackagefeaturewithsynthetics.first.first;
+
+import java.io.PrintStream;
+
+public class PkgProtectedMethod {
+
+  /* package protected */
+  static PrintStream getStream() {
+    return System.out;
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/resolution/InvokeSuperCallInStaticTest.java b/src/test/java/com/android/tools/r8/resolution/InvokeSuperCallInStaticTest.java
index 74f834d..f1ea8f0 100644
--- a/src/test/java/com/android/tools/r8/resolution/InvokeSuperCallInStaticTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/InvokeSuperCallInStaticTest.java
@@ -54,6 +54,7 @@
         computeAppViewWithLiveness(
             buildClasses(Base.class, Main.class)
                 .addClassProgramData(getAWithRewrittenInvokeSpecialToBase())
+                .addLibraryFile(parameters.getDefaultRuntimeLibrary())
                 .build(),
             Main.class);
     AppInfoWithLiveness appInfo = appView.appInfo();
diff --git a/src/test/java/com/android/tools/r8/resolution/SingleTargetLookupTest.java b/src/test/java/com/android/tools/r8/resolution/SingleTargetLookupTest.java
index a702874..2b560e2 100644
--- a/src/test/java/com/android/tools/r8/resolution/SingleTargetLookupTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/SingleTargetLookupTest.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.resolution;
 
+import static com.android.tools.r8.ToolHelper.getMostRecentAndroidJar;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
@@ -87,7 +88,13 @@
 
   @BeforeClass
   public static void computeAppInfo() throws Exception {
-    appView = computeAppViewWithLiveness(readClassesAndAsmDump(CLASSES, ASM_CLASSES), Main.class);
+    appView =
+        computeAppViewWithLiveness(
+            buildClassesWithTestingAnnotations(CLASSES)
+                .addClassProgramData(ASM_CLASSES)
+                .addLibraryFile(getMostRecentAndroidJar())
+                .build(),
+            Main.class);
     appInfo = appView.appInfo();
   }
 
diff --git a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodTest.java b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodTest.java
index c0996fe..75d4bbc 100644
--- a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodTest.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.resolution;
 
+import static com.android.tools.r8.ToolHelper.getMostRecentAndroidJar;
 import static org.hamcrest.CoreMatchers.containsString;
 import static org.junit.Assert.assertTrue;
 
@@ -57,7 +58,10 @@
 
   @BeforeClass
   public static void computeAppInfo() throws Exception {
-    appInfo = computeAppViewWithLiveness(readClasses(CLASSES), Main.class).appInfo();
+    appInfo =
+        computeAppViewWithLiveness(
+                buildClasses(CLASSES).addLibraryFile(getMostRecentAndroidJar()).build(), Main.class)
+            .appInfo();
   }
 
   private static DexMethod buildMethod(Class clazz, String name) {
diff --git a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodWithVirtualParentTest.java b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodWithVirtualParentTest.java
index 1d6dc16..6be194c 100644
--- a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodWithVirtualParentTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfPrivateStaticMethodWithVirtualParentTest.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.resolution;
 
+import static com.android.tools.r8.ToolHelper.getMostRecentAndroidJar;
 import static org.hamcrest.CoreMatchers.containsString;
 import static org.junit.Assert.assertTrue;
 
@@ -78,7 +79,11 @@
   public static void computeAppInfo() throws Exception {
     appInfo =
         computeAppViewWithLiveness(
-                buildClasses(CLASSES).addClassProgramData(getDumps()).build(), Main.class)
+                buildClasses(CLASSES)
+                    .addClassProgramData(getDumps())
+                    .addLibraryFile(getMostRecentAndroidJar())
+                    .build(),
+                Main.class)
             .appInfo();
   }
 
diff --git a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentInterfaceTest.java b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentInterfaceTest.java
index 5b08461..c92f813 100644
--- a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentInterfaceTest.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.resolution;
 
+import static com.android.tools.r8.ToolHelper.getMostRecentAndroidJar;
 import static org.hamcrest.CoreMatchers.containsString;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -90,14 +91,20 @@
 
   public static List<Class<?>> CLASSES = ImmutableList.of(A.class, C.class, Main.class);
 
-  public static List<byte[]> DUMPS = ImmutableList.of(BDump.dump());
+  public static byte[] DUMP = BDump.dump();
 
   private static AppInfoWithLiveness appInfo;
 
   @BeforeClass
   public static void computeAppInfo() throws Exception {
     appInfo =
-        computeAppViewWithLiveness(readClassesAndAsmDump(CLASSES, DUMPS), Main.class).appInfo();
+        computeAppViewWithLiveness(
+                buildClasses(CLASSES)
+                    .addClassProgramData(DUMP)
+                    .addLibraryFile(getMostRecentAndroidJar())
+                    .build(),
+                Main.class)
+            .appInfo();
   }
 
   private static DexMethod buildMethod(Class clazz, String name) {
@@ -148,13 +155,13 @@
       runResult =
           testForJvm()
               .addProgramClasses(CLASSES)
-              .addProgramClassFileData(DUMPS)
+              .addProgramClassFileData(DUMP)
               .run(parameters.getRuntime(), Main.class);
     } else {
       runResult =
           testForD8()
               .addProgramClasses(CLASSES)
-              .addProgramClassFileData(DUMPS)
+              .addProgramClassFileData(DUMP)
               .setMinApi(parameters.getApiLevel())
               .run(parameters.getRuntime(), Main.class);
     }
@@ -175,7 +182,7 @@
     R8TestRunResult runResult =
         testForR8(parameters.getBackend())
             .addProgramClasses(CLASSES)
-            .addProgramClassFileData(DUMPS)
+            .addProgramClassFileData(DUMP)
             .addKeepMainRule(Main.class)
             .setMinApi(parameters.getApiLevel())
             .addOptionsModification(o -> o.enableVerticalClassMerging = enableVerticalClassMerging)
diff --git a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentTest.java b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentTest.java
index fe66478..2ffd43d 100644
--- a/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/VirtualOverrideOfStaticMethodWithVirtualParentTest.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.resolution;
 
+import static com.android.tools.r8.ToolHelper.getMostRecentAndroidJar;
 import static org.hamcrest.CoreMatchers.containsString;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -143,7 +144,13 @@
   @BeforeClass
   public static void computeAppInfo() throws Exception {
     appInfo =
-        computeAppViewWithLiveness(readClassesAndAsmDump(CLASSES, DUMPS), Main.class).appInfo();
+        computeAppViewWithLiveness(
+                buildClasses(CLASSES)
+                    .addClassProgramData(DUMPS)
+                    .addLibraryFile(getMostRecentAndroidJar())
+                    .build(),
+                Main.class)
+            .appInfo();
   }
 
   private static DexMethod buildMethod(Class clazz, String name) {
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodPublicAccessWithIntermediateTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodPublicAccessWithIntermediateTest.java
index 7d30885..ada12fe 100644
--- a/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodPublicAccessWithIntermediateTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/access/NestInvokeSpecialMethodPublicAccessWithIntermediateTest.java
@@ -137,7 +137,10 @@
 
   private AppView<AppInfoWithLiveness> getAppView() throws Exception {
     return computeAppViewWithLiveness(
-        buildClasses(getClasses()).addClassProgramData(getTransformedClasses()).build(),
+        buildClasses(getClasses())
+            .addClassProgramData(getTransformedClasses())
+            .addLibraryFile(parameters.getDefaultRuntimeLibrary())
+            .build(),
         Main.class);
   }
 
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestStaticMethodAccessTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestStaticMethodAccessTest.java
index 2000456..9785c92 100644
--- a/src/test/java/com/android/tools/r8/resolution/access/NestStaticMethodAccessTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/access/NestStaticMethodAccessTest.java
@@ -64,7 +64,10 @@
   public void testResolutionAccess() throws Exception {
     AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-            buildClasses(getClasses()).addClassProgramData(getTransformedClasses()).build(),
+            buildClasses(getClasses())
+                .addClassProgramData(getTransformedClasses())
+                .addLibraryFile(parameters.getDefaultRuntimeLibrary())
+                .build(),
             Main.class);
     AppInfoWithLiveness appInfo = appView.appInfo();
     DexProgramClass bClass =
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestStaticMethodAccessWithIntermediateClassTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestStaticMethodAccessWithIntermediateClassTest.java
index 9ceaddc..1df6b63 100644
--- a/src/test/java/com/android/tools/r8/resolution/access/NestStaticMethodAccessWithIntermediateClassTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/access/NestStaticMethodAccessWithIntermediateClassTest.java
@@ -63,7 +63,10 @@
   public void testResolutionAccess() throws Exception {
     AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-            buildClasses(getClasses()).addClassProgramData(getTransformedClasses()).build(),
+            buildClasses(getClasses())
+                .addClassProgramData(getTransformedClasses())
+                .addLibraryFile(parameters.getDefaultRuntimeLibrary())
+                .build(),
             Main.class);
     AppInfoWithLiveness appInfo = appView.appInfo();
     DexProgramClass bClass =
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestVirtualMethodAccessTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestVirtualMethodAccessTest.java
index e172db4..7ab3821 100644
--- a/src/test/java/com/android/tools/r8/resolution/access/NestVirtualMethodAccessTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/access/NestVirtualMethodAccessTest.java
@@ -67,7 +67,10 @@
   public void testResolutionAccess() throws Exception {
     AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-            buildClasses(getClasses()).addClassProgramData(getTransformedClasses()).build(),
+            buildClassesWithTestingAnnotations(getClasses())
+                .addClassProgramData(getTransformedClasses())
+                .addLibraryFile(parameters.getDefaultRuntimeLibrary())
+                .build(),
             Main.class);
     AppInfoWithLiveness appInfo = appView.appInfo();
     DexProgramClass bClass =
diff --git a/src/test/java/com/android/tools/r8/resolution/access/NestVirtualMethodAccessWithIntermediateClassTest.java b/src/test/java/com/android/tools/r8/resolution/access/NestVirtualMethodAccessWithIntermediateClassTest.java
index da00722..2c0dbca 100644
--- a/src/test/java/com/android/tools/r8/resolution/access/NestVirtualMethodAccessWithIntermediateClassTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/access/NestVirtualMethodAccessWithIntermediateClassTest.java
@@ -62,7 +62,10 @@
   public void testResolutionAccess() throws Exception {
     AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-            buildClasses(getClasses()).addClassProgramData(getTransformedClasses()).build(),
+            buildClasses(getClasses())
+                .addClassProgramData(getTransformedClasses())
+                .addLibraryFile(parameters.getDefaultRuntimeLibrary())
+                .build(),
             Main.class);
     AppInfoWithLiveness appInfo = appView.appInfo();
     DexProgramClass bClass =
diff --git a/src/test/java/com/android/tools/r8/resolution/access/SelfVirtualMethodAccessTest.java b/src/test/java/com/android/tools/r8/resolution/access/SelfVirtualMethodAccessTest.java
index f2d4c5c..cd2679e 100644
--- a/src/test/java/com/android/tools/r8/resolution/access/SelfVirtualMethodAccessTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/access/SelfVirtualMethodAccessTest.java
@@ -50,7 +50,10 @@
   public void testResolutionAccess() throws Exception {
     AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-            buildClasses(getClasses()).addClassProgramData(getTransformedClasses()).build(),
+            buildClasses(getClasses())
+                .addClassProgramData(getTransformedClasses())
+                .addLibraryFile(parameters.getDefaultRuntimeLibrary())
+                .build(),
             Main.class);
     AppInfoWithLiveness appInfo = appView.appInfo();
     DexProgramClass aClass =
diff --git a/src/test/java/com/android/tools/r8/resolution/access/indirectfield/IndirectFieldAccessTest.java b/src/test/java/com/android/tools/r8/resolution/access/indirectfield/IndirectFieldAccessTest.java
index 4d0f445..ea51b57 100644
--- a/src/test/java/com/android/tools/r8/resolution/access/indirectfield/IndirectFieldAccessTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/access/indirectfield/IndirectFieldAccessTest.java
@@ -49,7 +49,11 @@
   @Test
   public void testResolutionAccess() throws Exception {
     AppView<AppInfoWithLiveness> appView =
-        computeAppViewWithLiveness(readClasses(getClasses()), Main.class);
+        computeAppViewWithLiveness(
+            buildClasses(getClasses())
+                .addLibraryFile(parameters.getDefaultRuntimeLibrary())
+                .build(),
+            Main.class);
     AppInfoWithLiveness appInfo = appView.appInfo();
     DexProgramClass cClass =
         appInfo.definitionFor(buildType(C.class, appInfo.dexItemFactory())).asProgramClass();
diff --git a/src/test/java/com/android/tools/r8/resolution/access/indirectmethod/IndirectMethodAccessTest.java b/src/test/java/com/android/tools/r8/resolution/access/indirectmethod/IndirectMethodAccessTest.java
index 6e51158..008a478 100644
--- a/src/test/java/com/android/tools/r8/resolution/access/indirectmethod/IndirectMethodAccessTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/access/indirectmethod/IndirectMethodAccessTest.java
@@ -56,7 +56,11 @@
   public void testResolutionAccess() throws Exception {
     AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-            buildClasses(getClasses()).addClassProgramData(getTransforms()).build(), Main.class);
+            buildClasses(getClasses())
+                .addClassProgramData(getTransforms())
+                .addLibraryFile(parameters.getDefaultRuntimeLibrary())
+                .build(),
+            Main.class);
     AppInfoWithLiveness appInfo = appView.appInfo();
     DexProgramClass cClass =
         appInfo.definitionFor(buildType(C.class, appInfo.dexItemFactory())).asProgramClass();
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/AbstractAllTest.java b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/AbstractAllTest.java
index 44f969f..6c6d9fe 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/AbstractAllTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/AbstractAllTest.java
@@ -35,13 +35,14 @@
   }
 
   private static final List<Class<?>> CLASSES =
-      ImmutableList.of(T.class, L.class, R.class, B.class, Main.class);
+      ImmutableList.of(T.class, L.class, R.class, B.class, C.class, Main.class);
 
   @Test
   public void testResolution() throws Exception {
     // The resolution is runtime independent, so just run it on the default CF VM.
     assumeTrue(parameters.useRuntimeAsNoneRuntime());
-    AndroidApp app = readClasses(CLASSES);
+    AndroidApp app =
+        buildClasses(CLASSES).addLibraryFile(parameters.getDefaultRuntimeLibrary()).build();
     AppInfoWithLiveness appInfo = computeAppViewWithLiveness(app, Main.class).appInfo();
     DexMethod method = buildNullaryVoidMethod(B.class, "f", appInfo.dexItemFactory());
     ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method);
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultLeftAbstractRightTest.java b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultLeftAbstractRightTest.java
index 990d146..273fb50 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultLeftAbstractRightTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultLeftAbstractRightTest.java
@@ -45,6 +45,7 @@
         computeAppViewWithLiveness(
                 buildClasses(CLASSES)
                     .addClassProgramData(Collections.singletonList(transformB()))
+                    .addLibraryFile(parameters.getDefaultRuntimeLibrary())
                     .build(),
                 Main.class)
             .appInfo();
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultRightAbstractLeftTest.java b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultRightAbstractLeftTest.java
index 32d88b3..9897acd 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultRightAbstractLeftTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultRightAbstractLeftTest.java
@@ -45,6 +45,7 @@
         computeAppViewWithLiveness(
                 buildClasses(CLASSES)
                     .addClassProgramData(Collections.singletonList(transformB()))
+                    .addLibraryFile(parameters.getDefaultRuntimeLibrary())
                     .build(),
                 Main.class)
             .appInfo();
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAbstractLeftTest.java b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAbstractLeftTest.java
index 91b71ce..baa7747 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAbstractLeftTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAbstractLeftTest.java
@@ -48,6 +48,7 @@
         computeAppViewWithLiveness(
                 buildClasses(CLASSES)
                     .addClassProgramData(Collections.singletonList(transformB()))
+                    .addLibraryFile(parameters.getDefaultRuntimeLibrary())
                     .build(),
                 Main.class)
             .appInfo();
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAbstractRightTest.java b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAbstractRightTest.java
index 61f9725..904640e 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAbstractRightTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAbstractRightTest.java
@@ -48,6 +48,7 @@
         computeAppViewWithLiveness(
                 buildClasses(CLASSES)
                     .addClassProgramData(Collections.singletonList(transformB()))
+                    .addLibraryFile(parameters.getDefaultRuntimeLibrary())
                     .build(),
                 Main.class)
             .appInfo();
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAndBothTest.java b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAndBothTest.java
index 5c8f813..6406ea0 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAndBothTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAndBothTest.java
@@ -47,6 +47,7 @@
         computeAppViewWithLiveness(
                 buildClasses(CLASSES)
                     .addClassProgramData(Collections.singletonList(transformB()))
+                    .addLibraryFile(parameters.getDefaultRuntimeLibrary())
                     .build(),
                 Main.class)
             .appInfo();
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAndLeftTest.java b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAndLeftTest.java
index 74fb903..de6da74 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAndLeftTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAndLeftTest.java
@@ -41,7 +41,10 @@
     // The resolution is runtime independent, so just run it on the default CF VM.
     assumeTrue(parameters.useRuntimeAsNoneRuntime());
     AppInfoWithLiveness appInfo =
-        computeAppViewWithLiveness(readClasses(CLASSES), Main.class).appInfo();
+        computeAppViewWithLiveness(
+                buildClasses(CLASSES).addLibraryFile(parameters.getDefaultRuntimeLibrary()).build(),
+                Main.class)
+            .appInfo();
     DexMethod method = buildNullaryVoidMethod(B.class, "f", appInfo.dexItemFactory());
     ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method);
     DexEncodedMethod resolutionTarget = resolutionResult.getSingleTarget();
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAndRightTest.java b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAndRightTest.java
index 13f9340..7325cc1 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAndRightTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/DefaultTopAndRightTest.java
@@ -41,7 +41,10 @@
     // The resolution is runtime independent, so just run it on the default CF VM.
     assumeTrue(parameters.useRuntimeAsNoneRuntime());
     AppInfoWithLiveness appInfo =
-        computeAppViewWithLiveness(readClasses(CLASSES), Main.class).appInfo();
+        computeAppViewWithLiveness(
+                buildClasses(CLASSES).addLibraryFile(parameters.getDefaultRuntimeLibrary()).build(),
+                Main.class)
+            .appInfo();
     DexMethod method = buildNullaryVoidMethod(B.class, "f", appInfo.dexItemFactory());
     ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method);
     DexEncodedMethod resolutionTarget = resolutionResult.getSingleTarget();
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/TwoDefaultMethodsWithoutTopTest.java b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/TwoDefaultMethodsWithoutTopTest.java
index 8bc64cf..296f95f 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacediamonds/TwoDefaultMethodsWithoutTopTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacediamonds/TwoDefaultMethodsWithoutTopTest.java
@@ -48,6 +48,7 @@
         computeAppViewWithLiveness(
                 buildClasses(CLASSES)
                     .addClassProgramData(Collections.singletonList(transformB()))
+                    .addLibraryFile(parameters.getDefaultRuntimeLibrary())
                     .build(),
                 Main.class)
             .appInfo();
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultMethodAsOverrideWithLambdaTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultMethodAsOverrideWithLambdaTest.java
index 8f800f6..fbece8f 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultMethodAsOverrideWithLambdaTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultMethodAsOverrideWithLambdaTest.java
@@ -54,7 +54,10 @@
     assumeTrue(parameters.useRuntimeAsNoneRuntime());
     AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-            buildClasses(I.class, J.class, A.class, Main.class).build(), Main.class);
+            buildClassesWithTestingAnnotations(I.class, J.class, A.class, Main.class)
+                .addLibraryFile(parameters.getDefaultRuntimeLibrary())
+                .build(),
+            Main.class);
     AppInfoWithLiveness appInfo = appView.appInfo();
     DexMethod method = buildNullaryVoidMethod(I.class, "bar", appInfo.dexItemFactory());
     ResolutionResult resolutionResult = appInfo.resolveMethodOnInterface(method.holder, method);
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultMethodLambdaTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultMethodLambdaTest.java
index 169c255..8d0eb98 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultMethodLambdaTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultMethodLambdaTest.java
@@ -52,7 +52,11 @@
   public void testResolution() throws Exception {
     assumeTrue(parameters.useRuntimeAsNoneRuntime());
     AppView<AppInfoWithLiveness> appView =
-        computeAppViewWithLiveness(buildClasses(I.class, A.class, Main.class).build(), Main.class);
+        computeAppViewWithLiveness(
+            buildClassesWithTestingAnnotations(I.class, A.class, Main.class)
+                .addLibraryFile(parameters.getDefaultRuntimeLibrary())
+                .build(),
+            Main.class);
     AppInfoWithLiveness appInfo = appView.appInfo();
     DexMethod method = buildNullaryVoidMethod(I.class, "bar", appInfo.dexItemFactory());
     ResolutionResult resolutionResult = appInfo.resolveMethodOnInterface(method.holder, method);
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultWithoutTopTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultWithoutTopTest.java
index 16c1401..e7532b1 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultWithoutTopTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultWithoutTopTest.java
@@ -53,8 +53,9 @@
     assumeTrue(parameters.useRuntimeAsNoneRuntime());
     AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-            buildClasses(I.class, J.class, Main.class)
+            buildClassesWithTestingAnnotations(I.class, J.class, Main.class)
                 .addClassProgramData(setAImplementsIAndJ())
+                .addLibraryFile(parameters.getDefaultRuntimeLibrary())
                 .build(),
             Main.class);
     AppInfoWithLiveness appInfo = appView.appInfo();
@@ -99,8 +100,9 @@
     assumeTrue(parameters.useRuntimeAsNoneRuntime());
     AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-            buildClasses(I.class, J.class, K.class, Main.class)
+            buildClassesWithTestingAnnotations(I.class, J.class, K.class, Main.class)
                 .addClassProgramData(setAimplementsIandK())
+                .addLibraryFile(parameters.getDefaultRuntimeLibrary())
                 .build(),
             Main.class);
     AppInfoWithLiveness appInfo = appView.appInfo();
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/DuplicateImportsTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/DuplicateImportsTest.java
index 8b1f615..63d9316 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/DuplicateImportsTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/DuplicateImportsTest.java
@@ -54,7 +54,10 @@
     assumeTrue(parameters.useRuntimeAsNoneRuntime());
     AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-            buildClasses(I.class, J.class, A.class, Main.class).build(), Main.class);
+            buildClassesWithTestingAnnotations(I.class, J.class, A.class, Main.class)
+                .addLibraryFile(parameters.getDefaultRuntimeLibrary())
+                .build(),
+            Main.class);
     AppInfoWithLiveness appInfo = appView.appInfo();
     DexMethod method = buildNullaryVoidMethod(I.class, "foo", appInfo.dexItemFactory());
     ResolutionResult resolutionResult = appInfo.resolveMethodOnInterface(method);
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/InvokeInterfaceClInitTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/InvokeInterfaceClInitTest.java
index 3d20751..b15d446 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/InvokeInterfaceClInitTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/InvokeInterfaceClInitTest.java
@@ -52,6 +52,7 @@
         computeAppViewWithLiveness(
             buildClasses(A.class, B.class)
                 .addClassProgramData(transformI(), transformMain())
+                .addLibraryFile(parameters.getDefaultRuntimeLibrary())
                 .build(),
             Main.class);
     AppInfoWithLiveness appInfo = appView.appInfo();
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/InvokeInterfaceWithStaticTargetTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/InvokeInterfaceWithStaticTargetTest.java
index b4009fb..0ec1ce8 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/InvokeInterfaceWithStaticTargetTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/InvokeInterfaceWithStaticTargetTest.java
@@ -46,7 +46,10 @@
     assumeTrue(parameters.getRuntime().equals(TestRuntime.getDefaultJavaRuntime()));
     AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-            buildClasses(A.class, I.class).addClassProgramData(transformMain()).build(),
+            buildClasses(A.class, I.class)
+                .addClassProgramData(transformMain())
+                .addLibraryFile(parameters.getDefaultRuntimeLibrary())
+                .build(),
             Main.class);
     AppInfoWithLiveness appInfo = appView.appInfo();
     DexMethod method = buildNullaryVoidMethod(I.class, "bar", appInfo.dexItemFactory());
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/LambdaMultipleInterfacesTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/LambdaMultipleInterfacesTest.java
index 958e785..5f35faa 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/LambdaMultipleInterfacesTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/LambdaMultipleInterfacesTest.java
@@ -53,7 +53,10 @@
     assumeTrue(parameters.useRuntimeAsNoneRuntime());
     AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-            buildClasses(I.class, J.class, A.class, Main.class).build(), Main.class);
+            buildClassesWithTestingAnnotations(I.class, J.class, A.class, Main.class)
+                .addLibraryFile(parameters.getDefaultRuntimeLibrary())
+                .build(),
+            Main.class);
     AppInfoWithLiveness appInfo = appView.appInfo();
     DexMethod method = buildNullaryVoidMethod(J.class, "bar", appInfo.dexItemFactory());
     ResolutionResult resolutionResult = appInfo.resolveMethodOnInterface(method.holder, method);
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/MultipleImplementsTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/MultipleImplementsTest.java
index eb88c69..112c684 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/MultipleImplementsTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/MultipleImplementsTest.java
@@ -53,7 +53,11 @@
     assumeTrue(parameters.useRuntimeAsNoneRuntime());
     AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-            buildClasses(I.class, A.class, B.class, C.class, Main.class).build(), Main.class);
+            buildClassesWithTestingAnnotations(
+                    I.class, J.class, A.class, B.class, C.class, Main.class)
+                .addLibraryFile(parameters.getDefaultRuntimeLibrary())
+                .build(),
+            Main.class);
     AppInfoWithLiveness appInfo = appView.appInfo();
     DexMethod method = buildNullaryVoidMethod(I.class, "foo", appInfo.dexItemFactory());
     ResolutionResult resolutionResult = appInfo.resolveMethodOnInterface(method.holder, method);
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/SimpleInterfaceInvokeTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/SimpleInterfaceInvokeTest.java
index ec16d6d..d011624 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/SimpleInterfaceInvokeTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/SimpleInterfaceInvokeTest.java
@@ -54,7 +54,10 @@
     assumeTrue(parameters.useRuntimeAsNoneRuntime());
     AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-            buildClasses(I.class, A.class, B.class, Main.class).build(), Main.class);
+            buildClassesWithTestingAnnotations(I.class, A.class, B.class, Main.class)
+                .addLibraryFile(parameters.getDefaultRuntimeLibrary())
+                .build(),
+            Main.class);
     AppInfoWithLiveness appInfo = appView.appInfo();
     DexMethod method = buildNullaryVoidMethod(I.class, "foo", appInfo.dexItemFactory());
     ResolutionResult resolutionResult = appInfo.resolveMethodOnInterface(method.holder, method);
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubInterfaceOverridesTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubInterfaceOverridesTest.java
index 3e582c5..9caa8d2 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubInterfaceOverridesTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubInterfaceOverridesTest.java
@@ -53,7 +53,10 @@
     assumeTrue(parameters.useRuntimeAsNoneRuntime());
     AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-            buildClasses(I.class, J.class, A.class, B.class, C.class, Main.class).build(),
+            buildClassesWithTestingAnnotations(
+                    I.class, J.class, A.class, B.class, C.class, Main.class)
+                .addLibraryFile(parameters.getDefaultRuntimeLibrary())
+                .build(),
             Main.class);
     AppInfoWithLiveness appInfo = appView.appInfo();
     DexMethod method = buildNullaryVoidMethod(I.class, "foo", appInfo.dexItemFactory());
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubTypeMissingOverridesTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubTypeMissingOverridesTest.java
index 5628ea2..aef0b3d 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubTypeMissingOverridesTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubTypeMissingOverridesTest.java
@@ -53,7 +53,10 @@
     assumeTrue(parameters.useRuntimeAsNoneRuntime());
     AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-            buildClasses(I.class, A.class, B.class, C.class, Main.class).build(), Main.class);
+            buildClassesWithTestingAnnotations(I.class, A.class, B.class, C.class, Main.class)
+                .addLibraryFile(parameters.getDefaultRuntimeLibrary())
+                .build(),
+            Main.class);
     AppInfoWithLiveness appInfo = appView.appInfo();
     DexMethod method = buildNullaryVoidMethod(I.class, "foo", appInfo.dexItemFactory());
     ResolutionResult resolutionResult = appInfo.resolveMethodOnInterface(method.holder, method);
@@ -65,11 +68,7 @@
     Set<String> targets = new HashSet<>();
     lookupResult
         .asLookupResultSuccess()
-        .forEach(
-            target -> targets.add(target.getDefinition().qualifiedName()),
-            lambda -> {
-              fail();
-            });
+        .forEach(target -> targets.add(target.getDefinition().qualifiedName()), lambda -> fail());
     ImmutableSet<String> expected =
         ImmutableSet.of(B.class.getTypeName() + ".foo", C.class.getTypeName() + ".foo");
     assertEquals(expected, targets);
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubTypeOverridesTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubTypeOverridesTest.java
index 65d8bca..d6230c7 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubTypeOverridesTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubTypeOverridesTest.java
@@ -53,7 +53,10 @@
     assumeTrue(parameters.useRuntimeAsNoneRuntime());
     AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-            buildClasses(I.class, A.class, B.class, Main.class).build(), Main.class);
+            buildClassesWithTestingAnnotations(I.class, A.class, B.class, Main.class)
+                .addLibraryFile(parameters.getDefaultRuntimeLibrary())
+                .build(),
+            Main.class);
     AppInfoWithLiveness appInfo = appView.appInfo();
     DexMethod method = buildNullaryVoidMethod(I.class, "foo", appInfo.dexItemFactory());
     ResolutionResult resolutionResult = appInfo.resolveMethodOnInterface(method.holder, method);
diff --git a/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateClasspathWidenTest.java b/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateClasspathWidenTest.java
index 1033136..129c033 100644
--- a/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateClasspathWidenTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateClasspathWidenTest.java
@@ -65,7 +65,11 @@
     assumeTrue(parameters.useRuntimeAsNoneRuntime());
     AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-            buildClasses(C.class, Main.class).addClasspathFiles(classPathJar).build(), Main.class);
+            buildClasses(C.class, Main.class)
+                .addClasspathFiles(classPathJar)
+                .addLibraryFile(parameters.getDefaultRuntimeLibrary())
+                .build(),
+            Main.class);
     AppInfoWithLiveness appInfo = appView.appInfo();
     DexMethod method = buildNullaryVoidMethod(Abstract.class, "foo", appInfo.dexItemFactory());
     ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method);
diff --git a/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateReentryTest.java b/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateReentryTest.java
index 3a20a43..9d06f40 100644
--- a/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateReentryTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateReentryTest.java
@@ -53,7 +53,10 @@
     assumeTrue(parameters.useRuntimeAsNoneRuntime());
     AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-            buildClasses(A.class, B.class, C.class, D.class, Main.class).build(), Main.class);
+            buildClasses(A.class, B.class, C.class, D.class, Main.class)
+                .addLibraryFile(parameters.getDefaultRuntimeLibrary())
+                .build(),
+            Main.class);
     AppInfoWithLiveness appInfo = appView.appInfo();
     DexMethod method = buildNullaryVoidMethod(A.class, "bar", appInfo.dexItemFactory());
     ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method);
diff --git a/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateReentryWithNarrowingTest.java b/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateReentryWithNarrowingTest.java
index 81920cb..a9eddd1 100644
--- a/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateReentryWithNarrowingTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateReentryWithNarrowingTest.java
@@ -57,7 +57,10 @@
     assumeTrue(parameters.useRuntimeAsNoneRuntime());
     AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-            buildClasses(A.class, B.class, C.class, D.class, Main.class).build(), Main.class);
+            buildClasses(A.class, B.class, C.class, D.class, Main.class)
+                .addLibraryFile(parameters.getDefaultRuntimeLibrary())
+                .build(),
+            Main.class);
     AppInfoWithLiveness appInfo = appView.appInfo();
     DexMethod method = buildNullaryVoidMethod(A.class, "bar", appInfo.dexItemFactory());
     ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method);
diff --git a/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateWithDefaultMethod2Test.java b/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateWithDefaultMethod2Test.java
index a964f73..fd40588 100644
--- a/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateWithDefaultMethod2Test.java
+++ b/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateWithDefaultMethod2Test.java
@@ -68,6 +68,7 @@
                     J.class,
                     Main.class)
                 .addClassProgramData(getNonAbstractWithoutDeclaredMethods())
+                .addLibraryFile(parameters.getDefaultRuntimeLibrary())
                 .build(),
             Main.class);
     AppInfoWithLiveness appInfo = appView.appInfo();
diff --git a/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateWithDefaultMethodTest.java b/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateWithDefaultMethodTest.java
index 3920cc8..58f4f6d 100644
--- a/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateWithDefaultMethodTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/packageprivate/PackagePrivateWithDefaultMethodTest.java
@@ -62,6 +62,7 @@
                     J.class,
                     Main.class)
                 .addClassProgramData(getNonAbstractWithoutDeclaredMethods())
+                .addLibraryFile(parameters.getDefaultRuntimeLibrary())
                 .build(),
             Main.class);
     AppInfoWithLiveness appInfo = appView.appInfo();
diff --git a/src/test/java/com/android/tools/r8/resolution/packageprivate/WidenAccessOutsidePackageTest.java b/src/test/java/com/android/tools/r8/resolution/packageprivate/WidenAccessOutsidePackageTest.java
index d86de60..d5b9556 100644
--- a/src/test/java/com/android/tools/r8/resolution/packageprivate/WidenAccessOutsidePackageTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/packageprivate/WidenAccessOutsidePackageTest.java
@@ -54,7 +54,10 @@
     assumeTrue(parameters.useRuntimeAsNoneRuntime());
     AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-            buildClasses(A.class, B.class, C.class, Main.class).build(), Main.class);
+            buildClasses(A.class, B.class, C.class, Main.class)
+                .addLibraryFile(parameters.getDefaultRuntimeLibrary())
+                .build(),
+            Main.class);
     AppInfoWithLiveness appInfo = appView.appInfo();
     DexMethod method = buildNullaryVoidMethod(A.class, "bar", appInfo.dexItemFactory());
     ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method);
diff --git a/src/test/java/com/android/tools/r8/resolution/singletarget/InstantiatedLowerBoundTest.java b/src/test/java/com/android/tools/r8/resolution/singletarget/InstantiatedLowerBoundTest.java
index 4e19a05..9e89194 100644
--- a/src/test/java/com/android/tools/r8/resolution/singletarget/InstantiatedLowerBoundTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/singletarget/InstantiatedLowerBoundTest.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.resolution.singletarget;
 
+import static com.android.tools.r8.ToolHelper.getMostRecentAndroidJar;
 import static junit.framework.TestCase.assertEquals;
 import static junit.framework.TestCase.assertNotNull;
 import static junit.framework.TestCase.assertTrue;
@@ -46,7 +47,9 @@
   public void testSingleTargetLowerBoundInstantiated() throws Exception {
     AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-            buildClasses(A.class, B.class, Main.class).build(),
+            buildClasses(A.class, B.class, Main.class)
+                .addLibraryFile(getMostRecentAndroidJar())
+                .build(),
             factory ->
                 buildConfigForRules(factory, buildKeepRuleForClassAndMethods(Main.class, factory)));
     AppInfoWithLiveness appInfo = appView.appInfo();
@@ -71,7 +74,9 @@
   public void testSingleTargetLowerBoundInMiddleInstantiated() throws Exception {
     AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-            buildClasses(A.class, B.class, C.class, Main.class).build(),
+            buildClasses(A.class, B.class, C.class, Main.class)
+                .addLibraryFile(getMostRecentAndroidJar())
+                .build(),
             factory ->
                 buildConfigForRules(factory, buildKeepRuleForClassAndMethods(Main.class, factory)));
     AppInfoWithLiveness appInfo = appView.appInfo();
@@ -96,7 +101,9 @@
   public void testSingleTargetLowerAllInstantiated() throws Exception {
     AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-            buildClasses(A.class, B.class, C.class, MainAllInstantiated.class).build(),
+            buildClasses(A.class, B.class, C.class, MainAllInstantiated.class)
+                .addLibraryFile(getMostRecentAndroidJar())
+                .build(),
             factory ->
                 buildConfigForRules(
                     factory, buildKeepRuleForClassAndMethods(MainAllInstantiated.class, factory)));
diff --git a/src/test/java/com/android/tools/r8/resolution/singletarget/SuccessAndInvalidLookupTest.java b/src/test/java/com/android/tools/r8/resolution/singletarget/SuccessAndInvalidLookupTest.java
index 593670d..916c7a0 100644
--- a/src/test/java/com/android/tools/r8/resolution/singletarget/SuccessAndInvalidLookupTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/singletarget/SuccessAndInvalidLookupTest.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.resolution.singletarget;
 
+import static com.android.tools.r8.ToolHelper.getMostRecentAndroidJar;
 import static junit.framework.TestCase.assertEquals;
 import static junit.framework.TestCase.assertNotNull;
 import static junit.framework.TestCase.assertNull;
@@ -31,14 +32,16 @@
   }
 
   public SuccessAndInvalidLookupTest(TestParameters parameters) {
-    // Empty to satisfy construction of none-runtime.
+    assert parameters.isNoneRuntime();
   }
 
   @Test
   public void testSingleTargetWithInvalidInvokeInterfaceInvoke() throws Exception {
     AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-            buildClasses(I.class, A.class, Main.class).build(),
+            buildClasses(I.class, A.class, Main.class)
+                .addLibraryFile(getMostRecentAndroidJar())
+                .build(),
             factory ->
                 buildConfigForRules(factory, buildKeepRuleForClassAndMethods(Main.class, factory)));
     AppInfoWithLiveness appInfo = appView.appInfo();
@@ -62,7 +65,9 @@
   public void testSingleTargetWithInvalidInvokeVirtualInvoke() throws Exception {
     AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-            buildClasses(I.class, A.class, Main.class).build(),
+            buildClasses(I.class, A.class, Main.class)
+                .addLibraryFile(getMostRecentAndroidJar())
+                .build(),
             factory ->
                 buildConfigForRules(factory, buildKeepRuleForClassAndMethods(Main.class, factory)));
     AppInfoWithLiveness appInfo = appView.appInfo();
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/AbstractInMiddleTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/AbstractInMiddleTest.java
index 787f992..ee3387e 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/AbstractInMiddleTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/AbstractInMiddleTest.java
@@ -53,7 +53,10 @@
     assumeTrue(parameters.useRuntimeAsNoneRuntime());
     AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-            buildClasses(A.class, B.class, C.class, Main.class).build(), Main.class);
+            buildClassesWithTestingAnnotations(A.class, B.class, C.class, Main.class)
+                .addLibraryFile(parameters.getDefaultRuntimeLibrary())
+                .build(),
+            Main.class);
     AppInfoWithLiveness appInfo = appView.appInfo();
     DexMethod method = buildNullaryVoidMethod(A.class, "foo", appInfo.dexItemFactory());
     ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method);
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultInterfaceMethodInSubInterfaceSubTypeTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultInterfaceMethodInSubInterfaceSubTypeTest.java
index 80b6908..73b0af5 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultInterfaceMethodInSubInterfaceSubTypeTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultInterfaceMethodInSubInterfaceSubTypeTest.java
@@ -53,7 +53,10 @@
     assumeTrue(parameters.useRuntimeAsNoneRuntime());
     AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-            buildClasses(I.class, J.class, A.class, B.class, Main.class).build(), Main.class);
+            buildClassesWithTestingAnnotations(I.class, J.class, A.class, B.class, Main.class)
+                .addLibraryFile(parameters.getDefaultRuntimeLibrary())
+                .build(),
+            Main.class);
     AppInfoWithLiveness appInfo = appView.appInfo();
     DexMethod method = buildNullaryVoidMethod(A.class, "foo", appInfo.dexItemFactory());
     ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method);
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultInterfaceMethodInSubInterfaceTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultInterfaceMethodInSubInterfaceTest.java
index a4966b4..1f27130 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultInterfaceMethodInSubInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultInterfaceMethodInSubInterfaceTest.java
@@ -53,7 +53,10 @@
     assumeTrue(parameters.useRuntimeAsNoneRuntime());
     AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-            buildClasses(I.class, J.class, A.class, Main.class).build(), Main.class);
+            buildClassesWithTestingAnnotations(I.class, J.class, A.class, Main.class)
+                .addLibraryFile(parameters.getDefaultRuntimeLibrary())
+                .build(),
+            Main.class);
     AppInfoWithLiveness appInfo = appView.appInfo();
     DexMethod method = buildNullaryVoidMethod(A.class, "foo", appInfo.dexItemFactory());
     ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method);
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultWithoutTopTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultWithoutTopTest.java
index 1e23ae3..11e259c 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultWithoutTopTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultWithoutTopTest.java
@@ -53,8 +53,9 @@
     assumeTrue(parameters.useRuntimeAsNoneRuntime());
     AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-            buildClasses(I.class, J.class, Main.class)
+            buildClassesWithTestingAnnotations(I.class, J.class, Main.class)
                 .addClassProgramData(setAImplementsIAndJ())
+                .addLibraryFile(parameters.getDefaultRuntimeLibrary())
                 .build(),
             Main.class);
     AppInfoWithLiveness appInfo = appView.appInfo();
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/InvalidResolutionToThisTarget.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/InvalidResolutionToThisTarget.java
index b75b7ac..f19413c 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/InvalidResolutionToThisTarget.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/InvalidResolutionToThisTarget.java
@@ -54,6 +54,7 @@
                   computeAppViewWithLiveness(
                       buildClasses(A.class)
                           .addClassProgramData(getMainWithModifiedReceiverCall())
+                          .addLibraryFile(parameters.getDefaultRuntimeLibrary())
                           .build(),
                       Main.class);
               AppInfoWithLiveness appInfo = appView.appInfo();
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/InvokeVirtualToInterfaceDefinitionTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/InvokeVirtualToInterfaceDefinitionTest.java
index dcb03f9..511d697 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/InvokeVirtualToInterfaceDefinitionTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/InvokeVirtualToInterfaceDefinitionTest.java
@@ -52,7 +52,11 @@
   public void testResolution() throws Exception {
     assumeTrue(parameters.useRuntimeAsNoneRuntime());
     AppView<AppInfoWithLiveness> appView =
-        computeAppViewWithLiveness(buildClasses(A.class, I.class, Main.class).build(), Main.class);
+        computeAppViewWithLiveness(
+            buildClassesWithTestingAnnotations(A.class, I.class, Main.class)
+                .addLibraryFile(parameters.getDefaultRuntimeLibrary())
+                .build(),
+            Main.class);
     AppInfoWithLiveness appInfo = appView.appInfo();
     DexMethod method = buildNullaryVoidMethod(A.class, "foo", appInfo.dexItemFactory());
     ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method);
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/KeptTargetsIncompleteLookupTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/KeptTargetsIncompleteLookupTest.java
index bc35d2b..7df1ec6 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/KeptTargetsIncompleteLookupTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/KeptTargetsIncompleteLookupTest.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.resolution.virtualtargets;
 
+import static com.android.tools.r8.ToolHelper.getMostRecentAndroidJar;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
@@ -62,7 +63,7 @@
         methodToBeKept,
         classToBeKept,
         Arrays.asList(expectedMethodHolders),
-        Arrays.asList(I.class, A.class, B.class, C.class, Main.class),
+        Arrays.asList(I.class, A.class, B.class, C.class, Main.class, Unrelated.class),
         Main.class);
   }
 
@@ -76,7 +77,7 @@
       throws Exception {
     AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-            buildClasses(classes).build(),
+            buildClasses(classes).addLibraryFile(getMostRecentAndroidJar()).build(),
             factory -> {
               List<ProguardConfigurationRule> rules = new ArrayList<>();
               rules.addAll(buildKeepRuleForClassAndMethods(methodToBeKept, factory));
@@ -267,7 +268,9 @@
     //   private foo() <-- kept
     // }
     AppView<AppInfoWithLiveness> appView =
-        computeAppViewWithLiveness(buildClasses(Unrelated.class).build(), Unrelated.class);
+        computeAppViewWithLiveness(
+            buildClasses(Unrelated.class).addLibraryFile(getMostRecentAndroidJar()).build(),
+            Unrelated.class);
     AppInfoWithLiveness appInfo = appView.appInfo();
     DexMethod method = buildNullaryVoidMethod(Unrelated.class, "foo", appInfo.dexItemFactory());
     ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method);
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/PackagePrivateChainTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/PackagePrivateChainTest.java
index c74b196..3fc0355 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/PackagePrivateChainTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/PackagePrivateChainTest.java
@@ -57,6 +57,7 @@
     AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
             buildClasses(Top.class, Middle.class, Bottom.class, TopRunner.class, Main.class)
+                .addLibraryFile(parameters.getDefaultRuntimeLibrary())
                 .build(),
             Main.class);
     AppInfoWithLiveness appInfo = appView.appInfo();
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/PackagePrivateFinalOverrideTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/PackagePrivateFinalOverrideTest.java
index 00f9b0b..f081ef1 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/PackagePrivateFinalOverrideTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/PackagePrivateFinalOverrideTest.java
@@ -61,7 +61,9 @@
     assumeTrue(parameters.useRuntimeAsNoneRuntime());
     AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-            buildClasses(MyViewModel.class, ViewModel.class, Main.class, ViewModelRunner.class)
+            buildClassesWithTestingAnnotations(
+                    MyViewModel.class, ViewModel.class, Main.class, ViewModelRunner.class)
+                .addLibraryFile(parameters.getDefaultRuntimeLibrary())
                 .build(),
             Main.class);
     AppInfoWithLiveness appInfo = appView.appInfo();
@@ -110,7 +112,9 @@
     assumeTrue(parameters.useRuntimeAsNoneRuntime());
     AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-            buildClasses(MyViewModel.class, ViewModel.class, Main.class, ViewModelRunner.class)
+            buildClassesWithTestingAnnotations(
+                    MyViewModel.class, ViewModel.class, Main.class, ViewModelRunner.class)
+                .addLibraryFile(parameters.getDefaultRuntimeLibrary())
                 .build(),
             Main.class);
     AppInfoWithLiveness appInfo = appView.appInfo();
@@ -156,8 +160,13 @@
     assumeTrue(parameters.useRuntimeAsNoneRuntime());
     AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-            buildClasses(
-                    MyViewModel.class, ViewModel.class, Main.class, ViewModelRunnerWithCast.class)
+            buildClassesWithTestingAnnotations(
+                    MyViewModel.class,
+                    ViewModel.class,
+                    Main.class,
+                    ViewModelRunner.class,
+                    ViewModelRunnerWithCast.class)
+                .addLibraryFile(parameters.getDefaultRuntimeLibrary())
                 .build(),
             Main.class);
     AppInfoWithLiveness appInfo = appView.appInfo();
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/PrivateOverrideOfVirtualTargetTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/PrivateOverrideOfVirtualTargetTest.java
index e7319cd..86e9ecb 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/PrivateOverrideOfVirtualTargetTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/PrivateOverrideOfVirtualTargetTest.java
@@ -56,6 +56,7 @@
         computeAppViewWithLiveness(
             buildClasses(A.class, Main.class)
                 .addClassProgramData(getBWithModifiedInvokes())
+                .addLibraryFile(parameters.getDefaultRuntimeLibrary())
                 .build(),
             Main.class);
     AppInfoWithLiveness appInfo = appView.appInfo();
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/ProtectedDifferentPackageLookupTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/ProtectedDifferentPackageLookupTest.java
index 37b4dc8..092f9b5 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/ProtectedDifferentPackageLookupTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/ProtectedDifferentPackageLookupTest.java
@@ -50,6 +50,7 @@
     builder.addProgramFiles(ToolHelper.getClassFileForTestClass(A.class));
     builder.addClassProgramData(
         ImmutableList.of(getBInAnotherPackage(), getMainWithCallToRelocatedB()));
+    builder.addLibraryFile(parameters.getDefaultRuntimeLibrary());
     AppView<AppInfoWithLiveness> appView = computeAppViewWithLiveness(builder.build(), Main.class);
     AppInfoWithLiveness appInfo = appView.appInfo();
     DexMethod method = buildNullaryVoidMethod(A.class, "foo", appInfo.dexItemFactory());
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/ProtectedSamePackageLookupTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/ProtectedSamePackageLookupTest.java
index ea86d8a..8915fa5 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/ProtectedSamePackageLookupTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/ProtectedSamePackageLookupTest.java
@@ -44,7 +44,10 @@
     assumeTrue(parameters.useRuntimeAsNoneRuntime());
     AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-            buildClasses(A.class, C.class, Main.class).build(), PackagePrivateChainTest.Main.class);
+            buildClasses(A.class, C.class, Main.class)
+                .addLibraryFile(parameters.getDefaultRuntimeLibrary())
+                .build(),
+            PackagePrivateChainTest.Main.class);
     AppInfoWithLiveness appInfo = appView.appInfo();
     DexMethod method = buildNullaryVoidMethod(A.class, "foo", appInfo.dexItemFactory());
     ResolutionResult resolutionResult = appInfo.resolveMethodOnClass(method);
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/TargetInDefaultMethodTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/TargetInDefaultMethodTest.java
index c1f2301..092bcb8 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/TargetInDefaultMethodTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/TargetInDefaultMethodTest.java
@@ -54,7 +54,10 @@
     assumeTrue(parameters.useRuntimeAsNoneRuntime());
     AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-            buildClasses(I.class, A.class, B.class, C.class, Main.class).build(), Main.class);
+            buildClassesWithTestingAnnotations(I.class, A.class, B.class, C.class, Main.class)
+                .addLibraryFile(parameters.getDefaultRuntimeLibrary())
+                .build(),
+            Main.class);
     AppInfoWithLiveness appInfo = appView.appInfo();
     DexMethod method = buildNullaryVoidMethod(I.class, "foo", appInfo.dexItemFactory());
     ResolutionResult resolutionResult = appInfo.resolveMethodOnInterface(method);
diff --git a/src/test/java/com/android/tools/r8/retrace/KotlinInlineFunctionInSameFileRetraceTests.java b/src/test/java/com/android/tools/r8/retrace/KotlinInlineFunctionInSameFileRetraceTests.java
index b16dc35..b65563e 100644
--- a/src/test/java/com/android/tools/r8/retrace/KotlinInlineFunctionInSameFileRetraceTests.java
+++ b/src/test/java/com/android/tools/r8/retrace/KotlinInlineFunctionInSameFileRetraceTests.java
@@ -5,6 +5,8 @@
 
 import static com.android.tools.r8.Collectors.toSingle;
 import static com.android.tools.r8.ToolHelper.getFilesInTestFolderRelativeToClass;
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
+import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.containsLinePositions;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isInlineFrame;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isInlineStack;
@@ -19,7 +21,6 @@
 import com.android.tools.r8.KotlinTestBase;
 import com.android.tools.r8.KotlinTestParameters;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.naming.retrace.StackTrace;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
@@ -74,7 +75,7 @@
     assumeTrue(kotlinc.is(KotlinCompilerVersion.KOTLINC_1_3_72));
     testForRuntime(parameters)
         .addProgramFiles(compilationResults.getForConfiguration(kotlinc, targetVersion))
-        .addRunClasspathFiles(buildOnDexRuntime(parameters, ToolHelper.getKotlinStdlibJar(kotlinc)))
+        .addRunClasspathFiles(buildOnDexRuntime(parameters, getKotlinStdlibJar(kotlinc)))
         .run(parameters.getRuntime(), MAIN)
         .assertFailureWithErrorThatMatches(containsString("foo"))
         .assertFailureWithErrorThatMatches(
@@ -90,8 +91,7 @@
     CodeInspector kotlinInspector = new CodeInspector(kotlinSources);
     testForR8(parameters.getBackend())
         .addProgramFiles(compilationResults.getForConfiguration(kotlinc, targetVersion))
-        .addProgramFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
-        .addDontWarnJetBrainsNotNullAnnotation()
+        .addProgramFiles(getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
         .addKeepAttributes("SourceFile", "LineNumberTable")
         .setMode(CompilationMode.RELEASE)
         .addKeepMainRule(MAIN)
diff --git a/src/test/java/com/android/tools/r8/retrace/KotlinInlineFunctionRetraceTest.java b/src/test/java/com/android/tools/r8/retrace/KotlinInlineFunctionRetraceTest.java
index ffc5515..17d4dc6 100644
--- a/src/test/java/com/android/tools/r8/retrace/KotlinInlineFunctionRetraceTest.java
+++ b/src/test/java/com/android/tools/r8/retrace/KotlinInlineFunctionRetraceTest.java
@@ -6,6 +6,8 @@
 
 import static com.android.tools.r8.Collectors.toSingle;
 import static com.android.tools.r8.ToolHelper.getFilesInTestFolderRelativeToClass;
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
+import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.containsLinePositions;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isInlineFrame;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isInlineStack;
@@ -20,7 +22,6 @@
 import com.android.tools.r8.KotlinTestBase;
 import com.android.tools.r8.KotlinTestParameters;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.naming.retrace.StackTrace;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.FoundMethodSubject;
@@ -87,7 +88,7 @@
   public void testRuntime() throws Exception {
     testForRuntime(parameters)
         .addProgramFiles(compilationResults.getForConfiguration(kotlinc, targetVersion))
-        .addRunClasspathFiles(buildOnDexRuntime(parameters, ToolHelper.getKotlinStdlibJar(kotlinc)))
+        .addRunClasspathFiles(buildOnDexRuntime(parameters, getKotlinStdlibJar(kotlinc)))
         .run(parameters.getRuntime(), "retrace.MainKt")
         .assertFailureWithErrorThatMatches(containsString("inlineExceptionStatic"))
         .assertFailureWithErrorThatMatches(containsString("at retrace.MainKt.main(Main.kt:15)"));
@@ -102,12 +103,12 @@
     Path kotlinSources = compilationResults.getForConfiguration(kotlinc, targetVersion);
     CodeInspector kotlinInspector = new CodeInspector(kotlinSources);
     testForR8(parameters.getBackend())
-        .addProgramFiles(kotlinSources, ToolHelper.getKotlinStdlibJar(kotlinc))
+        .addProgramFiles(
+            kotlinSources, getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
         .addKeepAttributes("SourceFile", "LineNumberTable")
         .allowDiagnosticWarningMessages()
         .setMode(CompilationMode.RELEASE)
         .addKeepMainRule(main)
-        .addDontWarnJetBrainsNotNullAnnotation()
         .setMinApi(parameters.getApiLevel())
         .compile()
         .assertAllWarningMessagesMatch(equalTo("Resource 'META-INF/MANIFEST.MF' already exists."))
@@ -134,12 +135,12 @@
     Path kotlinSources = compilationResults.getForConfiguration(kotlinc, targetVersion);
     CodeInspector kotlinInspector = new CodeInspector(kotlinSources);
     testForR8(parameters.getBackend())
-        .addProgramFiles(kotlinSources, ToolHelper.getKotlinStdlibJar(kotlinc))
+        .addProgramFiles(
+            kotlinSources, getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
         .addKeepAttributes("SourceFile", "LineNumberTable")
         .allowDiagnosticWarningMessages()
         .setMode(CompilationMode.RELEASE)
         .addKeepMainRule(main)
-        .addDontWarnJetBrainsNotNullAnnotation()
         .setMinApi(parameters.getApiLevel())
         .compile()
         .assertAllWarningMessagesMatch(equalTo("Resource 'META-INF/MANIFEST.MF' already exists."))
@@ -169,12 +170,12 @@
     Path kotlinSources = compilationResults.getForConfiguration(kotlinc, targetVersion);
     CodeInspector kotlinInspector = new CodeInspector(kotlinSources);
     testForR8(parameters.getBackend())
-        .addProgramFiles(kotlinSources, ToolHelper.getKotlinStdlibJar(kotlinc))
+        .addProgramFiles(
+            kotlinSources, getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
         .addKeepAttributes("SourceFile", "LineNumberTable")
         .allowDiagnosticWarningMessages()
         .setMode(CompilationMode.RELEASE)
         .addKeepMainRule(main)
-        .addDontWarnJetBrainsNotNullAnnotation()
         .setMinApi(parameters.getApiLevel())
         .compile()
         .assertAllWarningMessagesMatch(equalTo("Resource 'META-INF/MANIFEST.MF' already exists."))
@@ -203,12 +204,12 @@
     Path kotlinSources = compilationResults.getForConfiguration(kotlinc, targetVersion);
     CodeInspector kotlinInspector = new CodeInspector(kotlinSources);
     testForR8(parameters.getBackend())
-        .addProgramFiles(kotlinSources, ToolHelper.getKotlinStdlibJar(kotlinc))
+        .addProgramFiles(
+            kotlinSources, getKotlinStdlibJar(kotlinc), getKotlinAnnotationJar(kotlinc))
         .addKeepAttributes("SourceFile", "LineNumberTable")
         .allowDiagnosticWarningMessages()
         .setMode(CompilationMode.RELEASE)
         .addKeepMainRule(main)
-        .addDontWarnJetBrainsNotNullAnnotation()
         .setMinApi(parameters.getApiLevel())
         .compile()
         .assertAllWarningMessagesMatch(equalTo("Resource 'META-INF/MANIFEST.MF' already exists."))
diff --git a/src/test/java/com/android/tools/r8/rewrite/JavaScriptScriptEngineTest.java b/src/test/java/com/android/tools/r8/rewrite/JavaScriptScriptEngineTest.java
index 0078c1b..e59bfb9 100644
--- a/src/test/java/com/android/tools/r8/rewrite/JavaScriptScriptEngineTest.java
+++ b/src/test/java/com/android/tools/r8/rewrite/JavaScriptScriptEngineTest.java
@@ -66,11 +66,15 @@
               }
             })
         .compile()
-        .assertAllWarningMessagesMatch(
-            anyOf(
-                containsString("Missing class "),
-                containsString("required for default or static interface methods desugaring"),
-                equalTo("Resource 'META-INF/MANIFEST.MF' already exists.")))
+        .applyIf(
+            parameters.isDexRuntime(),
+            result ->
+                result.assertAllWarningMessagesMatch(
+                    anyOf(
+                        containsString("Missing class "),
+                        containsString(
+                            "required for default or static interface methods desugaring"),
+                        equalTo("Resource 'META-INF/MANIFEST.MF' already exists."))))
         .run(parameters.getRuntime(), TestClass.class)
         .assertSuccessWithOutput(
             parameters.isCfRuntime() ? EXPECTED_NASHORN_OUTPUT : EXPECTED_RHINO_OUTPUT);
diff --git a/src/test/java/com/android/tools/r8/rewrite/ScriptEngineTest.java b/src/test/java/com/android/tools/r8/rewrite/ScriptEngineTest.java
index 0077cef..dd55c22 100644
--- a/src/test/java/com/android/tools/r8/rewrite/ScriptEngineTest.java
+++ b/src/test/java/com/android/tools/r8/rewrite/ScriptEngineTest.java
@@ -79,11 +79,15 @@
         // TODO(b/136633154): This should work both with and without -dontshrink.
         .noTreeShaking()
         .compile()
-        .assertAllWarningMessagesMatch(
-            anyOf(
-                containsString("Missing class "),
-                containsString("it is required for default or static interface methods desugaring"),
-                equalTo("Resource 'META-INF/MANIFEST.MF' already exists.")))
+        .applyIf(
+            parameters.isDexRuntime(),
+            result ->
+                result.assertAllWarningMessagesMatch(
+                    anyOf(
+                        containsString("Missing class "),
+                        containsString(
+                            "it is required for default or static interface methods desugaring"),
+                        equalTo("Resource 'META-INF/MANIFEST.MF' already exists."))))
         .writeToZip(path)
         .run(parameters.getRuntime(), TestClass.class)
         // TODO(b/136633154): This should provide 2 script engines on both runtimes. The use of
diff --git a/src/test/java/com/android/tools/r8/rewrite/ScriptEngineTestBase.java b/src/test/java/com/android/tools/r8/rewrite/ScriptEngineTestBase.java
index af0878b..5e411be 100644
--- a/src/test/java/com/android/tools/r8/rewrite/ScriptEngineTestBase.java
+++ b/src/test/java/com/android/tools/r8/rewrite/ScriptEngineTestBase.java
@@ -4,15 +4,15 @@
 
 package com.android.tools.r8.rewrite;
 
-import com.android.tools.r8.R8FullTestBuilder;
 import com.android.tools.r8.R8TestBuilder;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestBuilder;
+import com.android.tools.r8.TestShrinkerBuilder;
 import com.android.tools.r8.ToolHelper;
 import java.nio.file.Paths;
 
 public class ScriptEngineTestBase extends TestBase {
-  public void addRhinoForAndroid(TestBuilder builder) {
+  public void addRhinoForAndroid(TestBuilder<?, ?> builder) {
     builder
         // JSR 223: Scripting for the JavaTM Platform (https://jcp.org/en/jsr/detail?id=223).
         .addProgramFiles(Paths.get(ToolHelper.JSR223_RI_JAR))
@@ -21,10 +21,10 @@
         // The rhino-android contains concrete implementation of sun.misc.Service
         // used by the JSR 223 RI, which is not in the Android runtime (except for N?).
         .addProgramFiles(Paths.get(ToolHelper.RHINO_ANDROID_JAR));
-    if (builder instanceof R8FullTestBuilder) {
-      ((R8FullTestBuilder) builder)
+    if (builder instanceof TestShrinkerBuilder) {
+      ((TestShrinkerBuilder<?, ?, ?, ?, ?>) builder)
           // The rhino-android library have references to missing classes.
-          .addOptionsModification(options -> options.ignoreMissingClasses = true);
+          .addIgnoreWarnings();
     }
   }
 
diff --git a/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationKotlinTest.java b/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationKotlinTest.java
index 0298ecd..22ba711 100644
--- a/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationKotlinTest.java
+++ b/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationKotlinTest.java
@@ -170,7 +170,11 @@
         .allowDiagnosticWarningMessages(!kotlinStdlibAsLibrary)
         .addRunClasspathFiles(kotlinStdlibLibraryForRuntime())
         .compile()
-        .assertAllWarningMessagesMatch(equalTo("Resource 'META-INF/MANIFEST.MF' already exists."))
+        .applyIf(
+            !kotlinStdlibAsLibrary,
+            result ->
+                result.assertAllWarningMessagesMatch(
+                    equalTo("Resource 'META-INF/MANIFEST.MF' already exists.")))
         .enableRuntimeAssertions(enableJvmAssertions)
         .run(parameters.getRuntime(), testClassKt)
         .inspect(inspector)
diff --git a/src/test/java/com/android/tools/r8/shaking/FieldTypeTest.java b/src/test/java/com/android/tools/r8/shaking/FieldTypeTest.java
index 512a9ff..df19a94 100644
--- a/src/test/java/com/android/tools/r8/shaking/FieldTypeTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/FieldTypeTest.java
@@ -27,7 +27,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-@RunWith(VmTestRunner.class)
 public class FieldTypeTest extends TestBase {
 
   private ClassBuilder addImplementor(
@@ -222,5 +221,4 @@
     ClassSubject itf1Subject = inspector.clazz(itf1.name);
     assertThat(itf1Subject, not(isPresent()));
   }
-
 }
diff --git a/src/test/java/com/android/tools/r8/shaking/InstantiatedLambdasTestRunner.java b/src/test/java/com/android/tools/r8/shaking/InstantiatedLambdasTestRunner.java
index c7ab1b7..88dd300 100644
--- a/src/test/java/com/android/tools/r8/shaking/InstantiatedLambdasTestRunner.java
+++ b/src/test/java/com/android/tools/r8/shaking/InstantiatedLambdasTestRunner.java
@@ -4,117 +4,96 @@
 package com.android.tools.r8.shaking;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.ByteDataView;
-import com.android.tools.r8.ClassFileConsumer;
 import com.android.tools.r8.ClassFileConsumer.ArchiveConsumer;
-import com.android.tools.r8.CompilationMode;
-import com.android.tools.r8.DexIndexedConsumer;
-import com.android.tools.r8.ProgramConsumer;
-import com.android.tools.r8.R8Command;
-import com.android.tools.r8.R8Command.Builder;
 import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.ToolHelper.ProcessResult;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.FileUtils;
+import com.android.tools.r8.utils.StringUtils;
 import java.io.IOException;
 import java.nio.file.Path;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
 
+@RunWith(Parameterized.class)
 public class InstantiatedLambdasTestRunner extends TestBase {
-  static final Class CLASS = InstantiatedLambdasTest.class;
-  static final Class[] CLASSES = InstantiatedLambdasTest.CLASSES;
+
+  static final Class<?> CLASS = InstantiatedLambdasTest.class;
+  static final Class<?>[] CLASSES = InstantiatedLambdasTest.CLASSES;
+  static final String EXPECTED = StringUtils.lines("Class implementation", "Lambda implementation");
+
+  private final TestParameters parameters;
 
   private Path inputJar;
-  private ProcessResult runInput;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().build();
+  }
+
+  public InstantiatedLambdasTestRunner(TestParameters parameters) {
+    this.parameters = parameters;
+  }
 
   @Before
   public void writeAndRunInputJar() throws IOException {
     inputJar = temp.getRoot().toPath().resolve("input.jar");
     ArchiveConsumer buildInput = new ArchiveConsumer(inputJar);
-    for (Class clazz : CLASSES) {
+    for (Class<?> clazz : CLASSES) {
       buildInput.accept(
           ByteDataView.of(ToolHelper.getClassAsBytes(clazz)),
           DescriptorUtils.javaTypeToDescriptor(clazz.getName()),
           null);
     }
     buildInput.finished(null);
-    runInput = ToolHelper.runJava(inputJar, CLASS.getCanonicalName());
-    assertEquals(0, runInput.exitCode);
-  }
-
-  private Path writeProguardRules(boolean aggressive) throws IOException {
-    Path pgConfig = temp.getRoot().toPath().resolve("keep.txt");
-    FileUtils.writeTextFile(
-        pgConfig,
-        "-keep public class " + CLASS.getCanonicalName() + " {",
-        "  public static void main(...);",
-        "}",
-        aggressive ? "-overloadaggressively" : "# Not overloading aggressively");
-    return pgConfig;
   }
 
   @Test
   public void testProguard() throws Exception {
+    assumeTrue(parameters.isCfRuntime());
     buildAndRunProguard("pg.jar", false);
   }
 
   @Test
   public void testProguardAggressive() throws Exception {
+    assumeTrue(parameters.isCfRuntime());
     buildAndRunProguard("pg-aggressive.jar", true);
   }
 
   @Test
-  public void testCf() throws Exception {
-    buildAndRunCf("cf.zip", false);
+  public void testR8() throws Exception {
+    testR8(false);
   }
 
   @Test
-  public void testCfAggressive() throws Exception {
-    buildAndRunCf("cf-aggressive.zip", true);
+  public void testR8Aggressive() throws Exception {
+    testR8(true);
   }
 
-  @Test
-  public void testDex() throws Exception {
-    buildAndRunDex("dex.zip", false);
-  }
-
-  @Test
-  public void testDexAggressive() throws Exception {
-    buildAndRunDex("dex-aggressive.zip", true);
-  }
-
-  private void buildAndRunCf(String outName, boolean aggressive) throws Exception {
-    Path outCf = temp.getRoot().toPath().resolve(outName);
-    build(new ClassFileConsumer.ArchiveConsumer(outCf), aggressive);
-    ProcessResult runCf = ToolHelper.runJava(outCf, CLASS.getCanonicalName());
-    assertEquals(runInput.toString(), runCf.toString());
-  }
-
-  private void buildAndRunDex(String outName, boolean aggressive) throws Exception {
-    Path outDex = temp.getRoot().toPath().resolve(outName);
-    build(new DexIndexedConsumer.ArchiveConsumer(outDex), aggressive);
-    ProcessResult runDex =
-        ToolHelper.runArtNoVerificationErrorsRaw(outDex.toString(), CLASS.getCanonicalName());
-    assertEquals(runInput.stdout, runDex.stdout);
-    assertEquals(runInput.exitCode, runDex.exitCode);
-  }
-
-  private void build(ProgramConsumer consumer, boolean aggressive) throws Exception {
-    Builder builder =
-        ToolHelper.addProguardConfigurationConsumer(
-                R8Command.builder(), configuration -> configuration.setPrintMapping(true))
-            .setMode(CompilationMode.DEBUG)
-            .addLibraryFiles(ToolHelper.getAndroidJar(ToolHelper.getMinApiLevelForDexVm()))
-            .addProgramFiles(inputJar)
-            .setProgramConsumer(consumer)
-            .addProguardConfigurationFiles(writeProguardRules(aggressive));
-    if (!(consumer instanceof ClassFileConsumer)) {
-      builder.setMinApiLevel(ToolHelper.getMinApiLevelForDexVm().getLevel());
-    }
-    ToolHelper.runR8(builder.build());
+  private void testR8(boolean aggressive) throws Exception {
+    testForR8(parameters.getBackend())
+        .addProgramFiles(inputJar)
+        .addKeepMainRule(CLASS)
+        .applyIf(aggressive, builder -> builder.addKeepRules("-overloadaggressively"))
+        .debug()
+        .setMinApi(parameters.getApiLevel())
+        .compile()
+        .apply(
+            compileResult ->
+                compileResult.run(parameters.getRuntime(), CLASS).assertSuccessWithOutput(EXPECTED))
+        .applyIf(
+            parameters.isDexRuntime(),
+            compileResult ->
+                compileResult.runDex2Oat(parameters.getRuntime()).assertNoVerificationErrors());
   }
 
   private void buildAndRunProguard(String outName, boolean aggressive) throws Exception {
@@ -131,4 +110,15 @@
     ProcessResult runPg = ToolHelper.runJava(outPg, CLASS.getCanonicalName());
     assertEquals(0, runPg.exitCode);
   }
+
+  private Path writeProguardRules(boolean aggressive) throws IOException {
+    Path pgConfig = temp.getRoot().toPath().resolve("keep.txt");
+    FileUtils.writeTextFile(
+        pgConfig,
+        "-keep public class " + CLASS.getCanonicalName() + " {",
+        "  public static void main(...);",
+        "}",
+        aggressive ? "-overloadaggressively" : "# Not overloading aggressively");
+    return pgConfig;
+  }
 }
diff --git a/src/test/java/com/android/tools/r8/shaking/InvalidTypesTest.java b/src/test/java/com/android/tools/r8/shaking/InvalidTypesTest.java
index ecb398a..efa7b4e 100644
--- a/src/test/java/com/android/tools/r8/shaking/InvalidTypesTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/InvalidTypesTest.java
@@ -286,6 +286,8 @@
       checkTestRunResult(d8Result, Compiler.D8);
     }
 
+    boolean allowDiagnosticWarningMessages =
+        mode == Mode.INVOKE_UNVERIFIABLE_METHOD && !useInterface;
     R8TestRunResult r8Result =
         testForR8(parameters.getBackend())
             .addProgramFiles(inputJar)
@@ -300,14 +302,16 @@
                     options.testing.allowTypeErrors = true;
                   }
                 })
-            .allowDiagnosticWarningMessages(
-                mode == Mode.INVOKE_UNVERIFIABLE_METHOD && !useInterface)
+            .allowDiagnosticWarningMessages(allowDiagnosticWarningMessages)
             .setMinApi(parameters.getApiLevel())
             .compile()
-            .assertAllWarningMessagesMatch(
-                equalTo(
-                    "The method `void UnverifiableClass.unverifiableMethod()` does not type check"
-                        + " and will be assumed to be unreachable."))
+            .applyIf(
+                allowDiagnosticWarningMessages,
+                result ->
+                    result.assertAllWarningMessagesMatch(
+                        equalTo(
+                            "The method `void UnverifiableClass.unverifiableMethod()` does not"
+                                + " type check and will be assumed to be unreachable.")))
             .run(parameters.getRuntime(), mainClass.name);
     checkTestRunResult(r8Result, Compiler.R8);
 
@@ -326,14 +330,16 @@
                   }
                   options.enableUninstantiatedTypeOptimizationForInterfaces = true;
                 })
-            .allowDiagnosticWarningMessages(
-                mode == Mode.INVOKE_UNVERIFIABLE_METHOD && !useInterface)
+            .allowDiagnosticWarningMessages(allowDiagnosticWarningMessages)
             .setMinApi(parameters.getApiLevel())
             .compile()
-            .assertAllWarningMessagesMatch(
-                equalTo(
-                    "The method `void UnverifiableClass.unverifiableMethod()` does not type check"
-                        + " and will be assumed to be unreachable."))
+            .applyIf(
+                allowDiagnosticWarningMessages,
+                result ->
+                    result.assertAllWarningMessagesMatch(
+                        equalTo(
+                            "The method `void UnverifiableClass.unverifiableMethod()` does not"
+                                + " type check and will be assumed to be unreachable.")))
             .run(parameters.getRuntime(), mainClass.name);
     checkTestRunResult(
         r8ResultWithUninstantiatedTypeOptimizationForInterfaces,
diff --git a/src/test/java/com/android/tools/r8/shaking/LibraryClassExtendingProgramClassSuperTest.java b/src/test/java/com/android/tools/r8/shaking/LibraryClassExtendingProgramClassSuperTest.java
index 584d3ae..c2c9f80 100644
--- a/src/test/java/com/android/tools/r8/shaking/LibraryClassExtendingProgramClassSuperTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/LibraryClassExtendingProgramClassSuperTest.java
@@ -70,7 +70,7 @@
             .addLibraryClasses(LibraryClass.class)
             .addProgramClasses(ProgramDirectSuper.class, ProgramIndirectSuper.class, Main.class)
             .addKeepMainRule(Main.class)
-            .applyIf(dontWarn, b -> b.addKeepRules("-dontwarn " + LibraryClass.class.getTypeName()))
+            .applyIf(dontWarn, b -> b.addDontWarn(LibraryClass.class))
             .setMinApi(parameters.getApiLevel())
             .addRunClasspathFiles(
                 compileToZip(
diff --git a/src/test/java/com/android/tools/r8/shaking/TreeShakingSpecificTest.java b/src/test/java/com/android/tools/r8/shaking/TreeShakingSpecificTest.java
index 63c9f40..2fac539 100644
--- a/src/test/java/com/android/tools/r8/shaking/TreeShakingSpecificTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/TreeShakingSpecificTest.java
@@ -3,23 +3,24 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.shaking;
 
+import static com.android.tools.r8.DiagnosticsMatcher.diagnosticType;
 import static com.android.tools.r8.ToolHelper.EXAMPLES_BUILD_DIR;
 import static com.android.tools.r8.ToolHelper.EXAMPLES_DIR;
+import static org.hamcrest.CoreMatchers.allOf;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
 
 import com.android.tools.r8.CompilationFailedException;
-import com.android.tools.r8.Diagnostic;
-import com.android.tools.r8.DiagnosticsHandler;
 import com.android.tools.r8.OutputMode;
-import com.android.tools.r8.R8;
 import com.android.tools.r8.R8Command;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersBuilder;
 import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.diagnostic.MissingDefinitionsDiagnostic;
 import java.io.BufferedReader;
 import java.io.IOException;
-import java.io.PrintStream;
 import java.io.StringReader;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
@@ -30,7 +31,6 @@
 import java.util.stream.Stream;
 import org.junit.Rule;
 import org.junit.Test;
-import org.junit.rules.ExpectedException;
 import org.junit.rules.TemporaryFolder;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -52,13 +52,16 @@
     parameters.assertNoneRuntime();
   }
 
-  private static final String VALID_PROGUARD_DIR = "src/test/proguard/valid/";
-
   @Rule
   public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest();
 
-  @Rule
-  public ExpectedException thrown = ExpectedException.none();
+  private Path getProgramFiles(String test) {
+    return Paths.get(EXAMPLES_BUILD_DIR, test + ".jar");
+  }
+
+  private byte[] getProgramDexFileData(String test) throws IOException {
+    return Files.readAllBytes(Paths.get(EXAMPLES_BUILD_DIR, test, "classes.dex"));
+  }
 
   private void finishBuild(R8Command.Builder builder, Path out, String test) throws IOException {
     Path input;
@@ -75,79 +78,77 @@
   @Test
   public void testIgnoreWarnings() throws Exception {
     // Generate R8 processed version without library option.
-    Path out = temp.getRoot().toPath();
     String test = "shaking2";
-    Path keepRules = Paths.get(EXAMPLES_DIR, test, "keep-rules.txt");
-    Path ignoreWarnings = Paths.get(VALID_PROGUARD_DIR, "ignorewarnings.flags");
-    R8Command.Builder builder = R8Command.builder()
-        .addProguardConfigurationFiles(keepRules, ignoreWarnings);
-    finishBuild(builder, out, test);
-    R8.run(builder.build());
+    testForR8(backend)
+        .applyIf(
+            backend.isCf(),
+            builder -> builder.addProgramFiles(getProgramFiles(test)),
+            builder -> builder.addProgramDexFileData(getProgramDexFileData(test)))
+        .addKeepRuleFiles(Paths.get(EXAMPLES_DIR, test, "keep-rules.txt"))
+        .addIgnoreWarnings()
+        .compile();
   }
 
   @Test(expected = CompilationFailedException.class)
   public void testMissingLibrary() throws Exception {
     // Generate R8 processed version without library option.
-    Path out = temp.getRoot().toPath();
     String test = "shaking2";
-    Path keepRules = Paths.get(EXAMPLES_DIR, test, "keep-rules.txt");
-    DiagnosticsHandler handler =
-        new DiagnosticsHandler() {
-          @Override
-          public void error(Diagnostic error) {
-            assertEquals(
-                "Compilation can't be completed because the following class is missing: "
-                    + "java.lang.Object.",
-                error.getDiagnosticMessage());
-          }
-        };
-    R8Command.Builder builder = R8Command.builder(handler)
-        .addProguardConfigurationFiles(keepRules);
-    finishBuild(builder, out, test);
-    R8.run(builder.build());
+    testForR8(backend)
+        .applyIf(
+            backend.isCf(),
+            builder -> builder.addProgramFiles(getProgramFiles(test)),
+            builder -> builder.addProgramDexFileData(getProgramDexFileData(test)))
+        .addLibraryFiles()
+        .addKeepRuleFiles(Paths.get(EXAMPLES_DIR, test, "keep-rules.txt"))
+        .allowDiagnosticErrorMessages()
+        .compileWithExpectedDiagnostics(
+            diagnostics -> {
+              diagnostics
+                  .assertOnlyErrors()
+                  .assertErrorsMatch(diagnosticType(MissingDefinitionsDiagnostic.class));
+
+              MissingDefinitionsDiagnostic diagnostic =
+                  (MissingDefinitionsDiagnostic) diagnostics.getErrors().get(0);
+              assertThat(
+                  diagnostic.getDiagnosticMessage(),
+                  allOf(
+                      containsString("Missing class java.io.PrintStream"),
+                      containsString("Missing class java.lang.Object"),
+                      containsString("Missing class java.lang.String"),
+                      containsString("Missing class java.lang.StringBuilder"),
+                      containsString("Missing class java.lang.System")));
+            });
   }
 
   @Test
-  public void testPrintMapping() throws Exception {
+  public void testPrintMapping() throws Throwable {
     // Generate R8 processed version without library option.
     String test = "shaking1";
-    Path out = temp.getRoot().toPath();
-    Path keepRules = Paths.get(EXAMPLES_DIR, test, "keep-rules.txt");
-
-    // Create a flags file in temp dir requesting dump of the mapping.
-    // The mapping file will be created alongside the flags file in temp dir.
-    Path printMapping = out.resolve("printmapping.flags");
-    try (PrintStream mapping = new PrintStream(printMapping.toFile())) {
-      mapping.println("-printmapping mapping.txt");
-    }
-
-    R8Command.Builder builder = R8Command.builder()
-        .addProguardConfigurationFiles(keepRules, printMapping);
-    // Turn off inlining, as we want the mapping that is printed to be stable.
-    finishBuild(builder, out, test);
-    if (backend == Backend.DEX) {
-      builder.addLibraryFiles(ToolHelper.getDefaultAndroidJar());
-    } else {
-      assert backend == Backend.CF;
-      builder.addLibraryFiles(ToolHelper.getJava8RuntimeJar());
-    }
-    ToolHelper.runR8(builder.build(), options -> options.enableInlining = false);
-
-    Path outputmapping = out.resolve("mapping.txt");
-    // Remove comments.
-    String actualMapping =
-        Stream.of(new String(Files.readAllBytes(outputmapping), StandardCharsets.UTF_8).split("\n"))
-            .filter(line -> !line.startsWith("#"))
-            .collect(Collectors.joining("\n"));
-    String refMapping =
-        new String(
-            Files.readAllBytes(
-                Paths.get(
-                    EXAMPLES_DIR,
-                    "shaking1",
-                    "print-mapping-" + backend.name().toLowerCase() + ".ref")),
-            StandardCharsets.UTF_8);
-    assertEquals(sorted(refMapping), sorted(actualMapping));
+    testForR8(backend)
+        .applyIf(
+            backend.isCf(),
+            builder -> builder.addProgramFiles(getProgramFiles(test)),
+            builder -> builder.addProgramDexFileData(getProgramDexFileData(test)))
+        .addKeepRuleFiles(Paths.get(EXAMPLES_DIR, test, "keep-rules.txt"))
+        .addOptionsModification(options -> options.enableInlining = false)
+        .compile()
+        .inspectProguardMap(
+            proguardMap -> {
+              // Remove comments.
+              String actualMapping =
+                  Stream.of(proguardMap.split("\n"))
+                      .filter(line -> !line.startsWith("#"))
+                      .collect(Collectors.joining("\n"));
+              String refMapping =
+                  new String(
+                      Files.readAllBytes(
+                          Paths.get(
+                              EXAMPLES_DIR,
+                              "shaking1",
+                              "print-mapping-" + backend.name().toLowerCase() + ".ref")),
+                      StandardCharsets.UTF_8);
+              assertEquals(sorted(refMapping), sorted(actualMapping));
+            });
   }
 
   private static String sorted(String str) {
diff --git a/src/test/java/com/android/tools/r8/shaking/annotations/LibraryAndMissingAnnotationsTest.java b/src/test/java/com/android/tools/r8/shaking/annotations/LibraryAndMissingAnnotationsTest.java
index 904c0cd..e78d675 100644
--- a/src/test/java/com/android/tools/r8/shaking/annotations/LibraryAndMissingAnnotationsTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/annotations/LibraryAndMissingAnnotationsTest.java
@@ -115,7 +115,7 @@
     if (includeOnLibraryPath) {
       t.addLibraryClasses(LibraryAnnotation.class);
     } else {
-      t.addKeepRules("-dontwarn " + LibraryAnnotation.class.getTypeName());
+      t.addDontWarn(LibraryAnnotation.class);
     }
     t.compile()
         .addRunClasspathFiles(compilationResults.apply(parameters))
diff --git a/src/test/java/com/android/tools/r8/shaking/annotations/ReflectiveAnnotationUseTest.java b/src/test/java/com/android/tools/r8/shaking/annotations/ReflectiveAnnotationUseTest.java
index 8eaee28..f102535 100644
--- a/src/test/java/com/android/tools/r8/shaking/annotations/ReflectiveAnnotationUseTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/annotations/ReflectiveAnnotationUseTest.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.shaking.annotations;
 
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
 import static org.hamcrest.CoreMatchers.containsString;
@@ -95,12 +96,13 @@
   public void b120951621_keepAll() throws Exception {
     CodeInspector inspector =
         testForR8(parameters.getBackend())
-            .addProgramFiles(compiledJars.getForConfiguration(kotlinc, targetVersion))
+            .addProgramFiles(
+                compiledJars.getForConfiguration(kotlinc, targetVersion),
+                getKotlinAnnotationJar(kotlinc))
             .addProgramFiles(getJavaJarFile(FOLDER))
             .addKeepMainRule(MAIN_CLASS_NAME)
             .addKeepRules(KEEP_ANNOTATIONS)
             .addKeepRules("-keep @interface " + ANNOTATION_NAME + " {", "  *;", "}")
-            .addDontWarnJetBrainsAnnotations()
             .allowDiagnosticWarningMessages()
             .minification(minify)
             .setMinApi(parameters.getApiLevel())
@@ -132,7 +134,9 @@
   public void b120951621_partiallyKeep() throws Exception {
     CodeInspector inspector =
         testForR8(parameters.getBackend())
-            .addProgramFiles(compiledJars.getForConfiguration(kotlinc, targetVersion))
+            .addProgramFiles(
+                compiledJars.getForConfiguration(kotlinc, targetVersion),
+                getKotlinAnnotationJar(kotlinc))
             .addProgramFiles(getJavaJarFile(FOLDER))
             .addKeepMainRule(MAIN_CLASS_NAME)
             .addKeepRules(KEEP_ANNOTATIONS)
@@ -140,7 +144,6 @@
                 "-keep,allowobfuscation @interface " + ANNOTATION_NAME + " {",
                 "  java.lang.String *f2();",
                 "}")
-            .addDontWarnJetBrainsAnnotations()
             .allowDiagnosticWarningMessages()
             .minification(minify)
             .setMinApi(parameters.getApiLevel())
@@ -173,11 +176,12 @@
   public void b120951621_keepAnnotation() throws Exception {
     CodeInspector inspector =
         testForR8(parameters.getBackend())
-            .addProgramFiles(compiledJars.getForConfiguration(kotlinc, targetVersion))
+            .addProgramFiles(
+                compiledJars.getForConfiguration(kotlinc, targetVersion),
+                getKotlinAnnotationJar(kotlinc))
             .addProgramFiles(getJavaJarFile(FOLDER))
             .addKeepMainRule(MAIN_CLASS_NAME)
             .addKeepRules(KEEP_ANNOTATIONS)
-            .addDontWarnJetBrainsAnnotations()
             .allowDiagnosticWarningMessages()
             .minification(minify)
             .setMinApi(parameters.getApiLevel())
@@ -210,10 +214,11 @@
   public void b120951621_noKeep() throws Exception {
     CodeInspector inspector =
         testForR8(parameters.getBackend())
-            .addProgramFiles(compiledJars.getForConfiguration(kotlinc, targetVersion))
+            .addProgramFiles(
+                compiledJars.getForConfiguration(kotlinc, targetVersion),
+                getKotlinAnnotationJar(kotlinc))
             .addProgramFiles(getJavaJarFile(FOLDER))
             .addKeepMainRule(MAIN_CLASS_NAME)
-            .addDontWarnJetBrainsAnnotations()
             .allowDiagnosticWarningMessages()
             .minification(minify)
             .setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/shaking/annotations/b137392797/B137392797.java b/src/test/java/com/android/tools/r8/shaking/annotations/b137392797/B137392797.java
index 073a085..ddc9a2b 100644
--- a/src/test/java/com/android/tools/r8/shaking/annotations/b137392797/B137392797.java
+++ b/src/test/java/com/android/tools/r8/shaking/annotations/b137392797/B137392797.java
@@ -4,13 +4,15 @@
 
 package com.android.tools.r8.shaking.annotations.b137392797;
 
+import static com.android.tools.r8.ToolHelper.getKotlinAnnotationJar;
+import static com.android.tools.r8.ToolHelper.getKotlinC_1_3_72;
+import static com.android.tools.r8.ToolHelper.getKotlinStdlibJar;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
 
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -63,8 +65,8 @@
             classWireFieldLabel(),
             classTest(defaultEnumValueInAnnotation))
         .addProgramClasses(TestClass.class)
-        .addClasspathFiles(ToolHelper.getKotlinStdlibJar(ToolHelper.getKotlinC_1_3_72()))
-        .addDontWarnJetBrainsAnnotations()
+        .addClasspathFiles(
+            getKotlinStdlibJar(getKotlinC_1_3_72()), getKotlinAnnotationJar(getKotlinC_1_3_72()))
         .addKeepClassAndMembersRules(
             "com.squareup.wire.WireField", "com.squareup.demo.myapplication.Test")
         .addKeepMainRule(TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/B152492625.java b/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/B152492625.java
index 8da32bc..1baeed5 100644
--- a/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/B152492625.java
+++ b/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/B152492625.java
@@ -110,7 +110,7 @@
     testForR8(parameters.getBackend())
         .addProgramClasses(TestClass.class, B.class)
         .addKeepMainRule(TestClass.class)
-        .applyIf(dontWarnObject, tb -> tb.addKeepRules("-dontwarn java.lang.Object"))
+        .applyIf(dontWarnObject, tb -> tb.addDontWarn(Object.class))
         .addKeepRules("-assumenosideeffects class " + B.class.getTypeName() + " { *; }")
         .setMinApi(parameters.getApiLevel())
         .allowDiagnosticWarningMessages(!dontWarnObject)
@@ -159,7 +159,7 @@
     testForR8(parameters.getBackend())
         .addProgramClasses(TestClass.class, B.class)
         .addKeepMainRule(TestClass.class)
-        .applyIf(dontWarnObject, tb -> tb.addKeepRules("-dontwarn java.lang.Object"))
+        .applyIf(dontWarnObject, tb -> tb.addDontWarn(Object.class))
         .apply(
             b ->
                 b.getBuilder().addProguardConfiguration(ImmutableList.of(starRule), starRuleOrigin))
@@ -181,7 +181,7 @@
     testForR8(parameters.getBackend())
         .addProgramClasses(TestClass.class, B.class)
         .addKeepMainRule(TestClass.class)
-        .applyIf(dontWarnObject, tb -> tb.addKeepRules("-dontwarn java.lang.Object"))
+        .applyIf(dontWarnObject, tb -> tb.addDontWarn(Object.class))
         .addKeepRules("-assumenosideeffects class " + B.class.getTypeName() + " { hash*(); }")
         .setMinApi(parameters.getApiLevel())
         .compile()
@@ -198,7 +198,7 @@
     testForR8(parameters.getBackend())
         .addProgramClasses(TestClass.class, B.class)
         .addKeepMainRule(TestClass.class)
-        .applyIf(dontWarnObject, tb -> tb.addKeepRules("-dontwarn java.lang.Object"))
+        .applyIf(dontWarnObject, tb -> tb.addDontWarn(Object.class))
         .addKeepRules("-assumenosideeffects class " + B.class.getTypeName() + " { <methods>; }")
         .setMinApi(parameters.getApiLevel())
         .allowDiagnosticWarningMessages(!dontWarnObject)
@@ -217,7 +217,7 @@
     testForR8(parameters.getBackend())
         .addProgramClasses(TestClass.class, B.class)
         .addKeepMainRule(TestClass.class)
-        .applyIf(dontWarnObject, tb -> tb.addKeepRules("-dontwarn java.lang.Object"))
+        .applyIf(dontWarnObject, tb -> tb.addDontWarn(Object.class))
         .addKeepRules("-assumenosideeffects class " + B.class.getTypeName() + " { *** w*(...); }")
         .setMinApi(parameters.getApiLevel())
         .allowDiagnosticWarningMessages(!dontWarnObject)
@@ -279,7 +279,7 @@
         .addProgramClasses(TestClass.class, B.class)
         .addKeepMainRule(TestClass.class)
         .addKeepRules("-assumenosideeffects class " + B.class.getTypeName() + " { *; }")
-        .addKeepRules("-dontwarn " + B152492625.class.getTypeName())
+        .addDontWarn(B152492625.class)
         .setMinApi(parameters.getApiLevel())
         .compile()
         .run(parameters.getRuntime(), TestClass.class)
@@ -295,7 +295,7 @@
         .addProgramClasses(TestClass.class, B.class)
         .addKeepMainRule(TestClass.class)
         .addKeepRules("-assumenosideeffects class java.lang.Object { void wait(); }")
-        .addKeepRules("-dontwarn " + B152492625.class.getTypeName())
+        .addDontWarn(B152492625.class)
         .setMinApi(parameters.getApiLevel())
         .compile()
         .inspect(inspector -> checkIfWaitIsInvokedFromMain(inspector, false))
diff --git a/src/test/java/com/android/tools/r8/shaking/b169045091/B169045091.java b/src/test/java/com/android/tools/r8/shaking/b169045091/B169045091.java
index 29a7280..1c6a438 100644
--- a/src/test/java/com/android/tools/r8/shaking/b169045091/B169045091.java
+++ b/src/test/java/com/android/tools/r8/shaking/b169045091/B169045091.java
@@ -83,8 +83,9 @@
     assumeTrue(parameters.useRuntimeAsNoneRuntime());
     AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-            buildClasses(getProgramClasses())
+            buildClassesWithTestingAnnotations(getProgramClasses())
                 .addClassProgramData(getWorldGreeterClassFileData())
+                .addLibraryFile(parameters.getDefaultRuntimeLibrary())
                 .build(),
             TestClass.class);
     AppInfoWithLiveness appInfo = appView.appInfo();
diff --git a/src/test/java/com/android/tools/r8/shaking/b169045091/NestMemberAccessibilityTest.java b/src/test/java/com/android/tools/r8/shaking/b169045091/NestMemberAccessibilityTest.java
index 62923a7..3d157d4 100644
--- a/src/test/java/com/android/tools/r8/shaking/b169045091/NestMemberAccessibilityTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/b169045091/NestMemberAccessibilityTest.java
@@ -21,6 +21,7 @@
 import com.android.tools.r8.shaking.b169045091.examples.NestHost;
 import com.android.tools.r8.shaking.b169045091.examples.NestHost.NestMember;
 import com.android.tools.r8.shaking.b169045091.examples.NonNestMember;
+import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.google.common.collect.ImmutableList;
 import java.nio.file.Path;
@@ -52,7 +53,7 @@
   public void testAccessibility() throws Exception {
     AppView<AppInfoWithLiveness> appView =
         computeAppViewWithLiveness(
-            buildClasses()
+            AndroidApp.builder()
                 .addProgramFiles(getProgramFiles())
                 .addClassProgramData(getNestHostClassFileData())
                 .build(),
diff --git a/src/test/java/com/android/tools/r8/smali/OutlineTest.java b/src/test/java/com/android/tools/r8/smali/OutlineTest.java
index efe3826..a7b67bf 100644
--- a/src/test/java/com/android/tools/r8/smali/OutlineTest.java
+++ b/src/test/java/com/android/tools/r8/smali/OutlineTest.java
@@ -1622,6 +1622,8 @@
         "    sput-object         v0, LA;->L:Ljava/util/Hashtable;",
         "    return-void");
 
+    builder.addClass("A");
+
     Consumer<InternalOptions> options = configureOutlineOptions(outline -> outline.threshold = 2);
 
     AndroidApp originalApplication = buildApplicationWithAndroidJar(builder);
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentMethodSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentMethodSubject.java
index ec133d7..9299e7f 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentMethodSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentMethodSubject.java
@@ -5,6 +5,7 @@
 package com.android.tools.r8.utils.codeinspector;
 
 import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.MethodAccessFlags;
 import com.android.tools.r8.graph.ProgramMethod;
@@ -20,6 +21,11 @@
   }
 
   @Override
+  public IRCode buildIR(AppView<?> appView) {
+    throw new Unreachable("Cannot build IR for an absent method");
+  }
+
+  @Override
   public boolean isPresent() {
     return false;
   }
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
index 17fffc3..dfccf5a 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
@@ -62,9 +62,13 @@
 
   @Override
   public IRCode buildIR() {
+    return buildIR(AppView.createForD8(AppInfo.createInitialAppInfo(codeInspector.application)));
+  }
+
+  @Override
+  public IRCode buildIR(AppView<?> appView) {
     assert codeInspector.application.options.programConsumer != null;
-    return getProgramMethod()
-        .buildIR(AppView.createForD8(AppInfo.createInitialAppInfo(codeInspector.application)));
+    return getProgramMethod().buildIR(appView);
   }
 
   @Override
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 536fa58..6803e16 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
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.utils.codeinspector;
 
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.MethodAccessFlags;
 import com.android.tools.r8.graph.ProgramMethod;
@@ -18,6 +19,8 @@
 
   public abstract IRCode buildIR();
 
+  public abstract IRCode buildIR(AppView<?> appView);
+
   public final boolean isAbsent() {
     return !isPresent();
   }
diff --git a/src/test/javaStubs/StringConcatFactory.java b/src/test/javaStubs/StringConcatFactory.java
new file mode 100644
index 0000000..9863857
--- /dev/null
+++ b/src/test/javaStubs/StringConcatFactory.java
@@ -0,0 +1,7 @@
+// Copyright (c) 2021, 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 java.lang.invoke;
+
+public class StringConcatFactory {}
diff --git a/src/test/javaStubs/VarHandle.java b/src/test/javaStubs/VarHandle.java
new file mode 100644
index 0000000..c12d32a
--- /dev/null
+++ b/src/test/javaStubs/VarHandle.java
@@ -0,0 +1,7 @@
+// Copyright (c) 2021, 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 java.lang.invoke;
+
+public class VarHandle {}
diff --git a/third_party/openjdk/desugar_jdk_libs.tar.gz.sha1 b/third_party/openjdk/desugar_jdk_libs.tar.gz.sha1
index 7b8d748..1fe619a 100644
--- a/third_party/openjdk/desugar_jdk_libs.tar.gz.sha1
+++ b/third_party/openjdk/desugar_jdk_libs.tar.gz.sha1
@@ -1 +1 @@
-2fdc16c4253420d7e240d5cf109bda5856984a8d
\ No newline at end of file
+653b4fe97b5dface6a31b9a6d94063a91a7f80be
\ No newline at end of file
diff --git a/tools/chrome_data.py b/tools/chrome_data.py
index 20ddb21..7649257 100644
--- a/tools/chrome_data.py
+++ b/tools/chrome_data.py
@@ -271,7 +271,8 @@
             { 'inputs': [os.path.join(V200520_MINIMAL_BASE, 'feature-7.jar')] },
             { 'inputs': [os.path.join(V200520_MINIMAL_BASE, 'feature-8.jar')] }
         ],
-        'pgconf': [os.path.join(V200520_MINIMAL_BASE, 'proguard.config')],
+        'pgconf': [os.path.join(V200520_MINIMAL_BASE, 'proguard.config'),
+                   utils.IGNORE_WARNINGS_RULES],
         'libraries': [os.path.join(V200520_MINIMAL_BASE, 'library.jar')],
         'min-api': ANDROID_N_API
     },
diff --git a/tools/gmail_data.py b/tools/gmail_data.py
index 4683458..4d1b250 100644
--- a/tools/gmail_data.py
+++ b/tools/gmail_data.py
@@ -27,7 +27,8 @@
     },
     'deploy' : {
       'inputs': ['%s_deploy.jar' % V170604_16_PREFIX],
-      'pgconf': ['%s_proguard.config' % V170604_16_PREFIX],
+      'pgconf': ['%s_proguard.config' % V170604_16_PREFIX,
+                 utils.IGNORE_WARNINGS_RULES],
     },
     'proguarded' : {
       'inputs': ['%s_proguard.jar' % V170604_16_PREFIX],
@@ -47,7 +48,8 @@
       'inputs': ['%s_deploy.jar' % V180826_15_PREFIX],
       'pgconf': [
           '%s_proguard.config' % V180826_15_PREFIX,
-          '%s/proguardsettings/Gmail_proguard.config' % utils.THIRD_PARTY],
+          '%s/proguardsettings/Gmail_proguard.config' % utils.THIRD_PARTY,
+          utils.IGNORE_WARNINGS_RULES],
       'min-api' : ANDROID_L_API,
       'allow-type-errors' : 1,
     },
diff --git a/tools/gmscore_data.py b/tools/gmscore_data.py
index 44971c1..bef5ba3 100644
--- a/tools/gmscore_data.py
+++ b/tools/gmscore_data.py
@@ -77,7 +77,8 @@
       'pgmap': '%s_proguard.map' % V9_PREFIX,
     },
     'deploy' : {
-      'pgconf': ['%s_proguard.config' % V9_PREFIX],
+      'pgconf': ['%s_proguard.config' % V9_PREFIX,
+                 utils.IGNORE_WARNINGS_RULES],
       'inputs': ['%s_deploy.jar' % V9_PREFIX],
       'min-api' : ANDROID_L_API,
     },
@@ -97,7 +98,8 @@
     },
     'deploy' : {
       'inputs': ['%s_deploy.jar' % V10_PREFIX],
-      'pgconf': ['%s_proguard.config' % V10_PREFIX],
+      'pgconf': ['%s_proguard.config' % V10_PREFIX,
+                 utils.IGNORE_WARNINGS_RULES],
       'min-api' : ANDROID_L_API,
     },
     'proguarded' : {
@@ -112,7 +114,8 @@
       'inputs': ['%s_deploy.jar' % LATEST_PREFIX],
       'pgconf': [
           '%s_proguard.config' % LATEST_PREFIX,
-          '%s/proguardsettings/GmsCore_proguard.config' % utils.THIRD_PARTY],
+          '%s/proguardsettings/GmsCore_proguard.config' % utils.THIRD_PARTY,
+          utils.IGNORE_WARNINGS_RULES],
       'min-api' : ANDROID_L_API,
     },
     'proguarded' : {
diff --git a/tools/nest_data.py b/tools/nest_data.py
index a87761d..5724e43 100644
--- a/tools/nest_data.py
+++ b/tools/nest_data.py
@@ -28,7 +28,8 @@
       'pgconf': [
           os.path.join(V20180926_BASE, 'proguard', 'proguard.cfg'),
           os.path.join(V20180926_BASE, 'proguard', 'proguard-no-optimizations.cfg'),
-          os.path.join(V20180926_BASE, 'proguard', 'proguard-ignore-warnings.cfg')],
+          os.path.join(V20180926_BASE, 'proguard', 'proguard-ignore-warnings.cfg'),
+          utils.IGNORE_WARNINGS_RULES],
       # Build for native multi dex
       'min-api' : ANDROID_L_API,
     }
diff --git a/tools/r8_release.py b/tools/r8_release.py
index 783b30d..d356586 100755
--- a/tools/r8_release.py
+++ b/tools/r8_release.py
@@ -577,7 +577,7 @@
   # [INFO] 06/19/2020 09:35:12 CEST: Release ID = 9171d015-18f6-4a90-9984-1c362589dc1b
   # [INFO] 06/19/2020 09:35:12 CEST: Stage Path = /bigstore/studio_staging/maven2/sgjesse/9171d015-18f6-4a90-9984-1c362589dc1b
 
-  matches = GMAVEN_PUBLISH_STAGE_RELEASE_ID_PATTERN.findall(output)
+  matches = GMAVEN_PUBLISH_STAGE_RELEASE_ID_PATTERN.findall(output.decode("utf-8"))
   if matches == None or len(matches) > 1:
     print("Could not determine the release ID from the gmaven_publisher " +
           "output. Expected a line with 'Release ID = <release id>'.")
diff --git a/tools/utils.py b/tools/utils.py
index dcfa4f8..8b7acb7 100644
--- a/tools/utils.py
+++ b/tools/utils.py
@@ -63,7 +63,7 @@
 DESUGAR_CONFIGURATION = os.path.join(
       'src', 'library_desugar', 'desugar_jdk_libs.json')
 DESUGAR_IMPLEMENTATION = os.path.join(
-      'third_party', 'openjdk', 'desugar_jdk_libs', 'libjava.jar')
+      'third_party', 'openjdk', 'desugar_jdk_libs', 'desugar_jdk_libs.jar')
 DESUGAR_CONFIGURATION_MAVEN_ZIP = os.path.join(
   LIBS, 'desugar_jdk_libs_configuration.zip')
 GENERATED_LICENSE = os.path.join(GENERATED_LICENSE_DIR, 'LICENSE')
@@ -82,6 +82,7 @@
 BAZEL_SHA_FILE = os.path.join(THIRD_PARTY, 'bazel.tar.gz.sha1')
 BAZEL_TOOL = os.path.join(THIRD_PARTY, 'bazel')
 JAVA8_SHA_FILE = os.path.join(THIRD_PARTY, 'openjdk', 'jdk8', 'linux-x86.tar.gz.sha1')
+IGNORE_WARNINGS_RULES = os.path.join(REPO_ROOT, 'src', 'test', 'ignorewarnings.rules')
 
 ANDROID_HOME_ENVIROMENT_NAME = "ANDROID_HOME"
 ANDROID_TOOLS_VERSION_ENVIRONMENT_NAME = "ANDROID_TOOLS_VERSION"
diff --git a/tools/youtube_data.py b/tools/youtube_data.py
index 46b0b9d..eafe5bb 100644
--- a/tools/youtube_data.py
+++ b/tools/youtube_data.py
@@ -52,7 +52,8 @@
     'deploy' : {
       'inputs': ['%s_deploy.jar' % V12_10_PREFIX],
       'pgconf': ['%s_proguard.config' % V12_10_PREFIX,
-                 '%s/proguardsettings/YouTubeRelease_proguard.config' % utils.THIRD_PARTY],
+                 '%s/proguardsettings/YouTubeRelease_proguard.config' % utils.THIRD_PARTY,
+                 utils.IGNORE_WARNINGS_RULES],
       'min-api' : ANDROID_L_API,
     }
     # The 'proguarded' version cannot be handled by D8/R8 because there are
@@ -74,7 +75,8 @@
     'deploy' : {
       'inputs': ['%s_deploy.jar' % V12_17_PREFIX],
       'pgconf': ['%s_proguard.config' % V12_17_PREFIX,
-                 '%s/proguardsettings/YouTubeRelease_proguard.config' % utils.THIRD_PARTY],
+                 '%s/proguardsettings/YouTubeRelease_proguard.config' % utils.THIRD_PARTY,
+                 utils.IGNORE_WARNINGS_RULES],
       'min-api' : ANDROID_L_API,
     },
     'proguarded' : {
@@ -94,7 +96,8 @@
       'inputs': ['%s_deploy.jar' % V12_22_PREFIX],
       'pgconf': [
           '%s_proguard.config' % V12_22_PREFIX,
-          '%s/proguardsettings/YouTubeRelease_proguard.config' % utils.THIRD_PARTY],
+          '%s/proguardsettings/YouTubeRelease_proguard.config' % utils.THIRD_PARTY,
+          utils.IGNORE_WARNINGS_RULES],
       'maindexrules' : [
           os.path.join(V12_22_BASE, 'mainDexClasses.rules'),
           os.path.join(V12_22_BASE, 'main-dex-classes-release.cfg'),
@@ -117,7 +120,8 @@
       'inputs': ['%s_deploy.jar' % V13_37_PREFIX],
       'pgconf': [
           '%s_proguard.config' % V13_37_PREFIX,
-          '%s/proguardsettings/YouTubeRelease_proguard.config' % utils.THIRD_PARTY],
+          '%s/proguardsettings/YouTubeRelease_proguard.config' % utils.THIRD_PARTY,
+          utils.IGNORE_WARNINGS_RULES],
       # Build for native multi dex, as Currently R8 cannot meet the main-dex
       # constraints.
       #'maindexrules' : [
@@ -143,7 +147,8 @@
       'inputs': ['%s_deploy.jar' % V14_19_PREFIX],
       'pgconf': [
           '%s_proguard.config' % V14_19_PREFIX,
-          '%s/proguardsettings/YouTubeRelease_proguard.config' % utils.THIRD_PARTY],
+          '%s/proguardsettings/YouTubeRelease_proguard.config' % utils.THIRD_PARTY,
+          utils.IGNORE_WARNINGS_RULES],
       'maindexrules' : [
           os.path.join(V14_19_BASE, 'mainDexClasses.rules'),
           os.path.join(V14_19_BASE, 'main-dex-classes-release-optimized.pgcfg'),
@@ -172,7 +177,8 @@
       'libraries' : [os.path.join(V14_44_BASE, 'legacy_YouTubeRelease_combined_library_jars.jar')],
       'pgconf': [
           '%s_proguard.config' % V14_44_PREFIX,
-          '%s/proguardsettings/YouTubeRelease_proguard.config' % utils.THIRD_PARTY],
+          '%s/proguardsettings/YouTubeRelease_proguard.config' % utils.THIRD_PARTY,
+          utils.IGNORE_WARNINGS_RULES],
       'maindexrules' : [
           os.path.join(V14_44_BASE, 'mainDexClasses.rules'),
           os.path.join(V14_44_BASE, 'main-dex-classes-release-optimized.pgcfg'),
@@ -202,7 +208,8 @@
       'pgconf': [
           '%s_proguard.config' % V15_08_PREFIX,
           '%s_proto_safety.pgcfg' % V15_08_PREFIX,
-          '%s/proguardsettings/YouTubeRelease_proguard.config' % utils.THIRD_PARTY],
+          '%s/proguardsettings/YouTubeRelease_proguard.config' % utils.THIRD_PARTY,
+          utils.IGNORE_WARNINGS_RULES],
       'maindexrules' : [
           os.path.join(V15_08_BASE, 'mainDexClasses.rules'),
           os.path.join(V15_08_BASE, 'main-dex-classes-release-optimized.pgcfg'),
@@ -231,7 +238,8 @@
       'libraries' : [os.path.join(V15_09_BASE, 'legacy_YouTubeRelease_combined_library_jars.jar')],
       'pgconf': [
           '%s_proguard.config' % V15_09_PREFIX,
-          '%s/proguardsettings/YouTubeRelease_proguard.config' % utils.THIRD_PARTY],
+          '%s/proguardsettings/YouTubeRelease_proguard.config' % utils.THIRD_PARTY,
+          utils.IGNORE_WARNINGS_RULES],
       'maindexrules' : [
           os.path.join(V15_09_BASE, 'mainDexClasses.rules'),
           os.path.join(V15_09_BASE, 'main-dex-classes-release-optimized.pgcfg'),
@@ -261,7 +269,8 @@
       'pgconf': [
           '%s_proguard.config' % V15_33_PREFIX,
           '%s_proguard_missing_classes.config' % V15_33_PREFIX,
-          '%s/proguardsettings/YouTubeRelease_proguard.config' % utils.THIRD_PARTY],
+          '%s/proguardsettings/YouTubeRelease_proguard.config' % utils.THIRD_PARTY,
+          utils.IGNORE_WARNINGS_RULES],
       'maindexrules' : [
           os.path.join(V15_33_BASE, 'mainDexClasses.rules'),
           os.path.join(V15_33_BASE, 'main-dex-classes-release-optimized.pgcfg'),