Move API outlining and stubbing out of desugaring

This fixes the API outlining and stubbing to only be part of dexing
and also to be independent of desugaring.

Dispite being "outside" desugaring, The compilation still requires a
correct bootclasspath during dexing.

The temporary system property
`com.android.tools.r8.enableApiOutliningAndStubbing` is added to enable
this for CLI users.  The API already has a deprecated method to enable
this experimental feature until it is default enabled for the compiler.

Bug: b/324270842
Bug: b/333477035
Fixes: b/324500844
Change-Id: I51f4b7b623f5ac905e1de5382f792f0fcdf60fab
diff --git a/src/main/java/com/android/tools/r8/D8Command.java b/src/main/java/com/android/tools/r8/D8Command.java
index 46f1ce4..85d86a6 100644
--- a/src/main/java/com/android/tools/r8/D8Command.java
+++ b/src/main/java/com/android/tools/r8/D8Command.java
@@ -771,7 +771,9 @@
     internal.configureDesugaredLibrary(desugaredLibrarySpecification, synthesizedClassPrefix);
     internal.desugaredLibraryKeepRuleConsumer = desugaredLibraryKeepRuleConsumer;
 
-    if (!enableMissingLibraryApiModeling) {
+    if (internal.isGeneratingClassFiles()
+        || (System.getProperty("com.android.tools.r8.enableApiOutliningAndStubbing") == null
+            && !enableMissingLibraryApiModeling)) {
       internal.apiModelingOptions().disableApiCallerIdentification();
       internal.apiModelingOptions().disableOutliningAndStubbing();
     }
diff --git a/src/main/java/com/android/tools/r8/GlobalSyntheticsGeneratorCommand.java b/src/main/java/com/android/tools/r8/GlobalSyntheticsGeneratorCommand.java
index fbfbc0a..9ffc2e8 100644
--- a/src/main/java/com/android/tools/r8/GlobalSyntheticsGeneratorCommand.java
+++ b/src/main/java/com/android/tools/r8/GlobalSyntheticsGeneratorCommand.java
@@ -146,6 +146,10 @@
     internal.programConsumer =
         classfileDesugaringOnly ? new ThrowingCfConsumer() : new ThrowingDexConsumer();
     internal.setGlobalSyntheticsConsumer(globalsConsumer);
+    if (classfileDesugaringOnly) {
+      internal.apiModelingOptions().disableApiCallerIdentification();
+      internal.apiModelingOptions().disableOutliningAndStubbing();
+    }
 
     // Assert and fixup defaults.
     assert !internal.isShrinking();
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index 7597634..819b349 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -1264,6 +1264,9 @@
       horizontalClassMergerOptions.disable();
       // R8 CF output does not support desugaring so disable it.
       internal.desugarState = DesugarState.OFF;
+      // TODO(b/333477035): Since D8 dexing now supports outline/stubbing API calls R8/CF should
+      //  likely disable API caller identification too so as not to prevent inlining.
+      internal.apiModelingOptions().disableOutliningAndStubbing();
     }
 
     // EXPERIMENTAL flags.
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringCollection.java b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringCollection.java
index d28ac39..97f2d27 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringCollection.java
@@ -43,7 +43,8 @@
     if (appView.options().isGeneratingClassFiles()) {
       return NonEmptyCfInstructionDesugaringCollection.createForCfToCfNonDesugar(appView);
     }
-    return NonEmptyCfInstructionDesugaringCollection.createForCfToDexNonDesugar(appView);
+    return NonEmptyCfInstructionDesugaringCollection.createForCfToDexNonDesugar(
+        appView, apiLevelCompute);
   }
 
   public static CfInstructionDesugaringCollection empty() {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java b/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
index 485322e..407daa8 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
@@ -74,6 +74,10 @@
     if (alwaysThrowingInstructionDesugaring != null) {
       desugarings.add(alwaysThrowingInstructionDesugaring);
     }
+    if (appView.options().apiModelingOptions().enableOutliningOfMethods) {
+      assert appView.options().isGeneratingDex();
+      yieldingDesugarings.add(new ApiInvokeOutlinerDesugaring(appView, apiLevelCompute));
+    }
     if (appView.options().desugarState.isOff()) {
       this.nestBasedAccessDesugaring = null;
       this.recordRewriter = null;
@@ -100,9 +104,6 @@
     if (disableDesugarer != null) {
       desugarings.add(disableDesugarer);
     }
-    if (appView.options().apiModelingOptions().enableOutliningOfMethods) {
-      yieldingDesugarings.add(new ApiInvokeOutlinerDesugaring(appView, apiLevelCompute));
-    }
     if (appView.options().enableTryWithResourcesDesugaring()) {
       desugarings.add(new TwrInstructionDesugaring(appView));
     }
@@ -174,11 +175,12 @@
     return desugaringCollection;
   }
 
-  static NonEmptyCfInstructionDesugaringCollection createForCfToDexNonDesugar(AppView<?> appView) {
+  static NonEmptyCfInstructionDesugaringCollection createForCfToDexNonDesugar(
+      AppView<?> appView, AndroidApiLevelCompute apiLevelCompute) {
     assert appView.options().desugarState.isOff();
     assert appView.options().isGeneratingDex();
     NonEmptyCfInstructionDesugaringCollection desugaringCollection =
-        new NonEmptyCfInstructionDesugaringCollection(appView, noAndroidApiLevelCompute());
+        new NonEmptyCfInstructionDesugaringCollection(appView, apiLevelCompute);
     desugaringCollection.desugarings.add(new InvokeSpecialToSelfDesugaring(appView));
     desugaringCollection.yieldingDesugarings.add(
         new UnrepresentableInDexInstructionRemover(appView));
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelIndirectTargetWithDifferentApiLevelTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelIndirectTargetWithDifferentApiLevelTest.java
index 10b38c6..c1ed5f3 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelIndirectTargetWithDifferentApiLevelTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelIndirectTargetWithDifferentApiLevelTest.java
@@ -168,13 +168,8 @@
                 "foo",
                 Collections.emptyList(),
                 null));
-    if (isR8 && parameters.isCfRuntime()) {
-      verifyHelper.isOutlinedFromUntil(
-          Main.class.getDeclaredMethod("main", String[].class), classMethodApiLevel);
-    } else {
-      verifyHelper.isOutlinedFromUntilAlsoForCf(
-          Main.class.getDeclaredMethod("main", String[].class), classMethodApiLevel);
-    }
+    verifyHelper.isOutlinedFromUntil(
+        Main.class.getDeclaredMethod("main", String[].class), classMethodApiLevel);
   }
 
   // Only present from api level 23.
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelIndirectTargetWithSameApiLevelTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelIndirectTargetWithSameApiLevelTest.java
index d01a450..1ee2689 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelIndirectTargetWithSameApiLevelTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelIndirectTargetWithSameApiLevelTest.java
@@ -150,13 +150,8 @@
                 "foo",
                 Collections.emptyList(),
                 null));
-    if (isR8 && parameters.isCfRuntime()) {
-      verifyHelper.isOutlinedFromUntil(
-          Main.class.getDeclaredMethod("main", String[].class), mockApiLevel);
-    } else {
-      verifyHelper.isOutlinedFromUntilAlsoForCf(
-          Main.class.getDeclaredMethod("main", String[].class), mockApiLevel);
-    }
+    verifyHelper.isOutlinedFromUntil(
+        Main.class.getDeclaredMethod("main", String[].class), mockApiLevel);
   }
 
   // Only present from api level 23.
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineCheckCastTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineCheckCastTest.java
index 4c6763e..ae77d7b 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineCheckCastTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineCheckCastTest.java
@@ -9,6 +9,7 @@
 import static com.android.tools.r8.apimodel.ApiModelingTestHelper.verifyThat;
 
 import com.android.tools.r8.CompilationMode;
+import com.android.tools.r8.D8TestCompileResult;
 import com.android.tools.r8.SingleTestRunResult;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestCompilerBuilder;
@@ -17,6 +18,8 @@
 import com.android.tools.r8.testing.AndroidBuildVersion;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import java.lang.reflect.Method;
+import java.nio.file.Path;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -38,12 +41,17 @@
   }
 
   private void setupTestBuilder(TestCompilerBuilder<?, ?, ?, ?, ?> testBuilder) throws Exception {
+    setupTestBuilderWithoutProgram(
+        testBuilder.addProgramClasses(Main.class).addAndroidBuildVersion(getApiLevelForRuntime()));
+  }
+
+  private void setupTestBuilderWithoutProgram(TestCompilerBuilder<?, ?, ?, ?, ?> testBuilder)
+      throws Exception {
     testBuilder
+        .markAndroidBuildVersionAsActive(getApiLevelForRuntime())
         .addLibraryClasses(LibraryClass.class, LibraryProvider.class)
         .addDefaultRuntimeLibrary(parameters)
-        .addProgramClasses(Main.class)
         .setMinApi(parameters)
-        .addAndroidBuildVersion(getApiLevelForRuntime())
         .apply(setMockApiLevelForClass(LibraryProvider.class, AndroidApiLevel.B))
         .apply(
             setMockApiLevelForMethod(
@@ -78,6 +86,52 @@
   }
 
   @Test
+  public void testD8Cf() throws Exception {
+    parameters.assumeCfRuntime();
+    testForD8(parameters.getBackend())
+        .setMinApi(parameters)
+        .setMode(CompilationMode.DEBUG)
+        .apply(this::setupTestBuilder)
+        .compile()
+        .inspect(
+            inspector ->
+                // Compiling to CF should never result in stubs and outlining for API modeling.
+                verifyThat(inspector, parameters, LibraryClass.class)
+                    .hasNotCheckCastOutlinedFrom(getMainMethod()))
+        .applyIf(
+            addToBootClasspath(),
+            b -> b.addBootClasspathClasses(LibraryClass.class, LibraryProvider.class),
+            b -> b.addBootClasspathClasses(LibraryProvider.class))
+        .run(parameters.getRuntime(), Main.class)
+        .apply(this::checkOutput);
+  }
+
+  @Test
+  public void testD8CfAndDexNoDesugaring() throws Exception {
+    parameters.assumeDexRuntime();
+    D8TestCompileResult compileResult =
+        testForD8(Backend.CF)
+            .setMinApi(parameters)
+            .setMode(CompilationMode.DEBUG)
+            .apply(this::setupTestBuilder)
+            .compile();
+    Path out = compileResult.writeToZip();
+    testForD8()
+        .disableDesugaring()
+        .setMode(CompilationMode.DEBUG)
+        .apply(this::setupTestBuilderWithoutProgram)
+        .addProgramFiles(out)
+        .compile()
+        .inspect(this::inspect)
+        .applyIf(
+            addToBootClasspath(),
+            b -> b.addBootClasspathClasses(LibraryClass.class, LibraryProvider.class),
+            b -> b.addBootClasspathClasses(LibraryProvider.class))
+        .run(parameters.getRuntime(), Main.class)
+        .apply(this::checkOutput);
+  }
+
+  @Test
   public void testD8Debug() throws Exception {
     parameters.assumeDexRuntime();
     testForD8()
@@ -127,7 +181,11 @@
 
   private void inspect(CodeInspector inspector) throws Exception {
     verifyThat(inspector, parameters, LibraryClass.class)
-        .hasCheckCastOutlinedFromUntil(Main.class.getMethod("main", String[].class), classApiLevel);
+        .hasCheckCastOutlinedFromUntil(getMainMethod(), classApiLevel);
+  }
+
+  private static Method getMainMethod() throws NoSuchMethodException {
+    return Main.class.getMethod("main", String[].class);
   }
 
   private void checkOutput(SingleTestRunResult<?> runResult) {
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelingTestHelper.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelingTestHelper.java
index 33fe85c..c546154 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelingTestHelper.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelingTestHelper.java
@@ -138,27 +138,33 @@
       TestCompilerBuilder<?, ?, ?, ?, ?> compilerBuilder) {
     compilerBuilder.addOptionsModification(
         options -> {
-          options.apiModelingOptions().enableLibraryApiModeling = true;
-          options.apiModelingOptions().enableStubbingOfClasses = true;
-          // Our tests rely on us amending the library path with additional classes that are not
-          // in the library.
-          options.testing.globalSyntheticCreatedCallback = null;
+          if (options.isGeneratingDex()) {
+            options.apiModelingOptions().enableLibraryApiModeling = true;
+            options.apiModelingOptions().enableStubbingOfClasses = true;
+            // Our tests rely on us amending the library path with additional classes that are not
+            // in the library.
+            options.testing.globalSyntheticCreatedCallback = null;
+          }
         });
   }
 
   public static void enableStubbingOfClasses(TestCompilerBuilder<?, ?, ?, ?, ?> compilerBuilder) {
     compilerBuilder.addOptionsModification(
         options -> {
-          options.apiModelingOptions().enableLibraryApiModeling = true;
-          options.apiModelingOptions().enableStubbingOfClasses = true;
+          if (options.isGeneratingDex()) {
+            options.apiModelingOptions().enableLibraryApiModeling = true;
+            options.apiModelingOptions().enableStubbingOfClasses = true;
+          }
         });
   }
 
   public static void enableOutliningOfMethods(TestCompilerBuilder<?, ?, ?, ?, ?> compilerBuilder) {
     compilerBuilder.addOptionsModification(
         options -> {
-          options.apiModelingOptions().enableLibraryApiModeling = true;
-          options.apiModelingOptions().enableOutliningOfMethods = true;
+          if (options.isGeneratingDex()) {
+            options.apiModelingOptions().enableLibraryApiModeling = true;
+            options.apiModelingOptions().enableOutliningOfMethods = true;
+          }
         });
   }
 
@@ -496,14 +502,6 @@
       }
     }
 
-    void isOutlinedFromUntilAlsoForCf(Executable method, AndroidApiLevel apiLevel) {
-      if (parameters.getApiLevel().isLessThan(apiLevel)) {
-        isOutlinedFrom(method);
-      } else {
-        isNotOutlinedFrom(method);
-      }
-    }
-
     void isOutlinedFrom(Executable method) {
       // Check that the call is in a synthetic class.
       List<FoundMethodSubject> outlinedMethod =
diff --git a/src/test/java/com/android/tools/r8/desugar/twr/TwrCloseResourceDuplicationTest.java b/src/test/java/com/android/tools/r8/desugar/twr/TwrCloseResourceDuplicationTest.java
index 78a7fb7..62f069e 100644
--- a/src/test/java/com/android/tools/r8/desugar/twr/TwrCloseResourceDuplicationTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/twr/TwrCloseResourceDuplicationTest.java
@@ -70,6 +70,16 @@
         .build();
   }
 
+  protected boolean hasTwrCloseResourceSupport(boolean isDesugaring) {
+    return !isDesugaring
+        || parameters.getApiLevel().isGreaterThanOrEqualTo(apiLevelWithTwrCloseResourceSupport());
+  }
+
+  protected boolean hasTwrCloseResourceApiOutlines() {
+    return parameters.isDexRuntime()
+        && parameters.getApiLevel().isLessThan(apiLevelWithTwrCloseResourceSupport());
+  }
+
   protected String getZipFile() throws IOException {
     return ZipUtils.ZipBuilder.builder(temp.newFile("file.zip").toPath())
         // DEX VMs from 4.4 up-to 9.0 including, will fail if no entry is added.
@@ -106,10 +116,13 @@
               // Throwable.addSuppressed that is still present in the original $closeResource.
               // TODO(b/214329923): If the original $closeResource is pruned this will decrease.
               // TODO(b/168568827): Once we support a nested addSuppressed this will increase.
-              int expectedSynthetics =
-                  parameters.getApiLevel().isLessThan(apiLevelWithTwrCloseResourceSupport())
-                      ? 3
-                      : 0;
+              int expectedSynthetics = 0;
+              if (!hasTwrCloseResourceSupport(true)) {
+                expectedSynthetics += 2;
+              }
+              if (hasTwrCloseResourceApiOutlines()) {
+                expectedSynthetics += 1;
+              }
               assertEquals(INPUT_CLASSES + expectedSynthetics, inspector.allClasses().size());
             });
   }
@@ -137,7 +150,7 @@
               // exception is known or not, thus the synthetic methods will be 2.
               Set<String> nonSyntheticClassOutput =
                   ImmutableSet.of(FOO.typeName(), BAR.typeName(), MAIN.typeName());
-              if (parameters.getApiLevel().isLessThan(apiLevelWithTwrCloseResourceSupport())) {
+              if (!hasTwrCloseResourceSupport(parameters.isDexRuntime())) {
                 Set<String> classOutputWithSynthetics = new HashSet<>(nonSyntheticClassOutput);
                 classOutputWithSynthetics.add(
                     SyntheticItemsTestUtils.syntheticApiOutlineClass(BAR.getClassReference(), 0)
diff --git a/src/test/java/com/android/tools/r8/profile/art/completeness/ApiOutlineProfileRewritingTest.java b/src/test/java/com/android/tools/r8/profile/art/completeness/ApiOutlineProfileRewritingTest.java
index 584814b..acd0d3f 100644
--- a/src/test/java/com/android/tools/r8/profile/art/completeness/ApiOutlineProfileRewritingTest.java
+++ b/src/test/java/com/android/tools/r8/profile/art/completeness/ApiOutlineProfileRewritingTest.java
@@ -49,8 +49,8 @@
         : parameters.getRuntime().maxSupportedApiLevel();
   }
 
-  public boolean isLibraryClassAlwaysPresent(boolean isDesugaring) {
-    return !isDesugaring || parameters.getApiLevel().isGreaterThanOrEqualTo(classApiLevel);
+  public boolean isLibraryClassAlwaysPresent(boolean isApiOutlining) {
+    return !isApiOutlining || parameters.getApiLevel().isGreaterThanOrEqualTo(classApiLevel);
   }
 
   public boolean isLibraryClassPresentInCurrentRuntime() {
@@ -114,7 +114,7 @@
 
   private void inspectD8(ArtProfileInspector profileInspector, CodeInspector inspector)
       throws Exception {
-    inspect(profileInspector, inspector, isLibraryClassAlwaysPresent(true));
+    inspect(profileInspector, inspector, isLibraryClassAlwaysPresent(parameters.isDexRuntime()));
   }
 
   private void inspectR8(ArtProfileInspector profileInspector, CodeInspector inspector)
diff --git a/src/test/java/com/android/tools/r8/profile/art/completeness/TwrCloseResourceDuplicationProfileRewritingTest.java b/src/test/java/com/android/tools/r8/profile/art/completeness/TwrCloseResourceDuplicationProfileRewritingTest.java
index 8554ae3..b8db6f5 100644
--- a/src/test/java/com/android/tools/r8/profile/art/completeness/TwrCloseResourceDuplicationProfileRewritingTest.java
+++ b/src/test/java/com/android/tools/r8/profile/art/completeness/TwrCloseResourceDuplicationProfileRewritingTest.java
@@ -6,6 +6,7 @@
 
 import static com.android.tools.r8.desugar.LibraryFilesHelper.getJdk11LibraryFiles;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentIf;
 import static com.android.tools.r8.utils.codeinspector.Matchers.notIf;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
@@ -111,11 +112,6 @@
         .build();
   }
 
-  private boolean hasTwrCloseResourceSupport(boolean isDesugaring) {
-    return !isDesugaring
-        || parameters.getApiLevel().isGreaterThanOrEqualTo(apiLevelWithTwrCloseResourceSupport());
-  }
-
   private void inspectD8(ArtProfileInspector profileInspector, CodeInspector inspector) {
     inspect(profileInspector, inspector, hasTwrCloseResourceSupport(true));
   }
@@ -128,10 +124,17 @@
       ArtProfileInspector profileInspector,
       CodeInspector inspector,
       boolean hasTwrCloseResourceSupport) {
+    int expectedClassCount = 3;
+    if (!hasTwrCloseResourceSupport) {
+      expectedClassCount += 8;
+    }
+    if (hasTwrCloseResourceApiOutlines()) {
+      expectedClassCount += 4;
+    }
     inspector
         .allClasses()
         .forEach(c -> System.out.println(c.getDexProgramClass().toSourceString()));
-    assertEquals(hasTwrCloseResourceSupport ? 3 : 15, inspector.allClasses().size());
+    assertEquals(expectedClassCount, inspector.allClasses().size());
     assertThat(inspector.clazz(MAIN.typeName()), isPresent());
 
     // Class Foo has two methods foo() and $closeResource().
@@ -167,49 +170,60 @@
       ClassSubject syntheticApiOutlineClassSubject0 =
           inspector.clazz(
               SyntheticItemsTestUtils.syntheticApiOutlineClass(clazz.getClassReference(), 0));
-      assertThat(syntheticApiOutlineClassSubject0, notIf(isPresent(), hasTwrCloseResourceSupport));
+      assertThat(syntheticApiOutlineClassSubject0, isPresentIf(hasTwrCloseResourceApiOutlines()));
 
       ClassSubject syntheticApiOutlineClassSubject1 =
           inspector.clazz(
               SyntheticItemsTestUtils.syntheticApiOutlineClass(clazz.getClassReference(), 1));
-      assertThat(syntheticApiOutlineClassSubject1, notIf(isPresent(), hasTwrCloseResourceSupport));
+      assertThat(syntheticApiOutlineClassSubject1, isPresentIf(hasTwrCloseResourceApiOutlines()));
+
+      int initialSyntheticId = hasTwrCloseResourceApiOutlines() ? 2 : 0;
 
       ClassSubject syntheticBackportClassSubject =
           inspector.clazz(
-              SyntheticItemsTestUtils.syntheticBackportClass(clazz.getClassReference(), 2));
+              SyntheticItemsTestUtils.syntheticBackportClass(
+                  clazz.getClassReference(), initialSyntheticId));
       assertThat(syntheticBackportClassSubject, notIf(isPresent(), hasTwrCloseResourceSupport));
 
       ClassSubject syntheticTwrCloseResourceClassSubject3 =
           inspector.clazz(
-              SyntheticItemsTestUtils.syntheticTwrCloseResourceClass(clazz.getClassReference(), 3));
+              SyntheticItemsTestUtils.syntheticTwrCloseResourceClass(
+                  clazz.getClassReference(), initialSyntheticId + 1));
       assertThat(
           syntheticTwrCloseResourceClassSubject3, notIf(isPresent(), hasTwrCloseResourceSupport));
 
       ClassSubject syntheticTwrCloseResourceClassSubject4 =
           inspector.clazz(
-              SyntheticItemsTestUtils.syntheticTwrCloseResourceClass(clazz.getClassReference(), 4));
+              SyntheticItemsTestUtils.syntheticTwrCloseResourceClass(
+                  clazz.getClassReference(), initialSyntheticId + 2));
       assertThat(
           syntheticTwrCloseResourceClassSubject4, notIf(isPresent(), hasTwrCloseResourceSupport));
 
       ClassSubject syntheticTwrCloseResourceClassSubject5 =
           inspector.clazz(
-              SyntheticItemsTestUtils.syntheticTwrCloseResourceClass(clazz.getClassReference(), 5));
+              SyntheticItemsTestUtils.syntheticTwrCloseResourceClass(
+                  clazz.getClassReference(), initialSyntheticId + 3));
       assertThat(
           syntheticTwrCloseResourceClassSubject5, notIf(isPresent(), hasTwrCloseResourceSupport));
 
       profileInspector.applyIf(
+          hasTwrCloseResourceApiOutlines(),
+          i ->
+              i.assertContainsClassRules(
+                      syntheticApiOutlineClassSubject0, syntheticApiOutlineClassSubject1)
+                  .assertContainsMethodRules(
+                      syntheticApiOutlineClassSubject0.uniqueMethod(),
+                      syntheticApiOutlineClassSubject1.uniqueMethod()));
+
+      profileInspector.applyIf(
           !hasTwrCloseResourceSupport,
           i ->
               i.assertContainsClassRules(
-                      syntheticApiOutlineClassSubject0,
-                      syntheticApiOutlineClassSubject1,
                       syntheticBackportClassSubject,
                       syntheticTwrCloseResourceClassSubject3,
                       syntheticTwrCloseResourceClassSubject4,
                       syntheticTwrCloseResourceClassSubject5)
                   .assertContainsMethodRules(
-                      syntheticApiOutlineClassSubject0.uniqueMethod(),
-                      syntheticApiOutlineClassSubject1.uniqueMethod(),
                       syntheticBackportClassSubject.uniqueMethod(),
                       syntheticTwrCloseResourceClassSubject3.uniqueMethod(),
                       syntheticTwrCloseResourceClassSubject4.uniqueMethod(),
diff --git a/src/test/testbase/java/com/android/tools/r8/TestCompilerBuilder.java b/src/test/testbase/java/com/android/tools/r8/TestCompilerBuilder.java
index adfdeaf..4caf75f 100644
--- a/src/test/testbase/java/com/android/tools/r8/TestCompilerBuilder.java
+++ b/src/test/testbase/java/com/android/tools/r8/TestCompilerBuilder.java
@@ -130,6 +130,10 @@
 
   public T addAndroidBuildVersion(AndroidApiLevel specifiedApiLevel) {
     addProgramClasses(AndroidBuildVersion.class);
+    return markAndroidBuildVersionAsActive(specifiedApiLevel);
+  }
+
+  public T markAndroidBuildVersionAsActive(AndroidApiLevel specifiedApiLevel) {
     isAndroidBuildVersionAdded =
         Optional.ofNullable(specifiedApiLevel == null ? null : specifiedApiLevel.getLevel());
     return self();