[ApiModel] Do not outline methods that will be stubbed

Bug: 211720912
Change-Id: I6ccdd4cbcd9fffb19665ce4ffecc710d136473c4
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/apimodel/ApiInvokeOutlinerDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/apimodel/ApiInvokeOutlinerDesugaring.java
index d56be1a..da44c03 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/apimodel/ApiInvokeOutlinerDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/apimodel/ApiInvokeOutlinerDesugaring.java
@@ -92,13 +92,18 @@
     if (clazz == null || !clazz.isLibraryClass()) {
       return appView.computedMinApiLevel();
     }
-    ComputedApiLevel apiLevel =
+    ComputedApiLevel methodApiLevel =
         apiLevelCompute.computeApiLevelForLibraryReference(
             cfInvoke.getMethod(), ComputedApiLevel.unknown());
-    if (apiLevel.isGreaterThan(appView.computedMinApiLevel())) {
-      return apiLevel;
+    if (appView.computedMinApiLevel().isGreaterThanOrEqualTo(methodApiLevel)) {
+      return appView.computedMinApiLevel();
     }
-    return appView.computedMinApiLevel();
+    // Compute the api level of the holder to see if the method will be stubbed.
+    ComputedApiLevel holderApiLevel =
+        apiLevelCompute.computeApiLevelForLibraryReference(holderType, ComputedApiLevel.unknown());
+    return methodApiLevel.isGreaterThan(holderApiLevel)
+        ? methodApiLevel
+        : appView.computedMinApiLevel();
   }
 
   private Collection<CfInstruction> desugarLibraryCall(
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoOutlineForFullyMockedTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoOutlineForFullyMockedTest.java
index 58cdf92..91c55e4 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoOutlineForFullyMockedTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoOutlineForFullyMockedTest.java
@@ -77,8 +77,7 @@
               assertThat(inspector.method(mainMethod), isPresent());
               // TODO(b/211720912): We should never outline since the library class and method is
               //  introduced at the same level.
-              verifyThat(inspector, parameters, methodOn23)
-                  .isOutlinedFromUntil(mainMethod, libraryApiLevel);
+              verifyThat(inspector, parameters, methodOn23).isNotOutlinedFrom(mainMethod);
               verifyThat(inspector, parameters, LibraryClass.class).stubbedUntil(libraryApiLevel);
             });
   }
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodMissingClassTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodMissingClassTest.java
index b41ee4c..7755822 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodMissingClassTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodMissingClassTest.java
@@ -113,8 +113,7 @@
                                       .matches(methodSubject))
                       .findFirst();
               assertFalse(synthesizedMissingNotReferenced.isPresent());
-              verifyThat(inspector, parameters, addedOn23)
-                  .isOutlinedFromUntil(testMethod, AndroidApiLevel.M);
+              verifyThat(inspector, parameters, addedOn23).isNotOutlinedFrom(testMethod);
               verifyThat(inspector, parameters, addedOn27)
                   .isOutlinedFromUntil(testMethod, AndroidApiLevel.O_MR1);
               verifyThat(
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineNoMockingTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineNoMockingTest.java
deleted file mode 100644
index 69a7a97..0000000
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineNoMockingTest.java
+++ /dev/null
@@ -1,105 +0,0 @@
-// 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.apimodel;
-
-import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForClass;
-import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForMethod;
-import static com.android.tools.r8.apimodel.ApiModelingTestHelper.verifyThat;
-import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
-import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assume.assumeFalse;
-
-import com.android.tools.r8.TestBase;
-import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.ToolHelper.DexVm.Version;
-import com.android.tools.r8.testing.AndroidBuildVersion;
-import com.android.tools.r8.utils.AndroidApiLevel;
-import java.lang.reflect.Method;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameter;
-import org.junit.runners.Parameterized.Parameters;
-
-@RunWith(Parameterized.class)
-public class ApiModelOutlineNoMockingTest extends TestBase {
-
-  private final AndroidApiLevel libraryApiLevel = AndroidApiLevel.M;
-
-  @Parameter public TestParameters parameters;
-
-  @Parameters(name = "{0}")
-  public static TestParametersCollection data() {
-    return getTestParameters().withAllRuntimesAndApiLevels().build();
-  }
-
-  @Test
-  public void testR8() throws Exception {
-    assumeFalse(
-        parameters.isDexRuntime() && parameters.getDexRuntimeVersion().isEqualTo(Version.V12_0_0));
-    boolean isMethodApiLevel =
-        parameters.isDexRuntime()
-            && parameters.getApiLevel().isGreaterThanOrEqualTo(libraryApiLevel);
-    Method getterOn23 = LibraryClass.class.getDeclaredMethod("getterOn23");
-    Method methodOn23 = LibraryClass.class.getDeclaredMethod("methodOn23");
-    testForR8(parameters.getBackend())
-        .addProgramClasses(Main.class)
-        .addLibraryClasses(LibraryClass.class)
-        .addDefaultRuntimeLibrary(parameters)
-        .setMinApi(parameters.getApiLevel())
-        .addKeepMainRule(Main.class)
-        .addAndroidBuildVersion()
-        .apply(setMockApiLevelForClass(LibraryClass.class, libraryApiLevel))
-        .apply(setMockApiLevelForMethod(getterOn23, libraryApiLevel))
-        .apply(setMockApiLevelForMethod(methodOn23, libraryApiLevel))
-        .apply(ApiModelingTestHelper::enableOutliningOfMethods)
-        .apply(ApiModelingTestHelper::enableStubbingOfClasses)
-        .compile()
-        .applyIf(
-            parameters.isDexRuntime()
-                && parameters
-                    .getRuntime()
-                    .maxSupportedApiLevel()
-                    .isGreaterThanOrEqualTo(libraryApiLevel),
-            b -> b.addBootClasspathClasses(LibraryClass.class))
-        .run(parameters.getRuntime(), Main.class)
-        .assertSuccessWithOutputLinesIf(!isMethodApiLevel, "Hello World")
-        .assertSuccessWithOutputLinesIf(isMethodApiLevel, "LibraryClass::methodOn23", "Hello World")
-        .inspect(
-            inspector -> {
-              Method mainMethod = Main.class.getDeclaredMethod("main", String[].class);
-              assertThat(inspector.method(mainMethod), isPresent());
-              verifyThat(inspector, parameters, getterOn23)
-                  .isOutlinedFromUntil(mainMethod, libraryApiLevel);
-              verifyThat(inspector, parameters, methodOn23)
-                  .isOutlinedFromUntil(mainMethod, libraryApiLevel);
-              assertThat(inspector.clazz(LibraryClass.class), isAbsent());
-            });
-  }
-
-  // Only present from api level 19.
-  public static class LibraryClass {
-
-    public static LibraryClass getterOn23() {
-      return new LibraryClass();
-    }
-
-    public void methodOn23() {
-      System.out.println("LibraryClass::methodOn23");
-    }
-  }
-
-  public static class Main {
-
-    public static void main(String[] args) {
-      if (AndroidBuildVersion.VERSION >= 23) {
-        LibraryClass.getterOn23().methodOn23();
-      }
-      System.out.println("Hello World");
-    }
-  }
-}