| // 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.maindexlist.whyareyoukeeping; |
| |
| import static org.junit.Assert.assertEquals; |
| |
| import com.android.tools.r8.GenerateMainDexList; |
| import com.android.tools.r8.GenerateMainDexListCommand; |
| import com.android.tools.r8.R8FullTestBuilder; |
| import com.android.tools.r8.TestBase; |
| import com.android.tools.r8.ToolHelper; |
| import com.android.tools.r8.errors.Unreachable; |
| import com.android.tools.r8.experimental.graphinfo.GraphConsumer; |
| import com.android.tools.r8.origin.Origin; |
| import com.android.tools.r8.references.Reference; |
| import com.android.tools.r8.shaking.WhyAreYouKeepingConsumer; |
| import com.android.tools.r8.utils.AndroidApiLevel; |
| import com.android.tools.r8.utils.ListUtils; |
| import com.android.tools.r8.utils.StringUtils; |
| import com.google.common.collect.ImmutableList; |
| import java.io.ByteArrayOutputStream; |
| import java.io.PrintStream; |
| import java.util.List; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.junit.runners.Parameterized; |
| import org.junit.runners.Parameterized.Parameters; |
| |
| class HelloWorldMain { |
| public static void main(String[] args) { |
| System.out.println(new MainDexClass()); |
| } |
| } |
| |
| class MainDexClass {} |
| |
| class NonMainDexClass {} |
| |
| @RunWith(Parameterized.class) |
| public class MainDexListWhyAreYouKeeping extends TestBase { |
| |
| private static final List<Class<?>> CLASSES = |
| ImmutableList.of(HelloWorldMain.class, MainDexClass.class, NonMainDexClass.class); |
| |
| private enum Command { |
| R8, |
| Generator |
| } |
| |
| private enum ApiUse { |
| WhyAreYouKeepingRule, |
| KeptGraphConsumer |
| } |
| |
| @Parameters(name = "{0} {1}") |
| public static List<Object[]> parameters() { |
| return buildParameters(Command.values(), ApiUse.values()); |
| } |
| |
| private final Command command; |
| private final ApiUse apiUse; |
| |
| public MainDexListWhyAreYouKeeping(Command command, ApiUse apiUse) { |
| this.command = command; |
| this.apiUse = apiUse; |
| } |
| |
| public void runTestWithGenerator(GraphConsumer consumer, String rule) throws Exception { |
| GenerateMainDexListCommand.Builder builder = |
| GenerateMainDexListCommand.builder() |
| .addProgramFiles(ListUtils.map(CLASSES, ToolHelper::getClassFileForTestClass)) |
| .addLibraryFiles(ToolHelper.getDefaultAndroidJar()) |
| .addMainDexRules( |
| ImmutableList.of(keepMainProguardConfiguration(HelloWorldMain.class)), |
| Origin.unknown()) |
| .setMainDexKeptGraphConsumer(consumer); |
| if (rule != null) { |
| builder.addMainDexRules(ImmutableList.of(rule), Origin.unknown()); |
| } |
| GenerateMainDexList.run(builder.build()); |
| } |
| |
| public void runTestWithR8(GraphConsumer consumer, String rule) throws Exception { |
| R8FullTestBuilder builder = |
| testForR8(Backend.DEX) |
| .noTreeShaking() |
| .noMinification() |
| .setMinApi(AndroidApiLevel.K) |
| .addProgramClasses(CLASSES) |
| .addMainDexRules(keepMainProguardConfiguration(HelloWorldMain.class)) |
| .setMainDexKeptGraphConsumer(consumer); |
| if (rule != null) { |
| builder.addMainDexRules(rule); |
| } |
| builder.compile(); |
| } |
| |
| private String runTest(Class clazz) throws Exception { |
| PrintStream stdout = System.out; |
| ByteArrayOutputStream baos = new ByteArrayOutputStream(); |
| String rule = null; |
| WhyAreYouKeepingConsumer consumer = null; |
| if (apiUse == ApiUse.KeptGraphConsumer) { |
| consumer = new WhyAreYouKeepingConsumer(null); |
| } else { |
| assert apiUse == ApiUse.WhyAreYouKeepingRule; |
| rule = "-whyareyoukeeping class " + clazz.getTypeName(); |
| System.setOut(new PrintStream(baos)); |
| } |
| switch (command) { |
| case R8: |
| runTestWithR8(consumer, rule); |
| break; |
| case Generator: |
| runTestWithGenerator(consumer, rule); |
| break; |
| default: |
| throw new Unreachable(); |
| } |
| if (consumer != null) { |
| consumer.printWhyAreYouKeeping(Reference.classFromClass(clazz), new PrintStream(baos)); |
| } else { |
| System.setOut(stdout); |
| } |
| return baos.toString(); |
| } |
| |
| @Test |
| public void testMainDexClassWhyAreYouKeeping() throws Exception { |
| String expected = |
| StringUtils.lines( |
| "com.android.tools.r8.maindexlist.whyareyoukeeping.MainDexClass", |
| "|- is instantiated in:", |
| "| void " + HelloWorldMain.class.getTypeName() + ".main(java.lang.String[])", |
| "|- is referenced in keep rule:", |
| "| -keep class " + HelloWorldMain.class.getTypeName() + " {", |
| "| public static void main(java.lang.String[]);", |
| "| }"); |
| assertEquals(expected, runTest(MainDexClass.class)); |
| } |
| |
| @Test |
| public void testNonMainDexWhyAreYouKeeping() throws Exception { |
| String expected = |
| StringUtils.lines( |
| "Nothing is keeping com.android.tools.r8.maindexlist.whyareyoukeeping.NonMainDexClass"); |
| assertEquals(expected, runTest(NonMainDexClass.class)); |
| } |
| } |