Return a single dispatch target for final methods

Change-Id: I9ddbd7e8db63063bd90f86519570a3ff97b3565a
diff --git a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
index 56c1ea4..b7f9c4f 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -1361,8 +1361,8 @@
         .isDefinitelyInstanceOfStaticType(appView, () -> dynamicReceiverType, staticReceiverType)) {
       return null;
     }
-    DexClass initialResolutionHolder = definitionFor(method.holder);
-    if (initialResolutionHolder == null || initialResolutionHolder.isInterface() != isInterface) {
+    DexClass initialResolutionHolder = resolutionResult.getInitialResolutionHolder();
+    if (initialResolutionHolder.isInterface() != isInterface) {
       return null;
     }
     DexType refinedReceiverType =
@@ -1372,27 +1372,24 @@
       // The refined receiver is not defined in the program and we cannot determine the target.
       return null;
     }
-    if (!dynamicReceiverType.hasDynamicLowerBoundType()) {
-      if (singleTargetLookupCache.hasPositiveCacheHit(refinedReceiverType, method)) {
-        return singleTargetLookupCache.getPositiveCacheHit(refinedReceiverType, method);
-      }
-      if (singleTargetLookupCache.hasNegativeCacheHit(refinedReceiverType, method)) {
-        return null;
-      }
+    if (singleTargetLookupCache.hasPositiveCacheHit(refinedReceiverType, method)) {
+      return singleTargetLookupCache.getPositiveCacheHit(refinedReceiverType, method);
+    }
+    if (!dynamicReceiverType.hasDynamicLowerBoundType()
+        && singleTargetLookupCache.hasNegativeCacheHit(refinedReceiverType, method)) {
+      return null;
     }
     if (resolutionResult
         .isAccessibleForVirtualDispatchFrom(context.getHolder(), appView)
         .isFalse()) {
       return null;
     }
-    // If the method is modeled, return the resolution.
+    // If the resolved method is final, return the resolution.
     DexClassAndMethod resolvedMethod = resolutionResult.getResolutionPair();
-    if (modeledPredicate.isModeled(resolutionResult.getResolvedHolder().getType())) {
-      if (resolutionResult.getResolvedHolder().isFinal()
-          || (resolvedMethod.getAccessFlags().isFinal()
-              && resolvedMethod.getAccessFlags().isPublic())) {
-        singleTargetLookupCache.addToCache(refinedReceiverType, method, resolvedMethod);
-        return resolvedMethod;
+    if (resolvedMethod.getHolder().isFinal() || resolvedMethod.getAccessFlags().isFinal()) {
+      if (!resolvedMethod.isLibraryMethod()
+          || modeledPredicate.isModeled(resolvedMethod.getHolderType())) {
+        return singleTargetLookupCache.addToCache(refinedReceiverType, method, resolvedMethod);
       }
     }
     DispatchTargetLookupResult exactTarget =
diff --git a/src/main/java/com/android/tools/r8/shaking/SingleTargetLookupCache.java b/src/main/java/com/android/tools/r8/shaking/SingleTargetLookupCache.java
index 0c576e0..fbe53c8 100644
--- a/src/main/java/com/android/tools/r8/shaking/SingleTargetLookupCache.java
+++ b/src/main/java/com/android/tools/r8/shaking/SingleTargetLookupCache.java
@@ -31,10 +31,11 @@
         .add(method);
   }
 
-  public void addToCache(DexType refinedReceiverType, DexMethod method, DexClassAndMethod target) {
+  public DexClassAndMethod addToCache(
+      DexType refinedReceiverType, DexMethod method, DexClassAndMethod target) {
     if (target == null) {
       addNoSingleTargetToCache(refinedReceiverType, method);
-      return;
+      return null;
     }
     assert !ObjectUtils.identical(target.getDefinition(), DexEncodedMethod.SENTINEL);
     assert !hasNegativeCacheHit(refinedReceiverType, method);
@@ -43,6 +44,7 @@
     positiveCache
         .computeIfAbsent(refinedReceiverType, ignoreKey(ConcurrentHashMap::new))
         .put(method, target);
+    return target;
   }
 
   public void removeInstantiatedType(DexType instantiatedType, AppInfoWithLiveness appInfo) {