Merge "Keep default ctor of a first non-serializable super-class."
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 22790b4..75ce373 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -412,6 +412,10 @@
     return null;
   }
 
+  public boolean isSerializable(AppInfo appInfo) {
+    return type.implementedInterfaces(appInfo).contains(appInfo.dexItemFactory.serializableType);
+  }
+
   public boolean isExternalizable(AppInfo appInfo) {
     return type.implementedInterfaces(appInfo).contains(appInfo.dexItemFactory.externalizableType);
   }
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 0be9f91..e0cf415 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -291,6 +291,18 @@
     pinnedItems.add(item);
   }
 
+  private void enqueueFirstNonSerializableClassInitializer(DexClass clazz, KeepReason reason) {
+    assert clazz.isProgramClass() && clazz.isSerializable(appInfo);
+    // Clime up the class hierarchy. Break out if the definition is not found, or hit the library
+    // classes, which are kept by definition, or encounter the first non-serializable class.
+    while (clazz != null && clazz.isProgramClass() && clazz.isSerializable(appInfo)) {
+      clazz = appInfo.definitionFor(clazz.superType);
+    }
+    if (clazz != null && clazz.isProgramClass() && clazz.hasDefaultInitializer()) {
+      workList.add(Action.markMethodLive(clazz.getDefaultInitializer(), reason));
+    }
+  }
+
   private void enqueueHolderIfDependentNonStaticMember(
       DexClass holder, Map<DexDefinition, ProguardKeepRule> dependentItems) {
     // Check if any dependent members are not static, and in that case enqueue the class as well.
@@ -697,14 +709,19 @@
       }
       // We also need to add the corresponding <clinit> to the set of live methods, as otherwise
       // static field initialization (and other class-load-time sideeffects) will not happen.
+      KeepReason reason = KeepReason.reachableFromLiveType(type);
       if (!holder.isLibraryClass() && holder.hasNonTrivialClassInitializer()) {
         DexEncodedMethod clinit = holder.getClassInitializer();
         if (clinit != null) {
           assert clinit.method.holder == holder.type;
-          markDirectStaticOrConstructorMethodAsLive(clinit, KeepReason.reachableFromLiveType(type));
+          markDirectStaticOrConstructorMethodAsLive(clinit, reason);
         }
       }
 
+      if (holder.isProgramClass() && holder.isSerializable(appInfo)) {
+        enqueueFirstNonSerializableClassInitializer(holder, reason);
+      }
+
       // If this type has deferred annotations, we have to process those now, too.
       Set<DexAnnotation> annotations = deferredAnnotations.remove(type);
       if (annotations != null) {
diff --git a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ProguardCompatibilityTestBase.java b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ProguardCompatibilityTestBase.java
index cf14d8b..4ee3011 100644
--- a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ProguardCompatibilityTestBase.java
+++ b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ProguardCompatibilityTestBase.java
@@ -74,10 +74,25 @@
   protected AndroidApp runShrinker(
       Shrinker mode, List<Class> programClasses, Iterable<String> proguardConfigs)
       throws Exception {
-    return runShrinker(mode, programClasses, String.join(System.lineSeparator(), proguardConfigs));
+    return runShrinker(
+        mode, programClasses, String.join(System.lineSeparator(), proguardConfigs), null);
   }
 
-  protected AndroidApp runShrinker(Shrinker mode, List<Class> programClasses, String proguardConfig)
+  protected AndroidApp runShrinker(
+      Shrinker mode,
+      List<Class> programClasses,
+      Iterable<String> proguardConfigs,
+      Consumer<InternalOptions> configure)
+      throws Exception {
+    return runShrinker(
+        mode, programClasses, String.join(System.lineSeparator(), proguardConfigs), configure);
+  }
+
+  protected AndroidApp runShrinker(
+      Shrinker mode,
+      List<Class> programClasses,
+      String proguardConfig,
+      Consumer<InternalOptions> configure)
       throws Exception {
     proguardMap = File.createTempFile("proguard", ".map", temp.getRoot()).toPath();
     switch (mode) {
@@ -86,42 +101,56 @@
       case PROGUARD6:
         return runProguard6(programClasses, proguardConfig, proguardMap);
       case PROGUARD6_THEN_D8:
-        return runProguard6AndD8(programClasses, proguardConfig, proguardMap);
+        return runProguard6AndD8(programClasses, proguardConfig, proguardMap, configure);
       case R8_COMPAT:
-        return runR8Compat(programClasses, proguardConfig, proguardMap, Backend.DEX);
+        return runR8Compat(programClasses, proguardConfig, proguardMap, configure, Backend.DEX);
       case R8_COMPAT_CF:
-        return runR8Compat(programClasses, proguardConfig, proguardMap, Backend.CF);
+        return runR8Compat(programClasses, proguardConfig, proguardMap, configure, Backend.CF);
       case R8:
-        return runR8(programClasses, proguardConfig, proguardMap, Backend.DEX);
+        return runR8(programClasses, proguardConfig, proguardMap, configure, Backend.DEX);
       case R8_CF:
-        return runR8(programClasses, proguardConfig, proguardMap, Backend.CF);
+        return runR8(programClasses, proguardConfig, proguardMap, configure, Backend.CF);
     }
     throw new IllegalArgumentException("Unknown shrinker: " + mode);
   }
 
   protected CodeInspector inspectAfterShrinking(
-      Shrinker mode, List<Class> programClasses, List<String> proguardConfigs) throws Exception {
-    return inspectAfterShrinking(
-        mode, programClasses, String.join(System.lineSeparator(), proguardConfigs));
+      Shrinker mode, List<Class> programClasses, List<String> proguardConfigs)
+      throws Exception {
+    return inspectAfterShrinking(mode, programClasses, proguardConfigs, null);
   }
 
   protected CodeInspector inspectAfterShrinking(
-      Shrinker mode, List<Class> programClasses, String proguardConfig) throws Exception {
+      Shrinker mode,
+      List<Class> programClasses,
+      List<String> proguardConfigs,
+      Consumer<InternalOptions> configure)
+      throws Exception {
+    return inspectAfterShrinking(
+        mode, programClasses, String.join(System.lineSeparator(), proguardConfigs), configure);
+  }
+
+  protected CodeInspector inspectAfterShrinking(
+      Shrinker mode,
+      List<Class> programClasses,
+      String proguardConfig,
+      Consumer<InternalOptions> configure)
+      throws Exception {
     switch (mode) {
       case PROGUARD5:
         return inspectProguard5Result(programClasses, proguardConfig);
       case PROGUARD6:
         return inspectProguard6Result(programClasses, proguardConfig);
       case PROGUARD6_THEN_D8:
-        return inspectProguard6AndD8Result(programClasses, proguardConfig);
+        return inspectProguard6AndD8Result(programClasses, proguardConfig, configure);
       case R8_COMPAT:
-        return inspectR8CompatResult(programClasses, proguardConfig, Backend.DEX);
+        return inspectR8CompatResult(programClasses, proguardConfig, configure, Backend.DEX);
       case R8_COMPAT_CF:
-        return inspectR8CompatResult(programClasses, proguardConfig, Backend.CF);
+        return inspectR8CompatResult(programClasses, proguardConfig, configure, Backend.CF);
       case R8:
-        return inspectR8Result(programClasses, proguardConfig, Backend.DEX);
+        return inspectR8Result(programClasses, proguardConfig, configure, Backend.DEX);
       case R8_CF:
-        return inspectR8Result(programClasses, proguardConfig, Backend.CF);
+        return inspectR8Result(programClasses, proguardConfig, configure, Backend.CF);
     }
     throw new IllegalArgumentException("Unknown shrinker: " + mode);
   }
@@ -151,14 +180,19 @@
   }
 
   protected CodeInspector inspectR8Result(
-      List<Class> programClasses, String proguardConfig, Backend backend) throws Exception {
-    return new CodeInspector(runR8(programClasses, proguardConfig, null, backend));
+      List<Class> programClasses,
+      String proguardConfig,
+      Consumer<InternalOptions> configure,
+      Backend backend)
+      throws Exception {
+    return new CodeInspector(runR8(programClasses, proguardConfig, null, configure, backend));
   }
 
   protected AndroidApp runR8Compat(
       List<Class> programClasses,
       String proguardConfig,
       Path proguardMap,
+      Consumer<InternalOptions> configure,
       Backend backend)
       throws Exception {
     CompatProguardCommandBuilder builder = new CompatProguardCommandBuilder(true);
@@ -175,12 +209,15 @@
       builder.addLibraryFiles(ToolHelper.getJava8RuntimeJar());
       builder.setProgramConsumer(ClassFileConsumer.emptyConsumer());
     }
-    return ToolHelper.runR8(builder.build());
+    return ToolHelper.runR8(builder.build(), configure);
   }
 
   protected CodeInspector inspectR8CompatResult(
-      List<Class> programClasses, String proguardConfig, Backend backend) throws Exception {
-    return new CodeInspector(runR8Compat(programClasses, proguardConfig, null, backend));
+      List<Class> programClasses,
+      String proguardConfig,
+      Consumer<InternalOptions> configure,
+      Backend backend) throws Exception {
+    return new CodeInspector(runR8Compat(programClasses, proguardConfig, null, configure, backend));
   }
 
   protected AndroidApp runProguard5(
@@ -278,7 +315,11 @@
   }
 
   protected AndroidApp runProguard6AndD8(
-      List<Class> programClasses, String proguardConfig, Path proguardMap) throws Exception {
+      List<Class> programClasses,
+      String proguardConfig,
+      Path proguardMap,
+      Consumer<InternalOptions> configure)
+      throws Exception {
     Path proguardedJar =
         File.createTempFile("proguarded", FileUtils.JAR_EXTENSION, temp.getRoot()).toPath();
     Path proguardConfigFile = File.createTempFile("proguard", ".config", temp.getRoot()).toPath();
@@ -292,14 +333,15 @@
     if (result.exitCode != 0) {
       fail("Proguard failed, exit code " + result.exitCode + ", stderr:\n" + result.stderr);
     }
-    return ToolHelper.runD8(readJar(proguardedJar));
+    return ToolHelper.runD8(readJar(proguardedJar), configure);
   }
 
   protected CodeInspector inspectProguard6AndD8Result(
-      List<Class> programClasses, String proguardConfig) throws Exception {
+      List<Class> programClasses, String proguardConfig, Consumer<InternalOptions> configure)
+      throws Exception {
     proguardMap = File.createTempFile("proguard", ".map", temp.getRoot()).toPath();
     return new CodeInspector(
-        runProguard6AndD8(programClasses, proguardConfig, proguardMap), proguardMap);
+        runProguard6AndD8(programClasses, proguardConfig, proguardMap, configure), proguardMap);
   }
 
   protected void verifyClassesPresent(
diff --git a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/defaultctor/ExternalizableTest.java b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/defaultctor/ExternalizableTest.java
index e20b80a..67417e9 100644
--- a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/defaultctor/ExternalizableTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/defaultctor/ExternalizableTest.java
@@ -310,14 +310,7 @@
     assertThat(init, isPresent());
   }
 
-  @Test
-  public void testSerializable() throws Exception {
-    // TODO(b/116735204): R8 should keep default ctor() of first non-serializable superclass of
-    // serializable class.
-    if (shrinker.isR8()) {
-      return;
-    }
-
+  private void testSerializable(boolean enableVerticalClassMerging) throws Exception {
     String javaOutput = runOnJava(SerializableTestMain.class);
 
     List<String> config = ImmutableList.of(
@@ -331,7 +324,9 @@
         "  java.lang.Object readResolve();",
         "}");
 
-    AndroidApp processedApp = runShrinker(shrinker, CLASSES_FOR_SERIALIZABLE, config);
+    AndroidApp processedApp =
+        runShrinker(shrinker, CLASSES_FOR_SERIALIZABLE, config,
+            o -> o.enableVerticalClassMerging = enableVerticalClassMerging);
     // TODO(b/117302947): Need to update ART binary.
     if (shrinker.generatesCf()) {
       String output = runOnVM(
@@ -346,9 +341,33 @@
     //   ...
     //     * Have access to the no-arg constructor of its first non-serializable superclass
     CodeInspector codeInspector = new CodeInspector(processedApp, proguardMap);
-    ClassSubject classSubject = codeInspector.clazz(NonSerializableSuperClass.class);
+    ClassSubject classSubject;
+    if (shrinker.isR8() && enableVerticalClassMerging) {
+      // Vertical class merging.
+      classSubject = codeInspector.clazz(SerializableDataClass.class);
+    } else {
+      classSubject = codeInspector.clazz(NonSerializableSuperClass.class);
+    }
     assertThat(classSubject, isPresent());
     MethodSubject init = classSubject.init(ImmutableList.of());
     assertThat(init, isPresent());
   }
+
+  @Test
+  public void testSerializable_withVerticalClassMerging() throws Exception {
+    if (!shrinker.isR8()) {
+      // Already covered by the other tests.
+      return;
+    }
+    // TODO(b/117514095): Vertical class merging should preserve non/serializable behavior.
+    if (shrinker.isR8()) {
+      return;
+    }
+    testSerializable(true);
+  }
+
+  @Test
+  public void testSerializable_withoutVerticalClassMerging() throws Exception {
+    testSerializable(false);
+  }
 }
diff --git a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/defaultctor/ImplicitlyKeptDefaultConstructorTest.java b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/defaultctor/ImplicitlyKeptDefaultConstructorTest.java
index 777561d..a537d40 100644
--- a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/defaultctor/ImplicitlyKeptDefaultConstructorTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/defaultctor/ImplicitlyKeptDefaultConstructorTest.java
@@ -147,13 +147,14 @@
       Class mainClass, List<Class> programClasses, String proguardConfiguration,
       TriConsumer<Class, List<Class>, CodeInspector> r8Checker,
       TriConsumer<Class, List<Class>, CodeInspector> proguardChecker) throws Exception {
-    CodeInspector inspector = inspectR8CompatResult(programClasses, proguardConfiguration, backend);
+    CodeInspector inspector =
+        inspectR8CompatResult(programClasses, proguardConfiguration, null, backend);
     r8Checker.accept(mainClass, programClasses, inspector);
 
     if (isRunProguard()) {
       inspector = inspectProguard6Result(programClasses, proguardConfiguration);
       proguardChecker.accept(mainClass, programClasses, inspector);
-      inspector = inspectProguard6AndD8Result(programClasses, proguardConfiguration);
+      inspector = inspectProguard6AndD8Result(programClasses, proguardConfiguration, null);
       proguardChecker.accept(mainClass, programClasses, inspector);
     }
   }
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/IfOnAccessModifierTest.java b/src/test/java/com/android/tools/r8/shaking/ifrule/IfOnAccessModifierTest.java
index 89d5079..e420e1e 100644
--- a/src/test/java/com/android/tools/r8/shaking/ifrule/IfOnAccessModifierTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/IfOnAccessModifierTest.java
@@ -12,6 +12,7 @@
 import com.android.tools.r8.naming.MemberNaming.MethodSignature;
 import com.android.tools.r8.shaking.forceproguardcompatibility.ProguardCompatibilityTestBase;
 import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
@@ -45,13 +46,9 @@
     return ImmutableList.of(Shrinker.R8_CF, Shrinker.PROGUARD6, Shrinker.R8);
   }
 
-  @Override
-  protected AndroidApp runR8(
-      List<Class> programClasses, String proguardConfig, Path proguardMap, Backend backend)
-      throws Exception {
+  private void configure(InternalOptions options) {
     // Disable inlining, otherwise classes can be pruned away if all their methods are inlined.
-    return runR8(
-        programClasses, proguardConfig, proguardMap, o -> o.enableInlining = false, backend);
+    options.enableInlining = false;
   }
 
   @Test
@@ -68,7 +65,7 @@
         "  public <methods>;",
         "}"
     );
-    CodeInspector codeInspector = inspectAfterShrinking(shrinker, CLASSES, config);
+    CodeInspector codeInspector = inspectAfterShrinking(shrinker, CLASSES, config, this::configure);
     ClassSubject classSubject = codeInspector.clazz(ClassForIf.class);
     assertThat(classSubject, isPresent());
     MethodSubject methodSubject = classSubject.method(publicMethod);
@@ -97,7 +94,7 @@
         "  public <methods>;",
         "}"
     );
-    CodeInspector codeInspector = inspectAfterShrinking(shrinker, CLASSES, config);
+    CodeInspector codeInspector = inspectAfterShrinking(shrinker, CLASSES, config, this::configure);
     ClassSubject classSubject = codeInspector.clazz(ClassForIf.class);
     assertThat(classSubject, isPresent());
     MethodSubject methodSubject = classSubject.method(publicMethod);
@@ -136,7 +133,7 @@
         "  !public <methods>;",
         "}"
     );
-    CodeInspector codeInspector = inspectAfterShrinking(shrinker, CLASSES, config);
+    CodeInspector codeInspector = inspectAfterShrinking(shrinker, CLASSES, config, this::configure);
     ClassSubject classSubject = codeInspector.clazz(ClassForIf.class);
     assertThat(classSubject, isPresent());
     MethodSubject methodSubject = classSubject.method(publicMethod);
@@ -176,7 +173,7 @@
         "  public <methods>;",
         "}"
     );
-    CodeInspector codeInspector = inspectAfterShrinking(shrinker, CLASSES, config);
+    CodeInspector codeInspector = inspectAfterShrinking(shrinker, CLASSES, config, this::configure);
     ClassSubject classSubject = codeInspector.clazz(ClassForIf.class);
     assertThat(classSubject, isPresent());
     MethodSubject methodSubject = classSubject.method(publicMethod);
@@ -208,7 +205,7 @@
         "  !public <methods>;",
         "}"
     );
-    CodeInspector codeInspector = inspectAfterShrinking(shrinker, CLASSES, config);
+    CodeInspector codeInspector = inspectAfterShrinking(shrinker, CLASSES, config, this::configure);
     ClassSubject classSubject = codeInspector.clazz(ClassForIf.class);
     assertThat(classSubject, isPresent());
     MethodSubject methodSubject = classSubject.method(publicMethod);
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/IfOnClassTest.java b/src/test/java/com/android/tools/r8/shaking/ifrule/IfOnClassTest.java
index 5893782..3a95a6b 100644
--- a/src/test/java/com/android/tools/r8/shaking/ifrule/IfOnClassTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/IfOnClassTest.java
@@ -11,6 +11,7 @@
 import static org.junit.Assert.assertThat;
 
 import com.android.tools.r8.shaking.forceproguardcompatibility.ProguardCompatibilityTestBase;
+import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.FieldSubject;
@@ -19,6 +20,7 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
+import java.util.function.Consumer;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -62,8 +64,13 @@
 
   @Override
   protected CodeInspector inspectR8Result(
-      List<Class> programClasses, String proguardConfig, Backend backend) throws Exception {
-    return super.inspectR8Result(programClasses, adaptConfiguration(proguardConfig), backend);
+      List<Class> programClasses,
+      String proguardConfig,
+      Consumer<InternalOptions> configure,
+      Backend backend)
+      throws Exception {
+    return super.inspectR8Result(
+        programClasses, adaptConfiguration(proguardConfig), configure, backend);
   }
 
   @Override
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/IfOnFieldTest.java b/src/test/java/com/android/tools/r8/shaking/ifrule/IfOnFieldTest.java
index 25acb23..3f9c857 100644
--- a/src/test/java/com/android/tools/r8/shaking/ifrule/IfOnFieldTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/IfOnFieldTest.java
@@ -4,11 +4,13 @@
 package com.android.tools.r8.shaking.ifrule;
 
 import com.android.tools.r8.shaking.forceproguardcompatibility.ProguardCompatibilityTestBase;
+import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.google.common.collect.ImmutableList;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
+import java.util.function.Consumer;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -43,8 +45,12 @@
 
   @Override
   protected CodeInspector inspectR8Result(
-      List<Class> programClasses, String proguardConfig, Backend backend) throws Exception {
-    return super.inspectR8Result(programClasses, adaptConfiguration(proguardConfig), backend);
+      List<Class> programClasses,
+      String proguardConfig,
+      Consumer<InternalOptions> config,
+      Backend backend) throws Exception {
+    return super.inspectR8Result(
+        programClasses, adaptConfiguration(proguardConfig), config, backend);
   }
 
   @Override
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/IfRuleWithVerticalClassMerging.java b/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/IfRuleWithVerticalClassMerging.java
index 165a68f..9cada6f 100644
--- a/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/IfRuleWithVerticalClassMerging.java
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/verticalclassmerging/IfRuleWithVerticalClassMerging.java
@@ -88,13 +88,6 @@
     options.enableVerticalClassMerging = enableClassMerging;
   }
 
-  @Override
-  protected AndroidApp runR8(
-      List<Class> programClasses, String proguardConfig, Path proguardMap, Backend backend)
-      throws Exception {
-    return super.runR8(programClasses, proguardConfig, proguardMap, this::configure, backend);
-  }
-
   private void check(AndroidApp app) throws Exception {
     CodeInspector inspector = new CodeInspector(app);
     ClassSubject clazzA = inspector.clazz(A.class);
@@ -133,7 +126,7 @@
         "-dontobfuscate"
     );
 
-    check(runShrinker(shrinker, CLASSES, config));
+    check(runShrinker(shrinker, CLASSES, config, this::configure));
   }
 
   @Test
@@ -149,7 +142,7 @@
         "-dontobfuscate"
     );
 
-    check(runShrinker(shrinker, CLASSES, config));
+    check(runShrinker(shrinker, CLASSES, config, this::configure));
   }
 
   @Test
@@ -165,6 +158,6 @@
         "-dontobfuscate"
     );
 
-    check(runShrinker(shrinker, CLASSES, config));
+    check(runShrinker(shrinker, CLASSES, config, this::configure));
   }
 }
diff --git a/src/test/java/com/android/tools/r8/shaking/keepclassmembers/b115867670/B115867670.java b/src/test/java/com/android/tools/r8/shaking/keepclassmembers/b115867670/B115867670.java
index 51c2c35..a2ab372 100644
--- a/src/test/java/com/android/tools/r8/shaking/keepclassmembers/b115867670/B115867670.java
+++ b/src/test/java/com/android/tools/r8/shaking/keepclassmembers/b115867670/B115867670.java
@@ -84,8 +84,7 @@
         .add("  public static void main(java.lang.String[]);")
         .add("}")
         .add(additionalKeepRules);
-    String config = String.join(System.lineSeparator(), builder.build());
-    CodeInspector inspector = inspectAfterShrinking(shrinker, CLASSES, config);
+    CodeInspector inspector = inspectAfterShrinking(shrinker, CLASSES, builder.build());
     inspection.accept(inspector);
   }