Check for safe api inlining in ClassInliner

Bug: 138781768
Bug: 188388130
Change-Id: I1a9d417c0a6bedc7c3026aa16733d44b4cb14d49
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
index e653838..4e18dcd 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
@@ -5,6 +5,7 @@
 package com.android.tools.r8.ir.optimize.classinliner;
 
 import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
+import static com.android.tools.r8.ir.optimize.info.MethodOptimizationInfo.isApiSafeForInlining;
 
 import com.android.tools.r8.errors.InternalCompilerError;
 import com.android.tools.r8.errors.Unreachable;
@@ -879,7 +880,12 @@
     if (instanceInitializerInfo.receiverMayEscapeOutsideConstructorChain()) {
       return null;
     }
-
+    // Check the api level is allowed to be inlined.
+    if (isApiSafeForInlining(
+            method.getOptimizationInfo(), singleTarget.getOptimizationInfo(), appView.options())
+        .isPossiblyFalse()) {
+      return null;
+    }
     // Check that the entire constructor chain can be inlined into the current context.
     DexMethod parent = instanceInitializerInfo.getParent();
     while (parent != dexItemFactory.objectMembers.constructor) {
@@ -906,6 +912,14 @@
           NopWhyAreYouNotInliningReporter.getInstance())) {
         return null;
       }
+      // Check the api level is allowed to be inlined.
+      if (isApiSafeForInlining(
+              method.getOptimizationInfo(),
+              encodedParentMethod.getOptimizationInfo(),
+              appView.options())
+          .isPossiblyFalse()) {
+        return null;
+      }
       parent =
           encodedParentMethod
               .getOptimizationInfo()
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoClassInliningFieldTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoClassInliningFieldTest.java
index e482f59..f4609d4 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoClassInliningFieldTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoClassInliningFieldTest.java
@@ -53,8 +53,12 @@
         .compile()
         .inspect(
             inspector -> {
-              // TODO(b/138781768): Should not be class inlined.
-              assertThat(inspector.clazz(ApiCaller.class), not(isPresent()));
+              if (parameters.isDexRuntime()
+                  && parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.L_MR1)) {
+                assertThat(inspector.clazz(ApiCaller.class), not(isPresent()));
+              } else {
+                assertThat(inspector.clazz(ApiCaller.class), isPresent());
+              }
             })
         .addRunClasspathClasses(Api.class)
         .run(parameters.getRuntime(), Main.class)
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoClassInliningMethodTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoClassInliningMethodTest.java
index ac42465..22ecf86 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoClassInliningMethodTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoClassInliningMethodTest.java
@@ -5,13 +5,15 @@
 package com.android.tools.r8.apimodel;
 
 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.isPresent;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
 
-import com.android.tools.r8.NeverInline;
 import com.android.tools.r8.NoHorizontalClassMerging;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.apimodel.ApiModelNoClassInliningFieldTest.ApiCallerCaller;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import java.lang.reflect.Method;
 import org.junit.Test;
@@ -36,8 +38,6 @@
   @Test
   public void testR8() throws Exception {
     Method apiMethod = Api.class.getDeclaredMethod("apiLevel22");
-    Method apiCaller = ApiCaller.class.getDeclaredMethod("callApi");
-    Method apiCallerCaller = ApiCallerCaller.class.getDeclaredMethod("callCallApi");
     testForR8(parameters.getBackend())
         .addProgramClasses(ApiCaller.class, ApiCallerCaller.class, Main.class)
         .addLibraryClasses(Api.class)
@@ -50,8 +50,14 @@
         .apply(ApiModelingTestHelper::enableApiCallerIdentification)
         .compile()
         .inspect(
-            verifyThat(parameters, apiCaller)
-                .inlinedIntoFromApiLevel(apiCallerCaller, AndroidApiLevel.L_MR1))
+            inspector -> {
+              if (parameters.isDexRuntime()
+                  && parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.L_MR1)) {
+                assertThat(inspector.clazz(ApiCaller.class), not(isPresent()));
+              } else {
+                assertThat(inspector.clazz(ApiCaller.class), isPresent());
+              }
+            })
         .addRunClasspathClasses(Api.class)
         .run(parameters.getRuntime(), Main.class)
         .assertSuccessWithOutputLines("Api::apiLevel22");
@@ -72,19 +78,10 @@
     }
   }
 
-  @NoHorizontalClassMerging
-  public static class ApiCallerCaller {
-
-    @NeverInline
-    public static void callCallApi() {
-      new ApiCaller().callApi();
-    }
-  }
-
   public static class Main {
 
     public static void main(String[] args) {
-      ApiCallerCaller.callCallApi();
+      new ApiCaller().callApi();
     }
   }
 }