[ApiModel] Assign api-level to all library definitions

This CL also adds computation for api level for forwarding bridges added during memberrebinding.

Bug: b/235184674
Change-Id: I8060650b66e56d1324027ae260853c71083ca59a
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index 4196ca2..53ba483 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -1102,8 +1102,14 @@
             .build());
   }
 
+  public DexEncodedMethod toForwardingMethod(DexClass newHolder, AppView<?> definitions) {
+    return toForwardingMethod(newHolder, definitions, ConsumerUtils.emptyConsumer());
+  }
+
   public DexEncodedMethod toForwardingMethod(
-      DexClass newHolder, DexDefinitionSupplier definitions) {
+      DexClass newHolder,
+      AppView<?> definitions,
+      Consumer<DexEncodedMethod.Builder> builderConsumer) {
     DexMethod newMethod = getReference().withHolder(newHolder, definitions.dexItemFactory());
     checkIfObsolete();
 
@@ -1149,6 +1155,7 @@
                     .modifyAccessFlags(MethodAccessFlags::setBridge))
         .setIsLibraryMethodOverrideIf(
             !isStatic() && !isLibraryMethodOverride().isUnknown(), isLibraryMethodOverride())
+        .apply(builderConsumer)
         .build();
   }
 
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java
index aebbc12..30a6dfa 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java
@@ -7,6 +7,7 @@
 import com.android.tools.r8.androidapi.AndroidApiLevelCompute;
 import com.android.tools.r8.androidapi.ComputedApiLevel;
 import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.ClasspathOrLibraryClass;
 import com.android.tools.r8.graph.DexClassAndMember;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.LookupTarget;
@@ -70,6 +71,11 @@
   }
 
   @Override
+  public void processNewLiveNonProgramType(ClasspathOrLibraryClass clazz) {
+    clazz.forEachClassMethod(this::computeAndSetApiLevelForDefinition);
+  }
+
+  @Override
   public void notifyMarkVirtualDispatchTargetAsLive(
       LookupTarget target, EnqueuerWorklist worklist) {
     target.accept(
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerAnalysis.java
index 8dc26d6..d587b61 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerAnalysis.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerAnalysis.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.graph.analysis;
 
+import com.android.tools.r8.graph.ClasspathOrLibraryClass;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.LookupTarget;
@@ -35,6 +36,9 @@
       Enqueuer enqueuer,
       EnqueuerWorklist worklist) {}
 
+  /** Called when a non program class is visited and marked live */
+  public void processNewLiveNonProgramType(ClasspathOrLibraryClass clazz) {}
+
   /** Called when a method's code has been processed by the registry. */
   public void processTracedCode(
       ProgramMethod method, DefaultEnqueuerUseRegistry registry, EnqueuerWorklist worklist) {}
diff --git a/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java b/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
index c7395e9..483fdb4 100644
--- a/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
+++ b/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
@@ -35,6 +35,7 @@
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Sets;
 import java.util.ArrayList;
+import java.util.Comparator;
 import java.util.IdentityHashMap;
 import java.util.List;
 import java.util.Map;
@@ -354,15 +355,30 @@
         (bridgeHolder, targets) -> {
           // Sorting the list of bridges within a class maintains a deterministic order of entries
           // in the method collection.
-          targets.sort((p1, p2) -> p1.getFirst().compareTo(p2.getFirst()));
+          targets.sort(Comparator.comparing(Pair::getFirst));
           for (Pair<DexMethod, DexClassAndMethod> pair : targets) {
             DexMethod method = pair.getFirst();
             DexClassAndMethod target = pair.getSecond();
             DexMethod bridgeMethod =
                 method.withHolder(bridgeHolder.getType(), appView.dexItemFactory());
             if (bridgeHolder.getMethodCollection().getMethod(bridgeMethod) == null) {
+              DexEncodedMethod targetDefinition = target.getDefinition();
               DexEncodedMethod bridgeMethodDefinition =
-                  target.getDefinition().toForwardingMethod(bridgeHolder, appView);
+                  targetDefinition.toForwardingMethod(
+                      bridgeHolder,
+                      appView,
+                      builder -> {
+                        if (!targetDefinition.isAbstract()
+                            && targetDefinition.getApiLevelForCode().isNotSetApiLevel()) {
+                          assert target.isLibraryMethod();
+                          builder.setApiLevelForCode(
+                              appView
+                                  .apiLevelCompute()
+                                  .computeApiLevelForLibraryReference(
+                                      targetDefinition.getReference(),
+                                      appView.computedMinApiLevel()));
+                        }
+                      });
               bridgeHolder.addMethod(bridgeMethodDefinition);
             }
             assert resolver.apply(method).getResolvedMethod().getReference() == bridgeMethod;
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index c1f0b40..4907c2f 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -745,6 +745,7 @@
         // rules.
         handleLibraryTypeInheritingFromProgramType(clazz.asLibraryClass());
       }
+      analyses.forEach(analysis -> analysis.processNewLiveNonProgramType(clazz));
       clazz.forEachClassField(
           field ->
               addNonProgramClassToWorklist(
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelBridgeToLibraryMethodTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelBridgeToLibraryMethodTest.java
index 023a738..b90b066 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelBridgeToLibraryMethodTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelBridgeToLibraryMethodTest.java
@@ -48,7 +48,9 @@
                     diagnostics -> {
                       // TODO(b/235184674): Should not throw with an error.
                       diagnostics.assertErrorMessageThatMatches(
-                          containsString("Cannot compute relationship for not set"));
+                          containsString(
+                              "Unexpected virtual method without library method override"
+                                  + " information"));
                     }));
   }