Add a test of lookupSuperTarget

Bug: 111020945
Change-Id: Ieb4476a454aeecafd1e4e1f8cf42e9893c80dcfe
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java
index 7b4f199..8adddfd 100644
--- a/src/test/java/com/android/tools/r8/TestBase.java
+++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -166,6 +166,17 @@
   }
 
   /**
+   * Copy test classes to the specified directory.
+   */
+  protected void copyTestClasses(Path dest, Class... classes) throws IOException {
+    for (Class clazz : classes) {
+      Path path = dest.resolve(clazz.getCanonicalName().replace('.', '/') + ".class");
+      Files.createDirectories(path.getParent());
+      Files.copy(ToolHelper.getClassFileForTestClass(clazz), path);
+    }
+  }
+
+  /**
    * Create a temporary JAR file containing the specified test classes.
    */
   protected Path jarTestClasses(Class... classes) throws IOException {
@@ -518,7 +529,11 @@
   }
 
   protected ProcessResult runOnJavaRaw(String main, byte[]... classes) throws IOException {
-    Path file = writeToZip(Arrays.asList(classes));
+    return runOnJavaRaw(main, Arrays.asList(classes));
+  }
+
+  protected ProcessResult runOnJavaRaw(String main, List<byte[]> classes) throws IOException {
+    Path file = writeToZip(classes);
     return ToolHelper.runJavaNoVerify(file, main);
   }
 
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index 200a1e7..2667ce2 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -745,10 +745,6 @@
     return parts;
   }
 
-  public static Path getPackageDirectoryForTestClass(Class clazz) {
-    return getPackageDirectoryForTestPackage(clazz.getPackage());
-  }
-
   public static List<Path> getClassFilesForTestPackage(Package pkg) throws IOException {
     Path dir = ToolHelper.getPackageDirectoryForTestPackage(pkg);
     return Files.walk(dir)
@@ -762,6 +758,11 @@
         Paths.get("", parts.toArray(new String[parts.size() - 1])));
   }
 
+  public static Path getFileNameForTestClass(Class clazz) {
+    List<String> parts = getNamePartsForTestClass(clazz);
+    return Paths.get("", parts.toArray(new String[parts.size() - 1]));
+  }
+
   public static String getJarEntryForTestClass(Class clazz) {
     List<String> parts = getNamePartsForTestClass(clazz);
     return String.join("/", parts);
diff --git a/src/test/java/com/android/tools/r8/graph/TargetLookupTest.java b/src/test/java/com/android/tools/r8/graph/TargetLookupTest.java
index bda9ac5..6877617 100644
--- a/src/test/java/com/android/tools/r8/graph/TargetLookupTest.java
+++ b/src/test/java/com/android/tools/r8/graph/TargetLookupTest.java
@@ -10,11 +10,22 @@
 
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.ToolHelper.DexVm;
+import com.android.tools.r8.ToolHelper.ProcessResult;
+import com.android.tools.r8.graph.invokesuper2.C0;
+import com.android.tools.r8.graph.invokesuper2.C1;
+import com.android.tools.r8.graph.invokesuper2.C2;
+import com.android.tools.r8.graph.invokesuper2.I0;
+import com.android.tools.r8.graph.invokesuper2.I1;
+import com.android.tools.r8.graph.invokesuper2.I2;
+import com.android.tools.r8.graph.invokesuper2.I3;
+import com.android.tools.r8.graph.invokesuper2.I4;
+import com.android.tools.r8.graph.invokesuper2.Main;
 import com.android.tools.r8.smali.SmaliBuilder;
 import com.android.tools.r8.smali.SmaliTestBase;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.DexInspector;
 import com.google.common.collect.ImmutableList;
+import java.nio.file.Path;
 import java.util.Collections;
 import org.junit.Test;
 
@@ -200,6 +211,63 @@
     AndroidApp processedApp = processApplication(application);
     assertEquals("42", runArt(processedApp));
   }
+
+  @Test
+  public void testLookupSuperTarget() throws Exception {
+    String pkg = Main.class.getPackage().getName().replace('.', '/');
+
+    AndroidApp.Builder builder = AndroidApp.builder();
+    for (Class clazz : new Class[]{
+        I0.class, I1.class, I2.class, I3.class, I4.class,
+        C0.class, C1.class, C2.class,
+        Main.class}) {
+      builder.addProgramFiles(ToolHelper.getClassFileForTestClass(clazz));
+      // At least java.lang.Object is needed as interface method lookup have special handling
+      // of methods on java.lang.Object.
+      builder.addLibraryFiles(ToolHelper.getDefaultAndroidJar());
+    }
+    AndroidApp application = builder.build();
+    AppInfo appInfo = getAppInfo(application);
+    DexItemFactory factory = appInfo.dexItemFactory;
+
+    DexType i0 = factory.createType("L" + pkg + "/I0;");
+    DexType i1 = factory.createType("L" + pkg + "/I1;");
+    DexType i2 = factory.createType("L" + pkg + "/I2;");
+    DexType i3 = factory.createType("L" + pkg + "/I3;");
+    DexType i4 = factory.createType("L" + pkg + "/I4;");
+    DexType c0 = factory.createType("L" + pkg + "/C0;");
+    DexType c1 = factory.createType("L" + pkg + "/C1;");
+    DexType c2 = factory.createType("L" + pkg + "/C2;");
+
+    DexProto mProto = factory.createProto(factory.intType);
+    DexString m = factory.createString("m");
+    DexMethod mOnC0 = factory.createMethod(c0, mProto, m);
+    DexMethod mOnC1 = factory.createMethod(c1, mProto, m);
+    DexMethod mOnI0 = factory.createMethod(i0, mProto, m);
+    DexMethod mOnI1 = factory.createMethod(i1, mProto, m);
+    DexMethod mOnI2 = factory.createMethod(i2, mProto, m);
+    DexMethod mOnI3 = factory.createMethod(i3, mProto, m);
+    DexMethod mOnI4 = factory.createMethod(i4, mProto, m);
+
+    assertEquals(mOnI0, appInfo.lookupSuperTarget(mOnC0, c1).method);
+    assertEquals(mOnI1, appInfo.lookupSuperTarget(mOnI1, c1).method);
+    assertEquals(mOnI2, appInfo.lookupSuperTarget(mOnI2, c1).method);
+
+    assertEquals(mOnI0, appInfo.lookupSuperTarget(mOnC1, c2).method);
+    assertEquals(mOnI1, appInfo.lookupSuperTarget(mOnI3, c2).method);
+    assertEquals(mOnI2, appInfo.lookupSuperTarget(mOnI4, c2).method);
+
+    // Copy classes to run on the Java VM.
+    Path out = temp.newFolder().toPath();
+    copyTestClasses(out, I0.class, I1.class, I2.class, I3.class, I4.class);
+    copyTestClasses(out, C0.class, C1.class, C2.class, Main.class);
+    ProcessResult result = ToolHelper.runJava(out, Main.class.getCanonicalName());
+    assertEquals(0, result.exitCode);
+
+    // Process the application and expect the same result on Art.
+    AndroidApp processedApp = processApplication(application);
+    assertEquals(result.stdout, runArt(processedApp, Main.class.getCanonicalName()));
+  }
 }
 
 
diff --git a/src/test/java/com/android/tools/r8/graph/invokesuper2/C0.java b/src/test/java/com/android/tools/r8/graph/invokesuper2/C0.java
new file mode 100644
index 0000000..8e92fb4
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/graph/invokesuper2/C0.java
@@ -0,0 +1,8 @@
+// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.graph.invokesuper2;
+
+public class C0  implements I0 {
+}
diff --git a/src/test/java/com/android/tools/r8/graph/invokesuper2/C1.java b/src/test/java/com/android/tools/r8/graph/invokesuper2/C1.java
new file mode 100644
index 0000000..ff98da9
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/graph/invokesuper2/C1.java
@@ -0,0 +1,17 @@
+// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.graph.invokesuper2;
+
+public class C1 extends C0 implements I1, I2 {
+  public int m() {
+    // super.m() becomes: invokespecial com/android/tools/r8/graph/invokesuper2/C0.m()I
+    System.out.println(super.m());
+    // I1.super.m() becomes: invokespecial com/android/tools/r8/graph/invokesuper2/I1.m:()I
+    System.out.println(I1.super.m());
+    // I2.super.m() becomes: invokespecial com/android/tools/r8/graph/invokesuper2/I2.m:()I
+    System.out.println(I2.super.m());
+    return 3;
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/graph/invokesuper2/C2.java b/src/test/java/com/android/tools/r8/graph/invokesuper2/C2.java
new file mode 100644
index 0000000..abdf7ff
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/graph/invokesuper2/C2.java
@@ -0,0 +1,17 @@
+// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.graph.invokesuper2;
+
+public class C2 extends C0 implements I3, I4 {
+  public int m() {
+    // super.m() becomes: invokespecial com/android/tools/r8/graph/invokesuper2/C0.m()I
+    System.out.println(super.m());
+    // I1.super.m() becomes: invokespecial com/android/tools/r8/graph/invokesuper2/I3.m:()I
+    System.out.println(I3.super.m());
+    // I2.super.m() becomes: invokespecial com/android/tools/r8/graph/invokesuper2/I4.m:()I
+    System.out.println(I4.super.m());
+    return 3;
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/graph/invokesuper2/I0.java b/src/test/java/com/android/tools/r8/graph/invokesuper2/I0.java
new file mode 100644
index 0000000..02b59a6
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/graph/invokesuper2/I0.java
@@ -0,0 +1,11 @@
+// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.graph.invokesuper2;
+
+public interface I0 {
+  default int m() {
+    return 0;
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/graph/invokesuper2/I1.java b/src/test/java/com/android/tools/r8/graph/invokesuper2/I1.java
new file mode 100644
index 0000000..0593d90
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/graph/invokesuper2/I1.java
@@ -0,0 +1,11 @@
+// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.graph.invokesuper2;
+
+public interface I1 extends I0 {
+  default int m() {
+    return 1;
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/graph/invokesuper2/I2.java b/src/test/java/com/android/tools/r8/graph/invokesuper2/I2.java
new file mode 100644
index 0000000..22956c3
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/graph/invokesuper2/I2.java
@@ -0,0 +1,11 @@
+// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.graph.invokesuper2;
+
+public interface I2 extends I0 {
+  default int m() {
+    return 2;
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/graph/invokesuper2/I3.java b/src/test/java/com/android/tools/r8/graph/invokesuper2/I3.java
new file mode 100644
index 0000000..e64154e
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/graph/invokesuper2/I3.java
@@ -0,0 +1,8 @@
+// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.graph.invokesuper2;
+
+public interface I3 extends I1 {
+}
diff --git a/src/test/java/com/android/tools/r8/graph/invokesuper2/I4.java b/src/test/java/com/android/tools/r8/graph/invokesuper2/I4.java
new file mode 100644
index 0000000..ddc5ad0
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/graph/invokesuper2/I4.java
@@ -0,0 +1,8 @@
+// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.graph.invokesuper2;
+
+public interface I4 extends I2 {
+}
diff --git a/src/test/java/com/android/tools/r8/graph/invokesuper2/Main.java b/src/test/java/com/android/tools/r8/graph/invokesuper2/Main.java
new file mode 100644
index 0000000..6a2a3b9
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/graph/invokesuper2/Main.java
@@ -0,0 +1,13 @@
+// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.graph.invokesuper2;
+
+public class Main {
+
+  public static void main(String[] args) {
+    System.out.println(new C1().m());
+    System.out.println(new C2().m());
+  }
+}
\ No newline at end of file
diff --git a/src/test/java/com/android/tools/r8/jasmin/JasminBuilder.java b/src/test/java/com/android/tools/r8/jasmin/JasminBuilder.java
index 82381dd..9c15ce7 100644
--- a/src/test/java/com/android/tools/r8/jasmin/JasminBuilder.java
+++ b/src/test/java/com/android/tools/r8/jasmin/JasminBuilder.java
@@ -353,12 +353,16 @@
     return out.toByteArray();
   }
 
-  public List<byte[]> buildClasses() throws Exception {
-    List<byte[]> result = new ArrayList<>();
+  public ImmutableList.Builder<byte[]> buildClasses(ImmutableList.Builder<byte[]> builder)
+      throws Exception {
     for (ClassBuilder clazz : classes) {
-      result.add(compile(clazz));
+      builder.add(compile(clazz));
     }
-    return result;
+    return builder;
+  }
+
+  public List<byte[]> buildClasses() throws Exception {
+    return buildClasses(ImmutableList.builder()).build();
   }
 
   public AndroidApp build() throws Exception {