Update handling of API outline stubs

Include library exception guards in method API level calculation when
the class is never stubbed.

Bug: b/342961827
Change-Id: I8d33aaeee0412599a3bdc4fe3abc2fb8454e88eb
diff --git a/src/main/java/com/android/tools/r8/GlobalSyntheticsGenerator.java b/src/main/java/com/android/tools/r8/GlobalSyntheticsGenerator.java
index 6b6d239..9b9989a 100644
--- a/src/main/java/com/android/tools/r8/GlobalSyntheticsGenerator.java
+++ b/src/main/java/com/android/tools/r8/GlobalSyntheticsGenerator.java
@@ -289,7 +289,7 @@
           if (notModeledTypes.contains(libraryClass.getClassReference().getTypeName())) {
             return;
           }
-          if (ApiReferenceStubber.isJavaType(libraryClass.getType(), factory)) {
+          if (ApiReferenceStubber.isNeverStubbedType(libraryClass.getType(), factory)) {
             return;
           }
           KnownApiLevel knownApiLevel =
diff --git a/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java b/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java
index d3fafc4..4a2dc9a 100644
--- a/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java
+++ b/src/main/java/com/android/tools/r8/androidapi/ApiReferenceStubber.java
@@ -159,7 +159,7 @@
   }
 
   private void findReferencedLibraryClasses(DexType type, DexProgramClass context) {
-    if (!type.isClassType() || isJavaType(type, appView.dexItemFactory())) {
+    if (!type.isClassType() || isNeverStubbedType(type, appView.dexItemFactory())) {
       return;
     }
     DexClass clazz = appView.definitionFor(type);
@@ -182,10 +182,17 @@
     }
   }
 
-  @SuppressWarnings("ReferenceEquality")
-  public static boolean isJavaType(DexType type, DexItemFactory factory) {
+  public static boolean isAlwaysStubbedType(DexType type, DexItemFactory factory) {
+    return !isNeverStubbedType(type, factory);
+  }
+
+  public static boolean isNeverStubbedType(DexType type, DexItemFactory factory) {
+    return isJavaType(type, factory);
+  }
+
+  private static boolean isJavaType(DexType type, DexItemFactory factory) {
     DexString typeDescriptor = type.getDescriptor();
-    return type == factory.objectType
+    return type.isIdenticalTo(factory.objectType)
         || typeDescriptor.startsWith(factory.comSunDescriptorPrefix)
         || typeDescriptor.startsWith(factory.javaDescriptorPrefix)
         || typeDescriptor.startsWith(factory.javaxDescriptorPrefix)
@@ -201,7 +208,7 @@
       ApiReferenceStubberEventConsumer eventConsumer) {
     DexItemFactory factory = appView.dexItemFactory();
     // Do not stub the anything starting with java (including the object type).
-    if (isJavaType(libraryClass.getType(), factory)) {
+    if (isNeverStubbedType(libraryClass.getType(), factory)) {
       return;
     }
     // Check if desugared library will bridge the type.
diff --git a/src/main/java/com/android/tools/r8/shaking/ComputeApiLevelUseRegistry.java b/src/main/java/com/android/tools/r8/shaking/ComputeApiLevelUseRegistry.java
index ea26098..2f841a5 100644
--- a/src/main/java/com/android/tools/r8/shaking/ComputeApiLevelUseRegistry.java
+++ b/src/main/java/com/android/tools/r8/shaking/ComputeApiLevelUseRegistry.java
@@ -5,6 +5,7 @@
 package com.android.tools.r8.shaking;
 
 import com.android.tools.r8.androidapi.AndroidApiLevelCompute;
+import com.android.tools.r8.androidapi.ApiReferenceStubber;
 import com.android.tools.r8.androidapi.ComputedApiLevel;
 import com.android.tools.r8.dex.code.CfOrDexInstruction;
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
@@ -141,9 +142,9 @@
 
   @Override
   public void registerExceptionGuard(DexType guard) {
-    // Type references as exception guard are OK unless unknown. Library exception guards will be
-    // stubbed.
-    setMaxApiReferenceLevelIfUnknown(guard);
+    // Type references as exception guard are OK for stubbed exception guards as they are always
+    // present at runtime.
+    setMaxApiReferenceLevelIfNeverStubbedOrUnknown(guard);
   }
 
   @Override
@@ -172,10 +173,15 @@
     }
   }
 
-  private void setMaxApiReferenceLevelIfUnknown(DexType type) {
+  private void setMaxApiReferenceLevelIfNeverStubbedOrUnknown(DexType type) {
     if (isEnabled) {
+      if (ApiReferenceStubber.isAlwaysStubbedType(
+          type, appInfoWithClassHierarchy.dexItemFactory())) {
+        return;
+      }
       ComputedApiLevel computedApiLevel = apiLevelCompute.computeApiLevelForLibraryReference(type);
-      if (computedApiLevel.isUnknownApiLevel()) {
+      if (ApiReferenceStubber.isNeverStubbedType(type, appInfoWithClassHierarchy.dexItemFactory())
+          || computedApiLevel.isUnknownApiLevel()) {
         maxApiReferenceLevel = maxApiReferenceLevel.max(computedApiLevel);
       }
     }
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineCatchHandlerWithLibraryTypeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineCatchHandlerWithLibraryTypeTest.java
index ea19697..ebe5ac8 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineCatchHandlerWithLibraryTypeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineCatchHandlerWithLibraryTypeTest.java
@@ -87,10 +87,17 @@
         .transform();
   }
 
+  private static boolean isNeverStubbed(String exception) {
+    // Note: this is a simplified version of ApiReferenceStubber.isNeverStubbedType only testing
+    // the types relevant for this test.
+    return exception.startsWith("java.");
+  }
+
   private boolean compilationTargetIsMissingExceptionType() {
     // A CF target could target any API in the end.
     return parameters.isCfRuntime()
-        || parameters.getApiLevel().getLevel() < EXCEPTIONS.get(exception);
+        || (parameters.getApiLevel().getLevel() < EXCEPTIONS.get(exception)
+            && isNeverStubbed(exception));
   }
 
   @Test