Migrate barray and arrayaccess to a non-legacy test.

Bug: b/167145686
Change-Id: I55e722d258c9106fef3db01819426d53ef726e9a
diff --git a/src/test/java/com/android/tools/r8/CfFrontendExamplesTest.java b/src/test/java/com/android/tools/r8/CfFrontendExamplesTest.java
index 5bb4d63..95dd9bd 100644
--- a/src/test/java/com/android/tools/r8/CfFrontendExamplesTest.java
+++ b/src/test/java/com/android/tools/r8/CfFrontendExamplesTest.java
@@ -46,16 +46,6 @@
   }
 
   @Test
-  public void testArrayAccess() throws Exception {
-    runTest("arrayaccess.ArrayAccess");
-  }
-
-  @Test
-  public void testBArray() throws Exception {
-    runTest("barray.BArray");
-  }
-
-  @Test
   public void testBridgeMethod() throws Exception {
     runTest("bridge.BridgeMethod");
   }
diff --git a/src/test/java/com/android/tools/r8/JvmTestBuilder.java b/src/test/java/com/android/tools/r8/JvmTestBuilder.java
index 49ce60e..f615502 100644
--- a/src/test/java/com/android/tools/r8/JvmTestBuilder.java
+++ b/src/test/java/com/android/tools/r8/JvmTestBuilder.java
@@ -4,6 +4,7 @@
 package com.android.tools.r8;
 
 import com.android.tools.r8.ToolHelper.ProcessResult;
+import com.android.tools.r8.debug.CfDebugTestConfig;
 import com.android.tools.r8.errors.Unimplemented;
 import com.android.tools.r8.testing.AndroidBuildVersion;
 import com.android.tools.r8.utils.AndroidApiLevel;
@@ -65,6 +66,11 @@
     return new JvmTestRunResult(builder.build(), runtime, result, getState());
   }
 
+  public CfDebugTestConfig debugConfig(TestRuntime runtime) {
+    assert runtime.isCf();
+    return new CfDebugTestConfig(runtime.asCf(), classpath);
+  }
+
   @Override
   public JvmTestBuilder addLibraryFiles(Collection<Path> files) {
     return addRunClasspathFiles(files);
diff --git a/src/test/java/com/android/tools/r8/R8CommandTest.java b/src/test/java/com/android/tools/r8/R8CommandTest.java
index 152992d..d64a5a5 100644
--- a/src/test/java/com/android/tools/r8/R8CommandTest.java
+++ b/src/test/java/com/android/tools/r8/R8CommandTest.java
@@ -61,6 +61,22 @@
     parameters.assertNoneRuntime();
   }
 
+  static class A {}
+
+  static class B {}
+
+  private Path getJarWithA() throws Exception {
+    Path jar = temp.newFolder().toPath().resolve("out.jar");
+    writeClassesToJar(jar, A.class);
+    return jar;
+  }
+
+  private Path getJarWithB() throws Exception {
+    Path jar = temp.newFolder().toPath().resolve("out.jar");
+    writeClassesToJar(jar, B.class);
+    return jar;
+  }
+
   @Test(expected = CompilationFailedException.class)
   public void emptyBuilder() throws Throwable {
     // The builder must have a program consumer.
@@ -120,7 +136,7 @@
   @Test
   public void defaultOutIsCwd() throws Throwable {
     Path working = temp.getRoot().toPath();
-    Path input = Paths.get(EXAMPLES_BUILD_DIR, "arithmetic.jar").toAbsolutePath();
+    Path input = getJarWithA();
     Path library = ToolHelper.getDefaultAndroidJar();
     Path output = working.resolve("classes.dex");
     assertFalse(Files.exists(output));
@@ -138,8 +154,8 @@
   @Test
   public void passFeatureSplit() throws Throwable {
     Path working = temp.getRoot().toPath();
-    Path input = Paths.get(EXAMPLES_BUILD_DIR, "arithmetic.jar").toAbsolutePath();
-    Path inputFeature = Paths.get(EXAMPLES_BUILD_DIR, "arrayaccess.jar").toAbsolutePath();
+    Path input = getJarWithA();
+    Path inputFeature = getJarWithB();
     Path library = ToolHelper.getDefaultAndroidJar();
     Path output = working.resolve("classes.dex");
     Path featureOutput = working.resolve("feature.zip");
@@ -163,8 +179,8 @@
   @Test
   public void featureOnlyOneArgument() throws Throwable {
     Path working = temp.getRoot().toPath();
-    Path input = Paths.get(EXAMPLES_BUILD_DIR, "arithmetic.jar").toAbsolutePath();
-    Path inputFeature = Paths.get(EXAMPLES_BUILD_DIR, "arrayaccess.jar").toAbsolutePath();
+    Path input = getJarWithA();
+    Path inputFeature = getJarWithB();
     Path library = ToolHelper.getDefaultAndroidJar();
     Path output = working.resolve("classes.dex");
     assertFalse(Files.exists(output));
@@ -185,7 +201,7 @@
   public void flagsFile() throws Throwable {
     Path working = temp.getRoot().toPath();
     Path library = ToolHelper.getDefaultAndroidJar();
-    Path input = Paths.get(EXAMPLES_BUILD_DIR + "/arithmetic.jar").toAbsolutePath();
+    Path input = getJarWithA();
     Path output = working.resolve("output.zip");
     Path flagsFile = working.resolve("flags.txt");
     FileUtils.writeTextFile(
@@ -226,7 +242,7 @@
     Path working = temp.getRoot().toPath();
     Path flagsFile = working.resolve("flags.txt");
     Path recursiveFlagsFile = working.resolve("recursive_flags.txt");
-    Path input = Paths.get(EXAMPLES_BUILD_DIR + "/arithmetic.jar").toAbsolutePath();
+    Path input = getJarWithA();
     FileUtils.writeTextFile(recursiveFlagsFile, "--output", "output.zip");
     FileUtils.writeTextFile(
         flagsFile, "--min-api", "24", input.toString(), "@" + recursiveFlagsFile);
@@ -386,7 +402,7 @@
       Files.createFile(file);
       assertTrue(Files.exists(file));
     }
-    Path input = Paths.get(EXAMPLES_BUILD_DIR, "arithmetic.jar");
+    Path input = getJarWithA();
     ProcessResult result =
         ToolHelper.forkR8(
             Paths.get("."),
diff --git a/src/test/java/com/android/tools/r8/R8RunExamplesTest.java b/src/test/java/com/android/tools/r8/R8RunExamplesTest.java
index 45122d4..1cfd1a1 100644
--- a/src/test/java/com/android/tools/r8/R8RunExamplesTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunExamplesTest.java
@@ -26,8 +26,6 @@
   public static Collection<String[]> data() {
     String[] tests = {
         "arithmetic.Arithmetic",
-        "arrayaccess.ArrayAccess",
-        "barray.BArray",
         "bridge.BridgeMethod",
         "catchhandleroverlap.CatchHandlerOverlap",
         "cse.CommonSubexpressionElimination",
diff --git a/src/test/java/com/android/tools/r8/R8RunExamplesTestBase.java b/src/test/java/com/android/tools/r8/R8RunExamplesTestBase.java
index 99fedb6..a8edf73 100644
--- a/src/test/java/com/android/tools/r8/R8RunExamplesTestBase.java
+++ b/src/test/java/com/android/tools/r8/R8RunExamplesTestBase.java
@@ -102,11 +102,6 @@
   public Path getOriginalJarFile(String postFix) {
     return Paths.get(getExampleDir(), pkg + postFix + JAR_EXTENSION);
   }
-
-  private Path getOriginalDexFile() {
-    return Paths.get(getExampleDir(), pkg, ToolHelper.DEFAULT_DEX_FILENAME);
-  }
-
   @Rule
   public ExpectedException thrown = ExpectedException.none();
 
diff --git a/src/test/java/com/android/tools/r8/TestParameters.java b/src/test/java/com/android/tools/r8/TestParameters.java
index 206a8ab..1c44201 100644
--- a/src/test/java/com/android/tools/r8/TestParameters.java
+++ b/src/test/java/com/android/tools/r8/TestParameters.java
@@ -245,12 +245,16 @@
   }
 
   public TestParameters assumeR8TestParameters() {
+    assumeTrue(isR8TestParameters());
+    return this;
+  }
+
+  public boolean isR8TestParameters() {
     assertFalse(
-        "No need to use assumeR8TestParameters() when not using api levels for CF",
+        "No need to use is/assumeR8TestParameters() when not using api levels for CF",
         isCfRuntime() && apiLevel == null);
     assertTrue(apiLevel != null || representativeApiLevelForRuntime);
-    assumeTrue(isDexRuntime() || representativeApiLevelForRuntime);
-    return this;
+    return isDexRuntime() || representativeApiLevelForRuntime;
   }
 
   public TestParameters assumeRuntimeTestParameters() {
diff --git a/src/test/java/com/android/tools/r8/d8/DexVersionTests.java b/src/test/java/com/android/tools/r8/d8/DexVersionTests.java
index f413f98..9804829 100644
--- a/src/test/java/com/android/tools/r8/d8/DexVersionTests.java
+++ b/src/test/java/com/android/tools/r8/d8/DexVersionTests.java
@@ -12,23 +12,32 @@
 import com.android.tools.r8.DexIndexedConsumer;
 import com.android.tools.r8.DiagnosticsHandler;
 import com.android.tools.r8.OutputMode;
+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.utils.AndroidApiLevel;
 import java.nio.file.Path;
-import java.nio.file.Paths;
 import java.util.Set;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
 
-public class DexVersionTests {
+@RunWith(Parameterized.class)
+public class DexVersionTests extends TestBase {
 
-  private static final Path ARITHMETIC_JAR =
-      Paths.get(ToolHelper.EXAMPLES_BUILD_DIR + "/arithmetic.jar");
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return TestParameters.builder().withNoneRuntime().build();
+  }
 
-  private static final Path ARRAYACCESS_JAR =
-      Paths.get(ToolHelper.EXAMPLES_BUILD_DIR + "/arrayaccess.jar");
+  public DexVersionTests(TestParameters parameters) {
+    parameters.assertNoneRuntime();
+  }
 
   @Rule public TemporaryFolder defaultApiFolder1 = ToolHelper.getTemporaryFolderForTest();
   @Rule public TemporaryFolder defaultApiFolder2 = ToolHelper.getTemporaryFolderForTest();
@@ -37,9 +46,15 @@
   @Rule public TemporaryFolder androidNApiFolder1 = ToolHelper.getTemporaryFolderForTest();
   @Rule public TemporaryFolder androidNApiFolder2 = ToolHelper.getTemporaryFolderForTest();
 
+  static class Input1 {}
+
+  static class Input2 {}
+
   @Before
   public void compileVersions() throws Exception {
-    D8Command.Builder arrayAccessBuilder = D8Command.builder().addProgramFiles(ARRAYACCESS_JAR);
+    Path inputJar1 = getStaticTemp().newFolder().toPath().resolve("input1.jar");
+    writeClassesToJar(inputJar1, Input1.class);
+    D8Command.Builder arrayAccessBuilder = D8Command.builder().addProgramFiles(inputJar1);
     D8.run(
         arrayAccessBuilder
             .setOutput(defaultApiFolder1.getRoot().toPath(), OutputMode.DexIndexed)
@@ -55,7 +70,9 @@
             .setMinApiLevel(AndroidApiLevel.N.getLevel())
             .build());
 
-    D8Command.Builder arithmeticBuilder = D8Command.builder().addProgramFiles(ARITHMETIC_JAR);
+    Path inputJar2 = getStaticTemp().newFolder().toPath().resolve("input2.jar");
+    writeClassesToJar(inputJar2, Input2.class);
+    D8Command.Builder arithmeticBuilder = D8Command.builder().addProgramFiles(inputJar2);
     D8.run(
         arithmeticBuilder
             .setOutput(defaultApiFolder2.getRoot().toPath(), OutputMode.DexIndexed)
diff --git a/src/test/java/com/android/tools/r8/debug/DebugStreamComparator.java b/src/test/java/com/android/tools/r8/debug/DebugStreamComparator.java
index 426da42..cfd87f6 100644
--- a/src/test/java/com/android/tools/r8/debug/DebugStreamComparator.java
+++ b/src/test/java/com/android/tools/r8/debug/DebugStreamComparator.java
@@ -236,7 +236,9 @@
 
   public static String prettyPrintState(DebuggeeState state, PrintOptions options) {
     StringBuilder builder = new StringBuilder();
-    if (!options.printStack) {
+    if (state == null) {
+      builder.append("null state\n");
+    } else if (!options.printStack) {
       builder.append(prettyPrintFrame(state, options));
     } else {
       for (int i = 0; i < state.getFrameDepth(); i++) {
diff --git a/src/test/java/com/android/tools/r8/debug/ExamplesDebugTest.java b/src/test/java/com/android/tools/r8/debug/ExamplesDebugTest.java
index e35ce1f..76f9758 100644
--- a/src/test/java/com/android/tools/r8/debug/ExamplesDebugTest.java
+++ b/src/test/java/com/android/tools/r8/debug/ExamplesDebugTest.java
@@ -60,16 +60,6 @@
   }
 
   @Test
-  public void testArrayAccess() throws Exception {
-    testDebugging("arrayaccess", "ArrayAccess");
-  }
-
-  @Test
-  public void testBArray() throws Exception {
-    testDebugging("barray", "BArray");
-  }
-
-  @Test
   public void testBridgeMethod() throws Exception {
     testDebugging("bridge", "BridgeMethod");
   }
diff --git a/src/test/java/com/android/tools/r8/examples/ExamplesTestBase.java b/src/test/java/com/android/tools/r8/examples/ExamplesTestBase.java
new file mode 100644
index 0000000..093702c
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/examples/ExamplesTestBase.java
@@ -0,0 +1,106 @@
+// Copyright (c) 2023, 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.examples;
+
+import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfRuntime;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.debug.CfDebugTestConfig;
+import com.android.tools.r8.debug.DebugStreamComparator;
+import com.android.tools.r8.debug.DebugTestBase;
+import com.android.tools.r8.debug.DebugTestConfig;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.Collections;
+import java.util.List;
+import org.junit.Assume;
+import org.junit.Test;
+
+public abstract class ExamplesTestBase extends DebugTestBase {
+
+  public final TestParameters parameters;
+
+  public ExamplesTestBase(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  public abstract String getExpected();
+
+  public abstract Class<?> getMainClass();
+
+  public List<Class<?>> getTestClasses() {
+    return Collections.singletonList(getMainClass());
+  }
+
+  public void runTestDesugaring() throws Exception {
+    testForDesugaring(parameters)
+        .addProgramClasses(getTestClasses())
+        .run(parameters.getRuntime(), getMainClass())
+        .assertSuccessWithOutput(getExpected());
+  }
+
+  public void runTestR8() throws Exception {
+    parameters.assumeR8TestParameters();
+    testForR8(parameters.getBackend())
+        .setMinApi(parameters)
+        .addProgramClasses(getTestClasses())
+        .addKeepMainRule(getMainClass())
+        .run(parameters.getRuntime(), getMainClass())
+        .assertSuccessWithOutput(getExpected());
+  }
+
+  @Test
+  public void runTestDebugComparator() throws Exception {
+    Assume.assumeFalse(ToolHelper.isWindows());
+    Assume.assumeFalse(
+        "Debugging not enabled in 12.0.0", parameters.isDexRuntimeVersion(Version.V12_0_0));
+    Assume.assumeTrue(
+        "Streaming on Dalvik DEX runtimes has some unknown interference issue",
+        parameters.isCfRuntime() || parameters.isDexRuntimeVersionNewerThanOrEqual(Version.V6_0_1));
+
+    String mainTypeName = getMainClass().getTypeName();
+    DebugStreamComparator comparator =
+        new DebugStreamComparator()
+            .add("JVM", streamDebugTest(getJvmConfig(), mainTypeName, ANDROID_FILTER))
+            .add("D8", streamDebugTest(getD8Config(), mainTypeName, ANDROID_FILTER))
+            .setFilter(
+                state -> state.getClassName().startsWith(getMainClass().getPackage().getName()));
+
+    // Only add R8 on the representative config.
+    if (parameters.isR8TestParameters()) {
+      comparator.add("R8", streamDebugTest(getR8Config(), mainTypeName, ANDROID_FILTER));
+    }
+
+    comparator.compare();
+  }
+
+  private CfDebugTestConfig getJvmConfig() throws IOException {
+    // We can't use `testForJvm` as we want to build the reference even for non-representative API.
+    CfRuntime cfRuntime =
+        parameters.isCfRuntime() ? parameters.asCfRuntime() : CfRuntime.getDefaultCfRuntime();
+    Path jar = temp.newFolder().toPath().resolve("out.jar");
+    writeClassesToJar(jar, getTestClasses());
+    return new CfDebugTestConfig(cfRuntime, Collections.singletonList(jar));
+  }
+
+  private DebugTestConfig getD8Config() throws CompilationFailedException {
+    return testForD8(parameters.getBackend())
+        .addProgramClasses(getTestClasses())
+        .setMinApi(parameters)
+        .compile()
+        .debugConfig(parameters.getRuntime());
+  }
+
+  private DebugTestConfig getR8Config() throws CompilationFailedException {
+    return testForR8(parameters.getBackend())
+        .setMinApi(parameters)
+        .addProgramClasses(getTestClasses())
+        .addKeepMainRule(getMainClass())
+        .debug()
+        .compile()
+        .debugConfig(parameters.getRuntime());
+  }
+}
diff --git a/src/test/examples/arrayaccess/ArrayAccess.java b/src/test/java/com/android/tools/r8/examples/arrayaccess/ArrayAccess.java
similarity index 94%
rename from src/test/examples/arrayaccess/ArrayAccess.java
rename to src/test/java/com/android/tools/r8/examples/arrayaccess/ArrayAccess.java
index f73fd91..6ab0568 100644
--- a/src/test/examples/arrayaccess/ArrayAccess.java
+++ b/src/test/java/com/android/tools/r8/examples/arrayaccess/ArrayAccess.java
@@ -1,7 +1,7 @@
-// Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file
+// Copyright (c) 2023, 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 arrayaccess;
+package com.android.tools.r8.examples.arrayaccess;
 
 public class ArrayAccess {
 
@@ -73,4 +73,4 @@
     i += loadStoreArray(1, new Object[10]);
     System.out.println("37=" + i);
   }
-}
\ No newline at end of file
+}
diff --git a/src/test/java/com/android/tools/r8/examples/arrayaccess/ArrayAccessTestRunner.java b/src/test/java/com/android/tools/r8/examples/arrayaccess/ArrayAccessTestRunner.java
new file mode 100644
index 0000000..ec0a4bf
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/examples/arrayaccess/ArrayAccessTestRunner.java
@@ -0,0 +1,50 @@
+// Copyright (c) 2023, 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.examples.arrayaccess;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.examples.ExamplesTestBase;
+import com.android.tools.r8.utils.StringUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class ArrayAccessTestRunner extends ExamplesTestBase {
+
+  @Parameterized.Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().enableApiLevelsForCf().build();
+  }
+
+  public ArrayAccessTestRunner(TestParameters parameters) {
+    super(parameters);
+  }
+
+  @Override
+  public Class<?> getMainClass() {
+    return ArrayAccess.class;
+  }
+
+  @Override
+  public String getExpected() {
+    return StringUtils.lines("37=37");
+  }
+
+  @Test
+  public void testDesugaring() throws Exception {
+    runTestDesugaring();
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    runTestR8();
+  }
+
+  @Test
+  public void testDebug() throws Exception {
+    runTestDebugComparator();
+  }
+}
diff --git a/src/test/examples/barray/BArray.java b/src/test/java/com/android/tools/r8/examples/barray/BArray.java
similarity index 93%
rename from src/test/examples/barray/BArray.java
rename to src/test/java/com/android/tools/r8/examples/barray/BArray.java
index 26ac5f8..3a46079 100644
--- a/src/test/examples/barray/BArray.java
+++ b/src/test/java/com/android/tools/r8/examples/barray/BArray.java
@@ -1,7 +1,7 @@
-// Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file
+// Copyright (c) 2023, 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 barray;
+package com.android.tools.r8.examples.barray;
 
 public class BArray {
 
diff --git a/src/test/java/com/android/tools/r8/examples/barray/BArrayTestRunner.java b/src/test/java/com/android/tools/r8/examples/barray/BArrayTestRunner.java
new file mode 100644
index 0000000..2f0cc39
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/examples/barray/BArrayTestRunner.java
@@ -0,0 +1,50 @@
+// Copyright (c) 2023, 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.examples.barray;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.examples.ExamplesTestBase;
+import com.android.tools.r8.utils.StringUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class BArrayTestRunner extends ExamplesTestBase {
+
+  @Parameterized.Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().enableApiLevelsForCf().build();
+  }
+
+  public BArrayTestRunner(TestParameters parameters) {
+    super(parameters);
+  }
+
+  @Override
+  public Class<?> getMainClass() {
+    return BArray.class;
+  }
+
+  @Override
+  public String getExpected() {
+    return StringUtils.lines("null boolean: true", "null byte: 42", "boolean: true", "byte: 42");
+  }
+
+  @Test
+  public void testDesugaring() throws Exception {
+    runTestDesugaring();
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    runTestR8();
+  }
+
+  @Test
+  public void testDebug() throws Exception {
+    runTestDebugComparator();
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java b/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java
index 0ee68d2..ce200a0 100644
--- a/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java
+++ b/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java
@@ -1446,6 +1446,19 @@
         });
   }
 
+  public ClassFileTransformer stripDebugLocals(MethodPredicate predicate) {
+    return addMethodTransformer(
+        new MethodTransformer() {
+          @Override
+          public void visitLocalVariable(
+              String name, String descriptor, String signature, Label start, Label end, int index) {
+            if (!MethodPredicate.testContext(predicate, getContext())) {
+              super.visitLocalVariable(name, descriptor, signature, start, end, index);
+            }
+          }
+        });
+  }
+
   public ClassFileTransformer stripFrames(String methodName) {
     return addMethodTransformer(
         new MethodTransformer() {