| // Copyright (c) 2019, 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.desugaring.interfacemethods; | |
| import static org.junit.Assert.assertEquals; | |
| import com.android.tools.r8.TestBase; | |
| import com.android.tools.r8.ToolHelper; | |
| import com.android.tools.r8.ToolHelper.DexVm.Version; | |
| import com.android.tools.r8.origin.Origin; | |
| import com.android.tools.r8.smali.SmaliBuilder; | |
| import com.android.tools.r8.utils.AndroidApiLevel; | |
| import com.android.tools.r8.utils.AndroidApp; | |
| import com.android.tools.r8.utils.BooleanUtils; | |
| import com.android.tools.r8.utils.StringUtils; | |
| import com.google.common.collect.ImmutableList; | |
| import org.junit.Test; | |
| import org.junit.runner.RunWith; | |
| import org.junit.runners.Parameterized; | |
| @RunWith(Parameterized.class) | |
| public class InvokeSuperInDefaultInterfaceMethodToNonImmediateInterfaceTest extends TestBase { | |
| private final boolean includeInterfaceMethodOnJ; | |
| @Parameterized.Parameters(name = "Include interface method on J: {0}") | |
| public static Boolean[] data() { | |
| return BooleanUtils.values(); | |
| } | |
| public InvokeSuperInDefaultInterfaceMethodToNonImmediateInterfaceTest( | |
| boolean includeInterfaceMethodOnJ) { | |
| this.includeInterfaceMethodOnJ = includeInterfaceMethodOnJ; | |
| } | |
| @Test | |
| public void test() throws Exception { | |
| // Note that the expected output is independent of the presence of J.m(). | |
| String expectedOutput = StringUtils.lines("I.m()", "JImpl.m()"); | |
| byte[] dex = buildProgramDexFileData(); | |
| if (ToolHelper.getDexVm().getVersion().isNewerThan(Version.V6_0_1)) { | |
| AndroidApp app = | |
| AndroidApp.builder() | |
| .addDexProgramData(buildProgramDexFileData(), Origin.unknown()) | |
| .build(); | |
| assertEquals(expectedOutput, runOnArt(app, "TestClass")); | |
| } | |
| testForR8(Backend.DEX) | |
| .addProgramDexFileData(dex) | |
| .addKeepMainRule("TestClass") | |
| .setMinApi(AndroidApiLevel.M) | |
| .run("TestClass") | |
| .assertSuccessWithOutput(expectedOutput); | |
| } | |
| // Using Smali instead of Jasmin because interfaces are broken in Jasmin. | |
| private byte[] buildProgramDexFileData() throws Exception { | |
| SmaliBuilder smaliBuilder = new SmaliBuilder(); | |
| smaliBuilder.setMinApi(AndroidApiLevel.N); | |
| smaliBuilder.addClass("TestClass"); | |
| // public void main(String[] args) { new JImpl().m(); } | |
| smaliBuilder.addMainMethod( | |
| 1, | |
| "new-instance v0, LJImpl;", | |
| "invoke-direct {v0}, LJImpl;-><init>()V", | |
| "invoke-virtual {v0}, LJImpl;->m()V", | |
| "return-void"); | |
| smaliBuilder.addInterface("I"); | |
| // default void m() { System.out.println("In I.m()"); } | |
| smaliBuilder.addInstanceMethod( | |
| "void", | |
| "m", | |
| 2, | |
| "sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream;", | |
| "const-string v1, \"I.m()\"", | |
| "invoke-virtual {v0, v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V", | |
| "return-void"); | |
| smaliBuilder.addInterface("J", "java.lang.Object", ImmutableList.of("I")); | |
| if (includeInterfaceMethodOnJ) { | |
| smaliBuilder.addInstanceMethod( | |
| "void", | |
| "m", | |
| 2, | |
| "invoke-super {p0}, LI;->m()V", | |
| "sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream;", | |
| "const-string v1, \"J.m()\"", | |
| "invoke-virtual {v0, v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V", | |
| "return-void"); | |
| } | |
| smaliBuilder.addClass("JImpl", "java.lang.Object", ImmutableList.of("J")); | |
| smaliBuilder.addDefaultConstructor(); | |
| // default void m() { I.super.m(); System.out.println("In JImpl.m()"); } | |
| smaliBuilder.addInstanceMethod( | |
| "void", | |
| "m", | |
| 2, | |
| // Note: invoke-super instruction to the non-immediate interface I. | |
| "invoke-super {p0}, LI;->m()V", | |
| "sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream;", | |
| "const-string v1, \"JImpl.m()\"", | |
| "invoke-virtual {v0, v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V", | |
| "return-void"); | |
| return smaliBuilder.compile(); | |
| } | |
| } |