| // Copyright (c) 2020, 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.memberrebinding; |
| |
| import com.android.tools.r8.R8TestCompileResult; |
| import com.android.tools.r8.TestBase; |
| import com.android.tools.r8.TestParameters; |
| import com.android.tools.r8.TestParametersCollection; |
| import java.nio.file.Path; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.junit.runners.Parameterized; |
| import org.junit.runners.Parameterized.Parameters; |
| |
| @RunWith(Parameterized.class) |
| public class LibraryMemberRebindingTest extends TestBase { |
| |
| private final TestParameters parameters; |
| |
| @Parameters(name = "{0}") |
| public static TestParametersCollection data() { |
| return TestBase.getTestParameters().withAllRuntimesAndApiLevels().build(); |
| } |
| |
| public LibraryMemberRebindingTest(TestParameters parameters) { |
| this.parameters = parameters; |
| } |
| |
| @Test |
| public void testWithEmptyA() throws Exception { |
| Path compileTimeLibrary = compileLibraryForAppCompilation(LibraryB.class, LibraryA.class); |
| test(compileTimeLibrary, compileTimeLibrary); |
| } |
| |
| @Test |
| public void testWithEmptyB() throws Exception { |
| Path compileTimeLibrary = compileLibraryForAppCompilation(LibraryA.class, LibraryB.class); |
| test(compileTimeLibrary, compileTimeLibrary); |
| } |
| |
| @Test |
| public void testWithEmptyBOnlyAtCompileTime() throws Exception { |
| Path compileTimeLibrary = compileLibraryForAppCompilation(LibraryA.class, LibraryB.class); |
| Path runtimeLibrary = compileLibraryForAppCompilation(LibraryB.class, LibraryA.class); |
| test(compileTimeLibrary, runtimeLibrary); |
| } |
| |
| private void test(Path compileTimeLibrary, Path runtimeLibrary) throws Exception { |
| testForR8(parameters.getBackend()) |
| .addProgramClasses(TestClass.class) |
| .addKeepMainRule(TestClass.class) |
| .addLibraryFiles(compileTimeLibrary) |
| .addDefaultRuntimeLibrary(parameters) |
| .setMinApi(parameters.getApiLevel()) |
| .compile() |
| .apply(compileResult -> configureRunClasspath(compileResult, runtimeLibrary)) |
| .run(parameters.getRuntime(), TestClass.class) |
| .assertSuccessWithOutputLines("42"); |
| } |
| |
| private Path compileLibraryForAppCompilation( |
| Class<?> nonEmptyLibraryClass, Class<?> emptyLibraryClass) throws Exception { |
| return testForR8(Backend.CF) |
| .addProgramClasses(nonEmptyLibraryClass) |
| .addProgramClassFileData( |
| transformer(emptyLibraryClass) |
| .removeFields( |
| (int access, String name, String descriptor, String signature, Object value) -> |
| true) |
| .removeMethods( |
| (int access, |
| String name, |
| String descriptor, |
| String signature, |
| String[] exceptions) -> !name.equals("<init>")) |
| .transform()) |
| .addKeepAllClassesRule() |
| .setMinApi(parameters.getApiLevel()) |
| .compile() |
| .writeToZip(); |
| } |
| |
| private void configureRunClasspath(R8TestCompileResult compileResult, Path library) |
| throws Exception { |
| if (parameters.isCfRuntime()) { |
| compileResult.addRunClasspathFiles(library); |
| } else { |
| compileResult.addRunClasspathFiles( |
| testForD8() |
| .addProgramFiles(library) |
| .setMinApi(parameters.getApiLevel()) |
| .compile() |
| .writeToZip()); |
| } |
| } |
| |
| static class TestClass { |
| |
| public static void main(String[] args) { |
| System.out.println(LibraryB.f + LibraryB.m()); |
| } |
| } |
| |
| static class LibraryA { |
| |
| public static int f = 21; |
| |
| public static int m() { |
| return 21; |
| } |
| } |
| |
| static class LibraryB extends LibraryA { |
| |
| public static int f = 21; |
| |
| public static int m() { |
| return 21; |
| } |
| } |
| } |