[ApiModel] Do not inline into unknown api level

Bug: 216314378
Change-Id: Ic524c743ac2e3c9934eece9e80b57bc393a6e923
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidApiLevelUtils.java b/src/main/java/com/android/tools/r8/utils/AndroidApiLevelUtils.java
index 089ccce..72ae4c0 100644
--- a/src/main/java/com/android/tools/r8/utils/AndroidApiLevelUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/AndroidApiLevelUtils.java
@@ -22,6 +22,10 @@
     if (caller.getHolderType() == inlinee.getHolderType()) {
       return true;
     }
+    ComputedApiLevel apiLevelForCode = caller.getDefinition().getApiLevelForCode();
+    if (apiLevelForCode.isUnknownApiLevel()) {
+      return false;
+    }
     // For inlining we only measure if the code has invokes into the library.
     return caller
         .getDefinition()
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 7e6d2a5..97ee26b 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodMissingClassTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelOutlineMethodMissingClassTest.java
@@ -97,10 +97,8 @@
         .inspect(
             inspector -> {
               // No need to check further on CF.
-              // TODO(b/216314378): If this changes then we will have more classes here at some
-              //  point.
-              assertEquals(3, inspector.allClasses().size());
               if (parameters.isCfRuntime()) {
+                assertEquals(3, inspector.allClasses().size());
                 return;
               }
               Method testMethod = TestClass.class.getDeclaredMethod("test");
@@ -117,17 +115,17 @@
                       .findFirst();
               assertFalse(synthesizedMissingNotReferenced.isPresent());
               verifyThat(inspector, parameters, addedOn23).isNotOutlinedFrom(testMethod);
-              // TODO(b/216314378): We should consider if addedOn27 should not be inlined again.
-              verifyThat(inspector, parameters, addedOn27).isNotOutlinedFrom(testMethod);
+              verifyThat(inspector, parameters, addedOn27)
+                  .isOutlinedFromUntil(testMethod, finalLibraryMethodLevel);
               verifyThat(
                       inspector,
                       parameters,
                       LibraryClass.class.getDeclaredMethod("missingAndReferenced"))
                   .isNotOutlinedFrom(testMethod);
-              if (parameters.getApiLevel().isLessThan(AndroidApiLevel.O_MR1)) {
-                assertEquals(5, inspector.allClasses().size());
-              } else {
+              if (parameters.getApiLevel().isLessThan(finalLibraryMethodLevel)) {
                 assertEquals(4, inspector.allClasses().size());
+              } else {
+                assertEquals(3, inspector.allClasses().size());
               }
             });
   }
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/extrasubclasses/AbstractClassAlsoImplementedByMissingClassTest.java b/src/test/java/com/android/tools/r8/ir/optimize/extrasubclasses/AbstractClassAlsoImplementedByMissingClassTest.java
index 65cc34d..b67037d 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/extrasubclasses/AbstractClassAlsoImplementedByMissingClassTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/extrasubclasses/AbstractClassAlsoImplementedByMissingClassTest.java
@@ -72,10 +72,12 @@
     ClassSubject bClassSubject = inspector.clazz(B.class);
     assertThat(bClassSubject.uniqueMethodWithName("kept"), isPresent());
 
-    // A.notKept() and B.notKept() should not be present, because the only invoke instruction
-    // targeting A.notKept() should have been inlined.
+    // A.notKept() should not be present, because the only invoke instruction targeting A.notKept()
+    // should have been inlined.
     assertThat(aClassSubject.uniqueMethodWithName("notKept"), not(isPresent()));
-    assertThat(bClassSubject.uniqueMethodWithName("notKept"), not(isPresent()));
+    // B.notKept() is present because the caller has an invoke to an unknown method giving it api
+    // level unknown.
+    assertThat(bClassSubject.uniqueMethodWithName("notKept"), isPresent());
   }
 
   static class TestClass {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/extrasubclasses/InterfaceAlsoImplementedByMissingClassTest.java b/src/test/java/com/android/tools/r8/ir/optimize/extrasubclasses/InterfaceAlsoImplementedByMissingClassTest.java
index 89586d8..c371a93 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/extrasubclasses/InterfaceAlsoImplementedByMissingClassTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/extrasubclasses/InterfaceAlsoImplementedByMissingClassTest.java
@@ -70,9 +70,11 @@
     ClassSubject aClassSubject = inspector.clazz(A.class);
     assertThat(aClassSubject.uniqueMethodWithName("kept"), isPresent());
 
-    // I.notKept() and A.notKept() should not be present, because the only invoke instruction
-    // targeting I.notKept() should have been inlined.
+    // I.notKept() should not be present, because the only invoke instruction targeting I.notKept()
+    // should have been inlined.
     assertThat(iClassSubject.uniqueMethodWithName("notKept"), not(isPresent()));
+    // A.notKept() is present because the caller has an invoke to an unknown method giving it api
+    // level unknown.
     assertThat(aClassSubject.uniqueMethodWithName("notKept"), not(isPresent()));
   }