| // 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.naming.applymapping; |
| |
| import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertThat; |
| import static org.junit.Assert.assertTrue; |
| |
| import com.android.tools.r8.R8Command; |
| import com.android.tools.r8.TestBase; |
| import com.android.tools.r8.ToolHelper; |
| import com.android.tools.r8.graph.DexMethod; |
| import com.android.tools.r8.origin.Origin; |
| import com.android.tools.r8.utils.AndroidApp; |
| import com.android.tools.r8.utils.FileUtils; |
| import com.android.tools.r8.utils.codeinspector.ClassSubject; |
| import com.android.tools.r8.utils.codeinspector.CodeInspector; |
| import com.android.tools.r8.utils.codeinspector.InstructionSubject; |
| import com.android.tools.r8.utils.codeinspector.InvokeInstructionSubject; |
| import com.android.tools.r8.utils.codeinspector.MethodSubject; |
| import com.google.common.collect.ImmutableList; |
| import java.nio.file.Path; |
| import java.util.Iterator; |
| import java.util.List; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.junit.runners.Parameterized; |
| |
| // Base -> X: |
| class Base { |
| // foo() -> bar |
| void foo() { |
| System.out.println("Base#foo"); |
| } |
| } |
| |
| // Sub -> Y: |
| class Sub extends Base { |
| // foo() -> bar |
| // Sub#foo ~> Base#foo by member rebinding analysis |
| } |
| |
| class CompositionalLenseTestMain { |
| public static void main(String[] args) { |
| // Without regard to the order of member rebinding and apply mapping, |
| // this call should be mapped to X.bar(), not Y.bar() nor Base.foo(). |
| new Sub().foo(); |
| } |
| } |
| |
| @RunWith(Parameterized.class) |
| public class CompositionalLenseTest extends TestBase { |
| private final static List<Class> CLASSES = |
| ImmutableList.of(Base.class, Sub.class, CompositionalLenseTestMain.class); |
| |
| private Backend backend; |
| |
| @Parameterized.Parameters(name = "Backend: {0}") |
| public static Backend[] data() { |
| return Backend.values(); |
| } |
| |
| public CompositionalLenseTest(Backend backend) { |
| this.backend = backend; |
| } |
| |
| @Test |
| public void test() throws Exception { |
| Path mapPath = temp.newFile("test-mapping.txt").toPath(); |
| List<String> pgMap = ImmutableList.of( |
| "com.android.tools.r8.naming.applymapping.Base -> X:", |
| " void foo() -> bar", |
| "com.android.tools.r8.naming.applymapping.Sub -> Y:", |
| " void foo() -> bar" |
| ); |
| FileUtils.writeTextFile(mapPath, pgMap); |
| |
| AndroidApp app = readClasses(CLASSES); |
| R8Command.Builder builder = ToolHelper.prepareR8CommandBuilder(app, emptyConsumer(backend)); |
| builder |
| .addProguardConfiguration( |
| ImmutableList.of( |
| keepMainProguardConfiguration(CompositionalLenseTestMain.class), |
| "-applymapping " + mapPath, |
| "-dontobfuscate"), // to use the renamed names in test-mapping.txt |
| Origin.unknown()) |
| .addLibraryFiles(runtimeJar(backend)); |
| AndroidApp processedApp = |
| ToolHelper.runR8( |
| builder.build(), |
| options -> { |
| options.enableInlining = false; |
| options.enableVerticalClassMerging = false; |
| }); |
| CodeInspector codeInspector = new CodeInspector(processedApp); |
| ClassSubject classSubject = codeInspector.clazz(CompositionalLenseTestMain.class); |
| assertThat(classSubject, isPresent()); |
| MethodSubject methodSubject = classSubject.method(CodeInspector.MAIN); |
| assertThat(methodSubject, isPresent()); |
| Iterator<InstructionSubject> iterator = methodSubject.iterateInstructions(); |
| |
| InstructionSubject instruction = null; |
| boolean found = false; |
| while (iterator.hasNext()) { |
| instruction = iterator.next(); |
| if (instruction.isInvokeVirtual()) { |
| found = true; |
| break; |
| } |
| } |
| assertTrue(found); |
| |
| DexMethod invokedMethod = ((InvokeInstructionSubject) instruction).invokedMethod(); |
| assertEquals("bar", invokedMethod.name.toString()); |
| assertEquals("X", invokedMethod.getHolder().getName()); |
| } |
| } |