[Retrace] Add support for rewriting frames based on json comments

Change-Id: I2d02387617a2350cb82abf895ccf3dbcbf9f5d82
diff --git a/src/main/java/com/android/tools/r8/naming/ClassNamingForNameMapper.java b/src/main/java/com/android/tools/r8/naming/ClassNamingForNameMapper.java
index 7a0a20c..00028ff 100644
--- a/src/main/java/com/android/tools/r8/naming/ClassNamingForNameMapper.java
+++ b/src/main/java/com/android/tools/r8/naming/ClassNamingForNameMapper.java
@@ -8,8 +8,10 @@
 import com.android.tools.r8.naming.MemberNaming.Signature;
 import com.android.tools.r8.naming.MemberNaming.Signature.SignatureKind;
 import com.android.tools.r8.naming.mappinginformation.MappingInformation;
+import com.android.tools.r8.naming.mappinginformation.RewriteFrameMappingInformation;
 import com.android.tools.r8.utils.ChainableStringConsumer;
 import com.android.tools.r8.utils.ThrowingConsumer;
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Maps;
 import java.util.ArrayList;
@@ -453,6 +455,16 @@
       return false;
     }
 
+    public List<RewriteFrameMappingInformation> getRewriteFrameMappingInformation() {
+      ImmutableList.Builder<RewriteFrameMappingInformation> builder = ImmutableList.builder();
+      for (MappingInformation mappingInformation : additionalMappingInfo) {
+        if (mappingInformation.isRewriteFrameMappingInformation()) {
+          builder.add(mappingInformation.asRewriteFrameMappingInformation());
+        }
+      }
+      return builder.build();
+    }
+
     public int getOriginalLineNumber(int lineNumberAfterMinification) {
       if (minifiedRange == null) {
         // General mapping without concrete line numbers: "a() -> b"
diff --git a/src/main/java/com/android/tools/r8/naming/mappinginformation/MappingInformation.java b/src/main/java/com/android/tools/r8/naming/mappinginformation/MappingInformation.java
index 13bcfe9..9232500 100644
--- a/src/main/java/com/android/tools/r8/naming/mappinginformation/MappingInformation.java
+++ b/src/main/java/com/android/tools/r8/naming/mappinginformation/MappingInformation.java
@@ -30,6 +30,10 @@
     return false;
   }
 
+  public boolean isRewriteFrameMappingInformation() {
+    return false;
+  }
+
   public boolean isCompilerSynthesizedMappingInformation() {
     return false;
   }
@@ -50,6 +54,10 @@
     return null;
   }
 
+  public RewriteFrameMappingInformation asRewriteFrameMappingInformation() {
+    return null;
+  }
+
   public abstract boolean allowOther(MappingInformation information);
 
   public static void fromJsonObject(
@@ -102,6 +110,9 @@
       case CompilerSynthesizedMappingInformation.ID:
         CompilerSynthesizedMappingInformation.deserialize(version, onMappingInfo);
         return;
+      case RewriteFrameMappingInformation.ID:
+        RewriteFrameMappingInformation.deserialize(version, object, onMappingInfo);
+        return;
       default:
         diagnosticsHandler.info(MappingInformationDiagnostics.noHandlerFor(lineNumber, id));
         UnknownJsonMappingInformation.deserialize(id, object, onMappingInfo);
diff --git a/src/main/java/com/android/tools/r8/naming/mappinginformation/RewriteFrameMappingInformation.java b/src/main/java/com/android/tools/r8/naming/mappinginformation/RewriteFrameMappingInformation.java
new file mode 100644
index 0000000..150dc45
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/naming/mappinginformation/RewriteFrameMappingInformation.java
@@ -0,0 +1,262 @@
+// 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.naming.mappinginformation;
+
+import com.android.tools.r8.errors.CompilationError;
+import com.android.tools.r8.errors.Unimplemented;
+import com.android.tools.r8.naming.MapVersion;
+import com.android.tools.r8.retrace.internal.RetraceStackTraceContextImpl;
+import com.android.tools.r8.retrace.internal.RetraceStackTraceCurrentEvaluationInformation;
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.google.common.collect.ImmutableList;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonPrimitive;
+import java.util.List;
+import java.util.function.Consumer;
+
+public class RewriteFrameMappingInformation extends MappingInformation {
+
+  public static final MapVersion SUPPORTED_VERSION = MapVersion.MAP_VERSION_EXPERIMENTAL;
+  public static final String ID = "com.android.tools.r8.rewriteframe";
+  private static final String CONDITIONS_KEY = "conditions";
+  private static final String ACTIONS_KEY = "actions";
+
+  private final List<Condition> conditions;
+  private final List<RewriteAction> actions;
+
+  private RewriteFrameMappingInformation(List<Condition> conditions, List<RewriteAction> actions) {
+    this.conditions = conditions;
+    this.actions = actions;
+  }
+
+  public List<Condition> getConditions() {
+    return conditions;
+  }
+
+  public List<RewriteAction> getActions() {
+    return actions;
+  }
+
+  @Override
+  public String getId() {
+    return ID;
+  }
+
+  @Override
+  public String serialize() {
+    JsonObject object = new JsonObject();
+    object.add(MAPPING_ID_KEY, new JsonPrimitive(ID));
+    JsonArray conditionsArray = new JsonArray();
+    conditions.forEach(condition -> conditionsArray.add(condition.serialize()));
+    object.add(CONDITIONS_KEY, conditionsArray);
+    JsonArray actionsArray = new JsonArray();
+    actions.forEach(action -> actionsArray.add(action.serialize()));
+    object.add(ACTIONS_KEY, actionsArray);
+    return object.toString();
+  }
+
+  public static boolean isSupported(MapVersion version) {
+    return version.isGreaterThanOrEqualTo(SUPPORTED_VERSION);
+  }
+
+  @Override
+  public boolean allowOther(MappingInformation information) {
+    return !information.isRewriteFrameMappingInformation();
+  }
+
+  public static void deserialize(
+      MapVersion mapVersion, JsonObject object, Consumer<MappingInformation> onMappingInfo) {
+    if (!isSupported(mapVersion)) {
+      return;
+    }
+    ImmutableList.Builder<Condition> conditions = ImmutableList.builder();
+    object
+        .get(CONDITIONS_KEY)
+        .getAsJsonArray()
+        .forEach(
+            element -> {
+              conditions.add(Condition.deserialize(element));
+            });
+    ImmutableList.Builder<RewriteAction> actions = ImmutableList.builder();
+    object
+        .get(ACTIONS_KEY)
+        .getAsJsonArray()
+        .forEach(element -> actions.add(RewriteAction.deserialize(element)));
+    onMappingInfo.accept(new RewriteFrameMappingInformation(conditions.build(), actions.build()));
+  }
+
+  @Override
+  public boolean isRewriteFrameMappingInformation() {
+    return true;
+  }
+
+  @Override
+  public RewriteFrameMappingInformation asRewriteFrameMappingInformation() {
+    return this;
+  }
+
+  public abstract static class Condition {
+
+    protected abstract JsonPrimitive serialize();
+
+    private static Condition deserialize(JsonElement element) {
+      String elementString = element.getAsString();
+      int argIndex = elementString.indexOf('(');
+      if (argIndex < 1 || !elementString.endsWith(")")) {
+        throw new CompilationError("Invalid formatted condition: " + elementString);
+      }
+      String functionName = elementString.substring(0, argIndex);
+      String contents = elementString.substring(argIndex + 1, elementString.length() - 1);
+      if (ThrowsCondition.FUNCTION_NAME.equals(functionName)) {
+        return ThrowsCondition.deserialize(contents);
+      }
+      throw new Unimplemented("Unexpected condition: " + elementString);
+    }
+
+    public boolean isThrowsCondition() {
+      return false;
+    }
+
+    public ThrowsCondition asThrowsCondition() {
+      return null;
+    }
+
+    public abstract boolean evaluate(RetraceStackTraceContextImpl context);
+  }
+
+  public static class ThrowsCondition extends Condition {
+
+    static final String FUNCTION_NAME = "throws";
+
+    private final String descriptor;
+
+    private ThrowsCondition(String descriptor) {
+      this.descriptor = descriptor;
+    }
+
+    @Override
+    protected JsonPrimitive serialize() {
+      return new JsonPrimitive(FUNCTION_NAME + "(" + asThrowsCondition().getDescriptor() + ")");
+    }
+
+    @Override
+    public boolean isThrowsCondition() {
+      return true;
+    }
+
+    public String getDescriptor() {
+      return descriptor;
+    }
+
+    @Override
+    public ThrowsCondition asThrowsCondition() {
+      return this;
+    }
+
+    @Override
+    public boolean evaluate(RetraceStackTraceContextImpl context) {
+      return context.getSeenException() != null
+          && context.getSeenException().getDescriptor().equals(descriptor);
+    }
+
+    public static ThrowsCondition deserialize(String conditionString) {
+      if (!DescriptorUtils.isClassDescriptor(conditionString)) {
+        throw new CompilationError("Unexpected throws-descriptor: " + conditionString);
+      }
+      return new ThrowsCondition(conditionString);
+    }
+  }
+
+  public abstract static class RewriteAction {
+
+    static final String REMOVE_INNER_FRAMES_SERIALIZED_NAME = "removeInnerFrames";
+
+    private static final String FUNCTION_KEY = "function";
+    private static final String ARGUMENTS_KEY = "arguments";
+
+    abstract String serializeName();
+
+    abstract JsonArray getArguments();
+
+    JsonElement serialize() {
+      JsonObject jsonObject = new JsonObject();
+      jsonObject.add(FUNCTION_KEY, new JsonPrimitive(serializeName()));
+      jsonObject.add(ARGUMENTS_KEY, getArguments());
+      return jsonObject;
+    }
+
+    private static RewriteAction deserialize(JsonElement element) {
+      String functionString = element.getAsString();
+      int startArgsIndex = functionString.indexOf("(");
+      int endArgsIndex = functionString.indexOf(")");
+      if (endArgsIndex <= startArgsIndex) {
+        throw new Unimplemented("Unexpected action: " + functionString);
+      }
+      String functionName = functionString.substring(0, startArgsIndex);
+      String args = functionString.substring(startArgsIndex + 1, endArgsIndex);
+      if (REMOVE_INNER_FRAMES_SERIALIZED_NAME.equals(functionName)) {
+        return RemoveInnerFramesAction.create(args);
+      }
+      assert false : "Unknown function " + functionName;
+      throw new Unimplemented("Unexpected action: " + functionName);
+    }
+
+    public boolean isRemoveInnerFramesAction() {
+      return false;
+    }
+
+    public RemoveInnerFramesAction asRemoveInnerFramesRewriteAction() {
+      return null;
+    }
+
+    public abstract void evaluate(RetraceStackTraceCurrentEvaluationInformation.Builder builder);
+  }
+
+  public static class RemoveInnerFramesAction extends RewriteAction {
+
+    private final int numberOfFrames;
+
+    public RemoveInnerFramesAction(int numberOfFrames) {
+      this.numberOfFrames = numberOfFrames;
+    }
+
+    public int getNumberOfFrames() {
+      return numberOfFrames;
+    }
+
+    @Override
+    String serializeName() {
+      return REMOVE_INNER_FRAMES_SERIALIZED_NAME;
+    }
+
+    @Override
+    JsonArray getArguments() {
+      JsonArray arguments = new JsonArray();
+      arguments.add(numberOfFrames);
+      return arguments;
+    }
+
+    static RemoveInnerFramesAction create(String args) {
+      return new RemoveInnerFramesAction(Integer.parseInt(args));
+    }
+
+    @Override
+    public boolean isRemoveInnerFramesAction() {
+      return true;
+    }
+
+    @Override
+    public RemoveInnerFramesAction asRemoveInnerFramesRewriteAction() {
+      return this;
+    }
+
+    @Override
+    public void evaluate(RetraceStackTraceCurrentEvaluationInformation.Builder builder) {
+      builder.incrementRemoveInnerFramesCount(numberOfFrames);
+    }
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceClassElement.java b/src/main/java/com/android/tools/r8/retrace/RetraceClassElement.java
index 43bf109..6e61118 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceClassElement.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceClassElement.java
@@ -31,4 +31,6 @@
   RetraceFrameResult lookupFrame(Optional<Integer> position, MethodReference methodReference);
 
   RetraceUnknownJsonMappingInformationResult getUnknownJsonMappingInformation();
+
+  RetraceStackTraceContext getContextWhereClassWasThrown();
 }
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceElement.java b/src/main/java/com/android/tools/r8/retrace/RetraceElement.java
index 63d40db..55de558 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceElement.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceElement.java
@@ -16,6 +16,4 @@
   R getRetraceResultContext();
 
   boolean isCompilerSynthesized();
-
-  RetraceStackTraceContext getContext();
 }
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceFrameElement.java b/src/main/java/com/android/tools/r8/retrace/RetraceFrameElement.java
index b114240..f2ad4e7 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceFrameElement.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceFrameElement.java
@@ -18,9 +18,12 @@
 
   void visitAllFrames(BiConsumer<RetracedMethodReference, Integer> consumer);
 
-  void visitNonCompilerSynthesizedFrames(BiConsumer<RetracedMethodReference, Integer> consumer);
+  void visitRewrittenFrames(
+      RetraceStackTraceContext context, BiConsumer<RetracedMethodReference, Integer> consumer);
 
   RetracedSourceFile getSourceFile(RetracedClassMemberReference frame);
 
   List<? extends RetracedMethodReference> getOuterFrames();
+
+  RetraceStackTraceContext getContext();
 }
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceInvalidRewriteFrameDiagnostics.java b/src/main/java/com/android/tools/r8/retrace/RetraceInvalidRewriteFrameDiagnostics.java
new file mode 100644
index 0000000..ace1b86
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceInvalidRewriteFrameDiagnostics.java
@@ -0,0 +1,46 @@
+// 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.retrace;
+
+import com.android.tools.r8.Diagnostic;
+import com.android.tools.r8.Keep;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.position.Position;
+
+@Keep
+public class RetraceInvalidRewriteFrameDiagnostics implements Diagnostic {
+
+  private final int numberOfFramesToRemove;
+  private final String method;
+
+  private RetraceInvalidRewriteFrameDiagnostics(int numberOfFramesToRemove, String method) {
+    this.numberOfFramesToRemove = numberOfFramesToRemove;
+    this.method = method;
+  }
+
+  @Override
+  public Origin getOrigin() {
+    return Origin.unknown();
+  }
+
+  @Override
+  public Position getPosition() {
+    return Position.UNKNOWN;
+  }
+
+  @Override
+  public String getDiagnosticMessage() {
+    return "Cannot remove "
+        + numberOfFramesToRemove
+        + " frames from the retraced output of "
+        + method
+        + " because it exceeds the number of retraced frames";
+  }
+
+  public static RetraceInvalidRewriteFrameDiagnostics create(
+      int numberOfFramesToRemove, String method) {
+    return new RetraceInvalidRewriteFrameDiagnostics(numberOfFramesToRemove, method);
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/retrace/RetraceStackTraceContext.java b/src/main/java/com/android/tools/r8/retrace/RetraceStackTraceContext.java
index 9004cc1..e87ff95 100644
--- a/src/main/java/com/android/tools/r8/retrace/RetraceStackTraceContext.java
+++ b/src/main/java/com/android/tools/r8/retrace/RetraceStackTraceContext.java
@@ -11,6 +11,6 @@
 public interface RetraceStackTraceContext {
 
   static RetraceStackTraceContext getInitialContext() {
-    return new RetraceStackTraceContextImpl();
+    return RetraceStackTraceContextImpl.builder().build();
   }
 }
diff --git a/src/main/java/com/android/tools/r8/retrace/Retracer.java b/src/main/java/com/android/tools/r8/retrace/Retracer.java
index c609e44..bd865a8 100644
--- a/src/main/java/com/android/tools/r8/retrace/Retracer.java
+++ b/src/main/java/com/android/tools/r8/retrace/Retracer.java
@@ -33,4 +33,9 @@
       ProguardMapProducer proguardMapProducer, DiagnosticsHandler diagnosticsHandler) {
     return RetracerImpl.create(proguardMapProducer, diagnosticsHandler, false);
   }
+
+  static Retracer createExperimental(
+      ProguardMapProducer proguardMapProducer, DiagnosticsHandler diagnosticsHandler) {
+    return RetracerImpl.create(proguardMapProducer, diagnosticsHandler, true);
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetraceClassResultImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetraceClassResultImpl.java
index 54c90e6..0f165cf 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/RetraceClassResultImpl.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetraceClassResultImpl.java
@@ -20,7 +20,6 @@
 import com.android.tools.r8.retrace.RetraceStackTraceContext;
 import com.android.tools.r8.retrace.RetraceUnknownJsonMappingInformationResult;
 import com.android.tools.r8.retrace.RetracedSourceFile;
-import com.android.tools.r8.retrace.Retracer;
 import com.android.tools.r8.utils.ListUtils;
 import com.android.tools.r8.utils.Pair;
 import com.google.common.collect.ImmutableList;
@@ -220,7 +219,7 @@
         RetraceClassResultImpl classResult,
         List<Pair<RetraceClassElementImpl, T>> mappings,
         D definition,
-        Retracer retracer);
+        RetracerImpl retracer);
   }
 
   public static class RetraceClassElementImpl implements RetraceClassElement {
@@ -273,9 +272,10 @@
     }
 
     @Override
-    public RetraceStackTraceContext getContext() {
-      // TODO(b/197936862): Extend the context to enable tracking information.
-      return RetraceStackTraceContext.getInitialContext();
+    public RetraceStackTraceContext getContextWhereClassWasThrown() {
+      return RetraceStackTraceContextImpl.builder()
+          .setSeenException(getRetracedClass().getClassReference())
+          .build();
     }
 
     @Override
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetraceFieldResultImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetraceFieldResultImpl.java
index b536bea..38667c4 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/RetraceFieldResultImpl.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetraceFieldResultImpl.java
@@ -10,7 +10,6 @@
 import com.android.tools.r8.references.Reference;
 import com.android.tools.r8.retrace.RetraceFieldElement;
 import com.android.tools.r8.retrace.RetraceFieldResult;
-import com.android.tools.r8.retrace.RetraceStackTraceContext;
 import com.android.tools.r8.retrace.RetracedSourceFile;
 import com.android.tools.r8.retrace.Retracer;
 import com.android.tools.r8.retrace.internal.RetraceClassResultImpl.RetraceClassElementImpl;
@@ -114,11 +113,6 @@
     }
 
     @Override
-    public RetraceStackTraceContext getContext() {
-      return RetraceStackTraceContext.getInitialContext();
-    }
-
-    @Override
     public boolean isUnknown() {
       return fieldReference.isUnknown();
     }
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetraceFrameResultImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetraceFrameResultImpl.java
index 2f79d8e..9bee685 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/RetraceFrameResultImpl.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetraceFrameResultImpl.java
@@ -6,16 +6,17 @@
 
 import static com.android.tools.r8.retrace.internal.RetraceUtils.methodReferenceFromMappedRange;
 
+import com.android.tools.r8.DiagnosticsHandler;
 import com.android.tools.r8.naming.ClassNamingForNameMapper.MappedRange;
 import com.android.tools.r8.naming.Range;
 import com.android.tools.r8.references.MethodReference;
 import com.android.tools.r8.retrace.RetraceFrameElement;
 import com.android.tools.r8.retrace.RetraceFrameResult;
+import com.android.tools.r8.retrace.RetraceInvalidRewriteFrameDiagnostics;
 import com.android.tools.r8.retrace.RetraceStackTraceContext;
 import com.android.tools.r8.retrace.RetracedClassMemberReference;
 import com.android.tools.r8.retrace.RetracedMethodReference;
 import com.android.tools.r8.retrace.RetracedSourceFile;
-import com.android.tools.r8.retrace.Retracer;
 import com.android.tools.r8.retrace.internal.RetraceClassResultImpl.RetraceClassElementImpl;
 import com.android.tools.r8.utils.ListUtils;
 import com.android.tools.r8.utils.OptionalBool;
@@ -35,7 +36,7 @@
   private final MethodDefinition methodDefinition;
   private final Optional<Integer> obfuscatedPosition;
   private final List<Pair<RetraceClassElementImpl, List<MappedRange>>> mappedRanges;
-  private final Retracer retracer;
+  private final RetracerImpl retracer;
 
   private OptionalBool isAmbiguousCache = OptionalBool.UNKNOWN;
 
@@ -44,7 +45,7 @@
       List<Pair<RetraceClassElementImpl, List<MappedRange>>> mappedRanges,
       MethodDefinition methodDefinition,
       Optional<Integer> obfuscatedPosition,
-      Retracer retracer) {
+      RetracerImpl retracer) {
     this.classResult = classResult;
     this.methodDefinition = methodDefinition;
     this.obfuscatedPosition = obfuscatedPosition;
@@ -93,7 +94,8 @@
                             methodDefinition.substituteHolder(
                                 classElement.getRetracedClass().getClassReference())),
                         ImmutableList.of(),
-                        obfuscatedPosition));
+                        obfuscatedPosition,
+                        retracer));
               }
               // Iterate over mapped ranges that may have different positions than specified.
               List<ElementImpl> ambiguousFrames = new ArrayList<>();
@@ -125,7 +127,8 @@
         classElement,
         getRetracedMethod(methodReference, topFrame, obfuscatedPosition),
         mappedRangesForElement,
-        obfuscatedPosition);
+        obfuscatedPosition,
+        retracer);
   }
 
   private RetracedMethodReferenceImpl getRetracedMethod(
@@ -156,18 +159,21 @@
     private final RetraceClassElementImpl classElement;
     private final List<MappedRange> mappedRanges;
     private final Optional<Integer> obfuscatedPosition;
+    private final RetracerImpl retracer;
 
-    private ElementImpl(
+    ElementImpl(
         RetraceFrameResultImpl retraceFrameResult,
         RetraceClassElementImpl classElement,
         RetracedMethodReferenceImpl methodReference,
         List<MappedRange> mappedRanges,
-        Optional<Integer> obfuscatedPosition) {
+        Optional<Integer> obfuscatedPosition,
+        RetracerImpl retracer) {
       this.methodReference = methodReference;
       this.retraceFrameResult = retraceFrameResult;
       this.classElement = classElement;
       this.mappedRanges = mappedRanges;
       this.obfuscatedPosition = obfuscatedPosition;
+      this.retracer = retracer;
     }
 
     private boolean isOuterMostFrameCompilerSynthesized() {
@@ -188,11 +194,6 @@
     }
 
     @Override
-    public RetraceStackTraceContext getContext() {
-      return RetraceStackTraceContext.getInitialContext();
-    }
-
-    @Override
     public RetraceFrameResult getRetraceResultContext() {
       return retraceFrameResult;
     }
@@ -222,17 +223,32 @@
     }
 
     @Override
-    public void visitNonCompilerSynthesizedFrames(
-        BiConsumer<RetracedMethodReference, Integer> consumer) {
+    public void visitRewrittenFrames(
+        RetraceStackTraceContext context, BiConsumer<RetracedMethodReference, Integer> consumer) {
+      RetraceStackTraceContextImpl contextImpl = (RetraceStackTraceContextImpl) context;
+      RetraceStackTraceCurrentEvaluationInformation currentFrameInformation =
+          contextImpl.computeRewritingInformation(mappedRanges);
       int index = 0;
+      int numberOfFramesToRemove = currentFrameInformation.getRemoveInnerFrames();
       RetracedMethodReferenceImpl prev = getTopFrame();
-      for (RetracedMethodReferenceImpl next : getOuterFrames()) {
-        consumer.accept(prev, index++);
+      List<RetracedMethodReferenceImpl> outerFrames = getOuterFrames();
+      if (numberOfFramesToRemove > outerFrames.size() + 1) {
+        assert prev.isKnown();
+        DiagnosticsHandler diagnosticsHandler = retracer.getDiagnosticsHandler();
+        diagnosticsHandler.warning(
+            RetraceInvalidRewriteFrameDiagnostics.create(
+                numberOfFramesToRemove, prev.asKnown().toString()));
+        numberOfFramesToRemove = 0;
+      }
+      for (RetracedMethodReferenceImpl next : outerFrames) {
+        if (numberOfFramesToRemove-- <= 0) {
+          consumer.accept(prev, index++);
+        }
         prev = next;
       }
       // We expect only the last frame, i.e., the outer-most caller to potentially be synthesized.
       // If not include it too.
-      if (!isOuterMostFrameCompilerSynthesized()) {
+      if (numberOfFramesToRemove <= 0 && !isOuterMostFrameCompilerSynthesized()) {
         consumer.accept(prev, index);
       }
     }
@@ -259,5 +275,11 @@
       }
       return outerFrames;
     }
+
+    @Override
+    public RetraceStackTraceContext getContext() {
+      // This will change when supporting outline frames.
+      return RetraceStackTraceContext.getInitialContext();
+    }
   }
 }
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetraceMethodResultImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetraceMethodResultImpl.java
index 8ccdbdb..7d97ed2 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/RetraceMethodResultImpl.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetraceMethodResultImpl.java
@@ -10,10 +10,8 @@
 import com.android.tools.r8.references.MethodReference;
 import com.android.tools.r8.retrace.RetraceMethodElement;
 import com.android.tools.r8.retrace.RetraceMethodResult;
-import com.android.tools.r8.retrace.RetraceStackTraceContext;
 import com.android.tools.r8.retrace.RetracedMethodReference;
 import com.android.tools.r8.retrace.RetracedSourceFile;
-import com.android.tools.r8.retrace.Retracer;
 import com.android.tools.r8.retrace.internal.RetraceClassResultImpl.RetraceClassElementImpl;
 import com.android.tools.r8.utils.Pair;
 import com.google.common.collect.ImmutableList;
@@ -27,13 +25,13 @@
   private final MethodDefinition methodDefinition;
   private final RetraceClassResultImpl classResult;
   private final List<Pair<RetraceClassElementImpl, List<MappedRange>>> mappedRanges;
-  private final Retracer retracer;
+  private final RetracerImpl retracer;
 
   RetraceMethodResultImpl(
       RetraceClassResultImpl classResult,
       List<Pair<RetraceClassElementImpl, List<MappedRange>>> mappedRanges,
       MethodDefinition methodDefinition,
-      Retracer retracer) {
+      RetracerImpl retracer) {
     this.classResult = classResult;
     this.mappedRanges = mappedRanges;
     this.methodDefinition = methodDefinition;
@@ -149,11 +147,6 @@
     }
 
     @Override
-    public RetraceStackTraceContext getContext() {
-      return RetraceStackTraceContext.getInitialContext();
-    }
-
-    @Override
     public boolean isUnknown() {
       return methodReference.isUnknown();
     }
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetraceStackTraceContextImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetraceStackTraceContextImpl.java
index b33e06d..7cc4a30 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/RetraceStackTraceContextImpl.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetraceStackTraceContextImpl.java
@@ -4,6 +4,72 @@
 
 package com.android.tools.r8.retrace.internal;
 
+import com.android.tools.r8.naming.ClassNamingForNameMapper.MappedRange;
+import com.android.tools.r8.naming.mappinginformation.RewriteFrameMappingInformation;
+import com.android.tools.r8.naming.mappinginformation.RewriteFrameMappingInformation.Condition;
+import com.android.tools.r8.naming.mappinginformation.RewriteFrameMappingInformation.RewriteAction;
+import com.android.tools.r8.references.ClassReference;
 import com.android.tools.r8.retrace.RetraceStackTraceContext;
+import com.android.tools.r8.utils.ListUtils;
+import java.util.List;
 
-public class RetraceStackTraceContextImpl implements RetraceStackTraceContext {}
+public class RetraceStackTraceContextImpl implements RetraceStackTraceContext {
+
+  private final ClassReference seenException;
+
+  private RetraceStackTraceContextImpl(ClassReference seenException) {
+    this.seenException = seenException;
+  }
+
+  public ClassReference getSeenException() {
+    return seenException;
+  }
+
+  RetraceStackTraceCurrentEvaluationInformation computeRewritingInformation(
+      List<MappedRange> mappedRanges) {
+    if (mappedRanges == null || mappedRanges.isEmpty()) {
+      return RetraceStackTraceCurrentEvaluationInformation.empty();
+    }
+    RetraceStackTraceCurrentEvaluationInformation.Builder builder =
+        RetraceStackTraceCurrentEvaluationInformation.builder();
+    MappedRange last = ListUtils.last(mappedRanges);
+    for (RewriteFrameMappingInformation rewriteInformation :
+        last.getRewriteFrameMappingInformation()) {
+      if (evaluateConditions(rewriteInformation.getConditions())) {
+        for (RewriteAction action : rewriteInformation.getActions()) {
+          action.evaluate(builder);
+        }
+      }
+    }
+    return builder.build();
+  }
+
+  private boolean evaluateConditions(List<Condition> conditions) {
+    for (Condition condition : conditions) {
+      if (!condition.evaluate(this)) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  public static Builder builder() {
+    return new Builder();
+  }
+
+  public static class Builder {
+
+    private ClassReference seenException;
+
+    private Builder() {}
+
+    public Builder setSeenException(ClassReference seenException) {
+      this.seenException = seenException;
+      return this;
+    }
+
+    public RetraceStackTraceContextImpl build() {
+      return new RetraceStackTraceContextImpl(seenException);
+    }
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetraceStackTraceCurrentEvaluationInformation.java b/src/main/java/com/android/tools/r8/retrace/internal/RetraceStackTraceCurrentEvaluationInformation.java
new file mode 100644
index 0000000..b25454f
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetraceStackTraceCurrentEvaluationInformation.java
@@ -0,0 +1,43 @@
+// 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.retrace.internal;
+
+public class RetraceStackTraceCurrentEvaluationInformation {
+
+  private static final RetraceStackTraceCurrentEvaluationInformation EMPTY =
+      new RetraceStackTraceCurrentEvaluationInformation(0);
+
+  private final int removeInnerFrames;
+
+  private RetraceStackTraceCurrentEvaluationInformation(int removeInnerFrames) {
+    this.removeInnerFrames = removeInnerFrames;
+  }
+
+  public int getRemoveInnerFrames() {
+    return removeInnerFrames;
+  }
+
+  public static RetraceStackTraceCurrentEvaluationInformation empty() {
+    return EMPTY;
+  }
+
+  public static RetraceStackTraceCurrentEvaluationInformation.Builder builder() {
+    return new Builder();
+  }
+
+  public static class Builder {
+
+    private int removeInnerFramesCount;
+
+    public Builder incrementRemoveInnerFramesCount(int increment) {
+      removeInnerFramesCount += increment;
+      return this;
+    }
+
+    RetraceStackTraceCurrentEvaluationInformation build() {
+      return new RetraceStackTraceCurrentEvaluationInformation(removeInnerFramesCount);
+    }
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetracerImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetracerImpl.java
index 0758be3..bad33d8 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/RetracerImpl.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetracerImpl.java
@@ -21,9 +21,11 @@
 public class RetracerImpl implements Retracer {
 
   private final ClassNameMapper classNameMapper;
+  private final DiagnosticsHandler diagnosticsHandler;
 
-  public RetracerImpl(ClassNameMapper classNameMapper) {
+  public RetracerImpl(ClassNameMapper classNameMapper, DiagnosticsHandler diagnosticsHandler) {
     this.classNameMapper = classNameMapper;
+    this.diagnosticsHandler = diagnosticsHandler;
     assert classNameMapper != null;
   }
 
@@ -33,7 +35,8 @@
       boolean allowExperimentalMapping) {
     if (proguardMapProducer instanceof DirectClassNameMapperProguardMapProducer) {
       return new RetracerImpl(
-          ((DirectClassNameMapperProguardMapProducer) proguardMapProducer).getClassNameMapper());
+          ((DirectClassNameMapperProguardMapProducer) proguardMapProducer).getClassNameMapper(),
+          diagnosticsHandler);
     }
     try {
       ClassNameMapper classNameMapper =
@@ -42,12 +45,16 @@
               diagnosticsHandler,
               true,
               allowExperimentalMapping);
-      return new RetracerImpl(classNameMapper);
+      return new RetracerImpl(classNameMapper, diagnosticsHandler);
     } catch (Throwable throwable) {
       throw new InvalidMappingFileException(throwable);
     }
   }
 
+  public DiagnosticsHandler getDiagnosticsHandler() {
+    return diagnosticsHandler;
+  }
+
   @Override
   public RetraceMethodResultImpl retraceMethod(MethodReference methodReference) {
     return retraceClass(methodReference.getHolderClass())
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/StackTraceElementProxyRetracerImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/StackTraceElementProxyRetracerImpl.java
index 9fe783b..2e2c38f 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/StackTraceElementProxyRetracerImpl.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/StackTraceElementProxyRetracerImpl.java
@@ -78,7 +78,9 @@
                             .setRetracedClass(classElement.getRetracedClass())
                             .joinAmbiguous(classResult.isAmbiguous())
                             .setTopFrame(true)
-                            .setContext(classElement.getContext())
+                            // We assume, since no method was defined for this stack trace element,
+                            // that this was a thrown exception.
+                            .setContext(classElement.getContextWhereClassWasThrown())
                             .applyIf(
                                 element.hasSourceFile(),
                                 builder -> {
@@ -110,7 +112,8 @@
                   frameElement -> {
                     List<RetraceStackTraceElementProxyImpl<T, ST>> retracedProxies =
                         new ArrayList<>();
-                    frameElement.visitNonCompilerSynthesizedFrames(
+                    frameElement.visitRewrittenFrames(
+                        proxy.getContext(),
                         (frame, index) -> {
                           boolean isTopFrame = index == 0;
                           retracedProxies.add(
@@ -164,7 +167,6 @@
                           .setRetracedField(fieldElement.getField())
                           .joinAmbiguous(retraceFieldResult.isAmbiguous())
                           .setTopFrame(true)
-                          .setContext(fieldElement.getContext())
                           .applyIf(
                               element.hasSourceFile(),
                               builder -> {
diff --git a/src/test/java/com/android/tools/r8/retrace/RetraceTests.java b/src/test/java/com/android/tools/r8/retrace/RetraceTests.java
index 3a8fd5b..d1a074b 100644
--- a/src/test/java/com/android/tools/r8/retrace/RetraceTests.java
+++ b/src/test/java/com/android/tools/r8/retrace/RetraceTests.java
@@ -42,6 +42,7 @@
 import com.android.tools.r8.retrace.stacktraces.NamedModuleStackTrace;
 import com.android.tools.r8.retrace.stacktraces.NoObfuscatedLineNumberWithOverrideTest;
 import com.android.tools.r8.retrace.stacktraces.NoObfuscationRangeMappingWithStackTrace;
+import com.android.tools.r8.retrace.stacktraces.NpeInlineRetraceStackTrace;
 import com.android.tools.r8.retrace.stacktraces.NullStackTrace;
 import com.android.tools.r8.retrace.stacktraces.ObfucatedExceptionClassStackTrace;
 import com.android.tools.r8.retrace.stacktraces.ObfuscatedRangeToSingleLineStackTrace;
@@ -309,6 +310,11 @@
     runRetraceTest(new AmbiguousWithSignatureVerboseStackTrace());
   }
 
+  @Test
+  public void testNpeInlineRetraceStackTrace() throws Exception {
+    runExperimentalRetraceTest(new NpeInlineRetraceStackTrace());
+  }
+
   private void inspectRetraceTest(
       StackTraceForTest stackTraceForTest, Consumer<Retracer> inspection) {
     inspection.accept(
diff --git a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiRewriteFrameInlineNpeTest.java b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiRewriteFrameInlineNpeTest.java
new file mode 100644
index 0000000..0730508
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiRewriteFrameInlineNpeTest.java
@@ -0,0 +1,113 @@
+// 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.retrace.api;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import com.android.tools.r8.Diagnostic;
+import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.retrace.ProguardMapProducer;
+import com.android.tools.r8.retrace.RetraceClassElement;
+import com.android.tools.r8.retrace.RetraceFrameElement;
+import com.android.tools.r8.retrace.RetraceStackTraceContext;
+import com.android.tools.r8.retrace.RetracedMethodReference;
+import com.android.tools.r8.retrace.Retracer;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class RetraceApiRewriteFrameInlineNpeTest extends RetraceApiTestBase {
+
+  public RetraceApiRewriteFrameInlineNpeTest(TestParameters parameters) {
+    super(parameters);
+  }
+
+  @Override
+  protected Class<? extends RetraceApiBinaryTest> binaryTestClass() {
+    return ApiTest.class;
+  }
+
+  public static class ApiTest implements RetraceApiBinaryTest {
+
+    private final String npeDescriptor = "Ljava/lang/NullPointerException;";
+
+    private final String mapping =
+        "# { id: 'com.android.tools.r8.mapping', version: 'experimental' }\n"
+            + "some.Class -> a:\n"
+            + "  4:4:void other.Class.inlinee():23:23 -> a\n"
+            + "  4:4:void caller(other.Class):7 -> a\n"
+            + "  # { id: 'com.android.tools.r8.rewriteframe', "
+            + "      conditions: ['throws("
+            + npeDescriptor
+            + ")'], "
+            + "      actions: ['removeInnerFrames(1)']"
+            + "    }";
+
+    @Test
+    public void testFirstStackLineIsRemoved() {
+      TestDiagnosticsHandler testDiagnosticsHandler = new TestDiagnosticsHandler();
+      Retracer retracer =
+          Retracer.createExperimental(
+              ProguardMapProducer.fromString(mapping), testDiagnosticsHandler);
+
+      List<RetraceClassElement> npeRetraced =
+          retracer.retraceClass(Reference.classFromDescriptor(npeDescriptor)).stream()
+              .collect(Collectors.toList());
+      assertEquals(1, npeRetraced.size());
+
+      RetraceStackTraceContext context = npeRetraced.get(0).getContextWhereClassWasThrown();
+
+      List<RetraceFrameElement> retraceFrameElements =
+          retracer.retraceClass(Reference.classFromTypeName("a")).stream()
+              .flatMap(element -> element.lookupFrame(Optional.of(4), "a").stream())
+              .collect(Collectors.toList());
+      assertEquals(1, retraceFrameElements.size());
+
+      RetraceFrameElement retraceFrameElement = retraceFrameElements.get(0);
+      // Check that rewriting the frames will remove the top 1 frames if the condition is active.
+      Map<Integer, RetracedMethodReference> results = new LinkedHashMap<>();
+      retraceFrameElement.visitRewrittenFrames(
+          context,
+          (methodReference, index) -> {
+            RetracedMethodReference existingValue = results.put(index, methodReference);
+            assertNull(existingValue);
+          });
+      assertEquals(1, results.size());
+      assertEquals(7, results.get(0).getOriginalPositionOrDefault(4));
+      assertEquals(results.get(0).getMethodName(), "caller");
+    }
+
+    private static class TestDiagnosticsHandler implements com.android.tools.r8.DiagnosticsHandler {
+
+      private List<Diagnostic> infoMessages = new ArrayList<>();
+
+      @Override
+      public void warning(Diagnostic warning) {
+        throw new RuntimeException("Warning not expected");
+      }
+
+      @Override
+      public void error(Diagnostic error) {
+        throw new RuntimeException("Error not expected");
+      }
+
+      @Override
+      public void info(Diagnostic info) {
+        DiagnosticsHandler.super.info(info);
+        infoMessages.add(info);
+      }
+    }
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiSynthesizedFrameTest.java b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiSynthesizedFrameTest.java
index e1ad580..376a274 100644
--- a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiSynthesizedFrameTest.java
+++ b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiSynthesizedFrameTest.java
@@ -11,6 +11,7 @@
 import com.android.tools.r8.references.Reference;
 import com.android.tools.r8.retrace.ProguardMapProducer;
 import com.android.tools.r8.retrace.RetraceFrameElement;
+import com.android.tools.r8.retrace.RetraceStackTraceContext;
 import com.android.tools.r8.retrace.RetracedMethodReference;
 import com.android.tools.r8.retrace.Retracer;
 import java.util.ArrayList;
@@ -57,7 +58,8 @@
       retraceFrameElement.visitAllFrames((method, ignored) -> allFrames.add(method));
       assertEquals(2, allFrames.size());
       List<RetracedMethodReference> nonSyntheticFrames = new ArrayList<>();
-      retraceFrameElement.visitNonCompilerSynthesizedFrames(
+      retraceFrameElement.visitRewrittenFrames(
+          RetraceStackTraceContext.getInitialContext(),
           (method, ignored) -> nonSyntheticFrames.add(method));
       assertEquals(1, nonSyntheticFrames.size());
       assertEquals(nonSyntheticFrames.get(0), allFrames.get(0));
diff --git a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiSynthesizedInnerFrameTest.java b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiSynthesizedInnerFrameTest.java
index 73367a6..c7b8d7a 100644
--- a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiSynthesizedInnerFrameTest.java
+++ b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiSynthesizedInnerFrameTest.java
@@ -11,6 +11,7 @@
 import com.android.tools.r8.references.Reference;
 import com.android.tools.r8.retrace.ProguardMapProducer;
 import com.android.tools.r8.retrace.RetraceFrameElement;
+import com.android.tools.r8.retrace.RetraceStackTraceContext;
 import com.android.tools.r8.retrace.RetracedMethodReference;
 import com.android.tools.r8.retrace.Retracer;
 import java.util.ArrayList;
@@ -57,7 +58,8 @@
       retraceFrameElement.visitAllFrames((method, ignored) -> allFrames.add(method));
       assertEquals(2, allFrames.size());
       List<RetracedMethodReference> nonSyntheticFrames = new ArrayList<>();
-      retraceFrameElement.visitNonCompilerSynthesizedFrames(
+      retraceFrameElement.visitRewrittenFrames(
+          RetraceStackTraceContext.getInitialContext(),
           (method, ignored) -> nonSyntheticFrames.add(method));
       assertEquals(allFrames, nonSyntheticFrames);
     }
diff --git a/src/test/java/com/android/tools/r8/retrace/stacktraces/NpeInlineRetraceStackTrace.java b/src/test/java/com/android/tools/r8/retrace/stacktraces/NpeInlineRetraceStackTrace.java
new file mode 100644
index 0000000..04528c9
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/retrace/stacktraces/NpeInlineRetraceStackTrace.java
@@ -0,0 +1,49 @@
+// 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.retrace.stacktraces;
+
+import com.android.tools.r8.utils.StringUtils;
+import java.util.Arrays;
+import java.util.List;
+
+public class NpeInlineRetraceStackTrace implements StackTraceForTest {
+
+  @Override
+  public List<String> obfuscatedStackTrace() {
+    return Arrays.asList(
+        "Exception in thread \"main\" java.lang.NullPointerException", "\tat a.a(:4)");
+  }
+
+  @Override
+  public String mapping() {
+    return StringUtils.lines(
+        "# { id: 'com.android.tools.r8.mapping', version: 'experimental' }",
+        "some.Class -> a:",
+        "  4:4:void other.Class():23:23 -> a",
+        "  4:4:void caller(other.Class):7 -> a",
+        "  # { id: 'com.android.tools.r8.rewriteframe', "
+            + "conditions: ['throws(Ljava/lang/NullPointerException;)'],  "
+            + "actions: ['removeInnerFrames(1)'] }");
+  }
+
+  @Override
+  public List<String> retracedStackTrace() {
+    return Arrays.asList(
+        "Exception in thread \"main\" java.lang.NullPointerException",
+        "\tat some.Class.caller(Class.java:7)");
+  }
+
+  @Override
+  public List<String> retraceVerboseStackTrace() {
+    return Arrays.asList(
+        "Exception in thread \"main\" java.lang.NullPointerException",
+        "\tat some.Class.void caller(other.Class)(Class.java:7)");
+  }
+
+  @Override
+  public int expectedWarnings() {
+    return 0;
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java b/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
index 76d76e5..d753ca5 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
@@ -177,7 +177,7 @@
 
   public Retracer getRetracer() {
     if (lazyRetracer == null) {
-      lazyRetracer = new RetracerImpl(mapping);
+      lazyRetracer = new RetracerImpl(mapping, new TestDiagnosticMessagesImpl());
     }
     return lazyRetracer;
   }