AppInfoWithClassHierarchy: lookup direct

Bug:147578480
Change-Id: I61902e5dc074b16938229632ec83cdb74103a314
diff --git a/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java b/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java
index a1b5c3c..c858748 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java
@@ -66,17 +66,10 @@
    * @param method the method to lookup
    * @return The actual target for {@code method} or {@code null} if none found.
    */
-
   @Deprecated // TODO(b/147578480): Remove
   public DexEncodedMethod lookupStaticTarget(DexMethod method, DexType invocationContext) {
     assert checkIfObsolete();
-    assert invocationContext.isClassType();
-    DexClass context = definitionFor(invocationContext);
-    if (context == null) {
-      return null;
-    }
-    assert context.isProgramClass();
-    return lookupStaticTarget(method, context.asProgramClass());
+    return lookupStaticTarget(method, toProgramClass(invocationContext));
   }
 
   public final DexEncodedMethod lookupStaticTarget(
@@ -98,13 +91,7 @@
   @Deprecated // TODO(b/147578480): Remove
   public DexEncodedMethod lookupSuperTarget(DexMethod method, DexType invocationContext) {
     assert checkIfObsolete();
-    assert invocationContext.isClassType();
-    DexClass context = definitionFor(invocationContext);
-    if (context == null) {
-      return null;
-    }
-    assert context.isProgramClass();
-    return lookupSuperTarget(method, context.asProgramClass());
+    return lookupSuperTarget(method, toProgramClass(invocationContext));
   }
 
   public final DexEncodedMethod lookupSuperTarget(
@@ -112,4 +99,33 @@
     assert checkIfObsolete();
     return resolveMethod(method.holder, method).lookupInvokeSuperTarget(invocationContext, this);
   }
+
+  /**
+   * Lookup direct method following the super chain from the holder of {@code method}.
+   *
+   * <p>This method will lookup private and constructor methods.
+   *
+   * @param method the method to lookup
+   * @return The actual target for {@code method} or {@code null} if none found.
+   */
+  @Deprecated // TODO(b/147578480): Remove
+  public DexEncodedMethod lookupDirectTarget(DexMethod method, DexType invocationContext) {
+    assert checkIfObsolete();
+    return lookupDirectTarget(method, toProgramClass(invocationContext));
+  }
+
+  public DexEncodedMethod lookupDirectTarget(DexMethod method, DexProgramClass invocationContext) {
+    assert checkIfObsolete();
+    return resolveMethod(method.holder, method).lookupInvokeDirectTarget(invocationContext, this);
+  }
+
+  private DexProgramClass toProgramClass(DexType type) {
+    assert type.isClassType();
+    DexClass clazz = definitionFor(type);
+    if (clazz == null) {
+      return null;
+    }
+    assert clazz.isProgramClass();
+    return clazz.asProgramClass();
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/graph/ResolutionResult.java b/src/main/java/com/android/tools/r8/graph/ResolutionResult.java
index 2b70ca2..7e98588 100644
--- a/src/main/java/com/android/tools/r8/graph/ResolutionResult.java
+++ b/src/main/java/com/android/tools/r8/graph/ResolutionResult.java
@@ -67,6 +67,10 @@
   public abstract DexEncodedMethod lookupInvokeSuperTarget(
       DexProgramClass context, AppInfoWithClassHierarchy appInfo);
 
+  /** Lookup the single target of an invoke-direct on this resolution result if possible. */
+  public abstract DexEncodedMethod lookupInvokeDirectTarget(
+      DexProgramClass context, AppInfoWithClassHierarchy appInfo);
+
   @Deprecated
   public abstract DexEncodedMethod lookupInvokeSuperTarget(DexClass context, AppInfo appInfo);
 
@@ -219,6 +223,27 @@
       return null;
     }
 
+    /**
+     * Lookup direct method following the super chain from the holder of {@code method}.
+     *
+     * <p>This method will lookup private and constructor methods.
+     *
+     * @param context Class the invoke is contained in, i.e., the holder of the caller. * @param
+     *     appInfo Application info.
+     * @return The actual target or {@code null} if none found.
+     */
+    @Override
+    public DexEncodedMethod lookupInvokeDirectTarget(
+        DexProgramClass context, AppInfoWithClassHierarchy appInfo) {
+      if (!isAccessibleFrom(context, appInfo)) {
+        return null;
+      }
+      if (resolvedMethod.isDirectMethod()) {
+        return resolvedMethod;
+      }
+      return null;
+    }
+
     @Override
     public DexEncodedMethod lookupInvokeSuperTarget(DexClass context, AppInfo appInfo) {
       assert context != null;
@@ -441,6 +466,12 @@
     }
 
     @Override
+    public DexEncodedMethod lookupInvokeDirectTarget(
+        DexProgramClass context, AppInfoWithClassHierarchy appInfo) {
+      return null;
+    }
+
+    @Override
     public final Set<DexEncodedMethod> lookupVirtualTargets(AppInfoWithSubtyping appInfo) {
       return null;
     }
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java b/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java
index 936757f..29c6b76 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java
@@ -125,7 +125,7 @@
     DexMethod invokedMethod = getInvokedMethod();
     if (appView.appInfo().hasLiveness()) {
       AppInfoWithLiveness appInfo = appView.appInfo().withLiveness();
-      return appInfo.lookupDirectTarget(invokedMethod);
+      return appInfo.lookupDirectTarget(invokedMethod, invocationContext);
     }
     // In D8, we can treat invoke-direct instructions as having a single target if the invoke is
     // targeting a method in the enclosing class.
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 bba68bf..33e4eed 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -966,7 +966,7 @@
       case INTERFACE:
         return lookupSingleInterfaceTarget(target, invocationContext);
       case DIRECT:
-        return lookupDirectTarget(target);
+        return lookupDirectTarget(target, invocationContext);
       case STATIC:
         return lookupStaticTarget(target, invocationContext);
       case SUPER: