Merge "Add support for Proguard option -printconfiguration"
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index 5f27356..b5ec328 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -673,6 +673,13 @@
internal.outline.enabled = false;
}
+ // Setup a configuration consumer.
+ if (proguardConfiguration.isPrintConfiguration()) {
+ internal.configurationConsumer = proguardConfiguration.getPrintConfigurationFile() != null
+ ? new StringConsumer.FileConsumer(proguardConfiguration.getPrintConfigurationFile())
+ : new StringConsumer.StreamConsumer(StandardOutOrigin.instance(), System.out);
+ }
+
// Setup a usage information consumer.
if (proguardConfiguration.isPrintUsage()) {
internal.usageInformationConsumer = proguardConfiguration.getPrintUsageFile() != null
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
index b413bfe..30664a2 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
@@ -260,6 +260,11 @@
String deadCode,
ProguardMapSupplier proguardMapSupplier,
String proguardSeedsData) {
+ if (options.configurationConsumer != null) {
+ ExceptionUtils.withConsumeResourceHandler(
+ options.reporter, options.configurationConsumer,
+ options.proguardConfiguration.getParsedConfiguration());
+ }
if (options.usageInformationConsumer != null && deadCode != null) {
ExceptionUtils.withConsumeResourceHandler(
options.reporter, options.usageInformationConsumer, deadCode);
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
index c4a4478..2a31604a 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
@@ -20,6 +20,7 @@
public static class Builder {
+ private final List<String> parsedConfiguration = new ArrayList<>();
private final List<FilteredClassPath> injars = new ArrayList<>();
private final List<FilteredClassPath> libraryjars = new ArrayList<>();
private final Reporter reporter;
@@ -30,6 +31,8 @@
private boolean optimizing = true;
private boolean obfuscating = true;
private boolean shrinking = true;
+ private boolean printConfiguration;
+ private Path printConfigurationFile;
private boolean printUsage;
private Path printUsageFile;
private boolean printMapping;
@@ -59,6 +62,10 @@
this.reporter = reporter;
}
+ public void addParsedConfiguration(String source) {
+ parsedConfiguration.add(source);
+ }
+
public void addInjars(List<FilteredClassPath> injars) {
this.injars.addAll(injars);
}
@@ -113,6 +120,15 @@
shrinking = false;
}
+ public void setPrintConfiguration(boolean printConfiguration) {
+ this.printConfiguration = printConfiguration;
+ }
+
+ public void setPrintConfigurationFile(Path file) {
+ assert printConfiguration;
+ this.printConfigurationFile = file;
+ }
+
public void setPrintUsage(boolean printUsage) {
this.printUsage = printUsage;
}
@@ -217,6 +233,7 @@
public ProguardConfiguration buildRaw() {
ProguardConfiguration configuration = new ProguardConfiguration(
+ String.join(System.lineSeparator(), parsedConfiguration),
dexItemFactory,
injars,
libraryjars,
@@ -227,6 +244,8 @@
optimizing,
obfuscating,
shrinking,
+ printConfiguration,
+ printConfigurationFile,
printUsage,
printUsageFile,
printMapping,
@@ -279,6 +298,7 @@
}
}
+ private final String parsedConfiguration;
private final DexItemFactory dexItemFactory;
private final ImmutableList<FilteredClassPath> injars;
private final ImmutableList<FilteredClassPath> libraryjars;
@@ -289,6 +309,8 @@
private final boolean optimizing;
private final boolean obfuscating;
private final boolean shrinking;
+ private final boolean printConfiguration;
+ private final Path printConfigurationFile;
private final boolean printUsage;
private final Path printUsageFile;
private final boolean printMapping;
@@ -310,6 +332,7 @@
private final ProguardClassFilter adaptClassStrings;
private ProguardConfiguration(
+ String parsedConfiguration,
DexItemFactory factory,
List<FilteredClassPath> injars,
List<FilteredClassPath> libraryjars,
@@ -320,6 +343,8 @@
boolean optimizing,
boolean obfuscating,
boolean shrinking,
+ boolean printConfiguration,
+ Path printConfigurationFile,
boolean printUsage,
Path printUsageFile,
boolean printMapping,
@@ -339,6 +364,7 @@
boolean useUniqueClassMemberNames,
boolean keepParameterNames,
ProguardClassFilter adaptClassStrings) {
+ this.parsedConfiguration = parsedConfiguration;
this.dexItemFactory = factory;
this.injars = ImmutableList.copyOf(injars);
this.libraryjars = ImmutableList.copyOf(libraryjars);
@@ -349,6 +375,8 @@
this.optimizing = optimizing;
this.obfuscating = obfuscating;
this.shrinking = shrinking;
+ this.printConfiguration = printConfiguration;
+ this.printConfigurationFile = printConfigurationFile;
this.printUsage = printUsage;
this.printUsageFile = printUsageFile;
this.printMapping = printMapping;
@@ -378,6 +406,10 @@
return new Builder(dexItemFactory, reporter);
}
+ public String getParsedConfiguration() {
+ return parsedConfiguration;
+ }
+
public DexItemFactory getDexItemFactory() {
return dexItemFactory;
}
@@ -434,6 +466,14 @@
return shrinking;
}
+ public boolean isPrintConfiguration() {
+ return printConfiguration;
+ }
+
+ public Path getPrintConfigurationFile() {
+ return printConfigurationFile;
+ }
+
public boolean isPrintUsage() {
return printUsage;
}
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
index c1af9f4..3d426dd 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
@@ -70,7 +70,6 @@
"whyarenotsimple");
private static final List<String> WARNED_SINGLE_ARG_OPTIONS = ImmutableList.of(
- "printconfiguration",
// TODO -outjars (http://b/37137994) and -adaptresourcefilecontents (http://b/37139570)
// should be reported as errors, not just as warnings!
"outjars",
@@ -165,6 +164,7 @@
private final String name;
private final String contents;
private int position = 0;
+ private int positionAfterInclude = 0;
private int line = 1;
private int lineStartPosition = 0;
private Path baseDirectory;
@@ -181,6 +181,9 @@
do {
skipWhitespace();
} while (parseOption());
+ // Collect the parsed configuration.
+ configurationBuilder.addParsedConfiguration(
+ contents.substring(positionAfterInclude, contents.length()));
}
private boolean parseOption()
@@ -283,6 +286,12 @@
configurationBuilder.setOverloadAggressively(true);
} else if (acceptString("allowaccessmodification")) {
configurationBuilder.setAllowAccessModification(true);
+ } else if (acceptString("printconfiguration")) {
+ configurationBuilder.setPrintConfiguration(true);
+ skipWhitespace();
+ if (isOptionalArgumentGiven()) {
+ configurationBuilder.setPrintConfigurationFile(parseFileName());
+ }
} else if (acceptString("printmapping")) {
configurationBuilder.setPrintMapping(true);
skipWhitespace();
@@ -298,8 +307,12 @@
ProguardAssumeValuesRule rule = parseAssumeValuesRule();
configurationBuilder.addRule(rule);
} else if (acceptString("include")) {
+ // Collect the parsed configuration until the include.
+ configurationBuilder.addParsedConfiguration(
+ contents.substring(positionAfterInclude, position - ("include".length() + 1)));
skipWhitespace();
parseInclude();
+ positionAfterInclude = position;
} else if (acceptString("basedirectory")) {
skipWhitespace();
baseDirectory = parseFileName();
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index 42775d2..04c5f72 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -251,6 +251,10 @@
// If non-null, it must be and is passed to the consumer.
public StringConsumer usageInformationConsumer = null;
+ // If null, no configuration information needs to be printed.
+ // If non-null, configuration must be passed to the consumer.
+ public StringConsumer configurationConsumer = null;
+
public Path proguardCompatibilityRulesOutput = null;
public void warningMissingEnclosingMember(DexType clazz, Origin origin, int version) {
diff --git a/src/test/java/com/android/tools/r8/R8CommandTest.java b/src/test/java/com/android/tools/r8/R8CommandTest.java
index 5d7bec0..a89cbd4 100644
--- a/src/test/java/com/android/tools/r8/R8CommandTest.java
+++ b/src/test/java/com/android/tools/r8/R8CommandTest.java
@@ -373,6 +373,17 @@
}
@Test
+ public void printsConfigurationOnStdout() throws Throwable {
+ Path proguardPrintConfigurationConfiguration =
+ temp.newFile("printconfiguration.txt").toPath().toAbsolutePath();
+ FileUtils.writeTextFile(
+ proguardPrintConfigurationConfiguration, ImmutableList.of("-printconfiguration"));
+ ProcessResult result = runR8OnShaking1(proguardPrintConfigurationConfiguration);
+ assertEquals("R8 run failed: " + result.stderr, 0, result.exitCode);
+ assertTrue(result.stdout.contains("-printconfiguration"));
+ }
+
+ @Test
public void printsPrintSeedsOnStdout() throws Throwable {
Path proguardPrintSeedsConfiguration = temp.newFile("printseeds.txt").toPath().toAbsolutePath();
FileUtils.writeTextFile(proguardPrintSeedsConfiguration, ImmutableList.of("-printseeds"));
@@ -402,6 +413,21 @@
assertTrue(result.stdout.contains("shaking1.Unused"));
}
+ @Test
+ public void printsPrintSeedsAndPrintUsageAndPrintConfigurationOnStdout() throws Throwable {
+ Path proguardPrintSeedsConfiguration =
+ temp.newFile("printseedsandprintusageandprintconfiguration.txt").toPath().toAbsolutePath();
+ FileUtils.writeTextFile(proguardPrintSeedsConfiguration,
+ ImmutableList.of("-printseeds", "-printusage", "-printconfiguration"));
+ ProcessResult result = runR8OnShaking1(proguardPrintSeedsConfiguration);
+ assertEquals("R8 run failed: " + result.stderr, 0, result.exitCode);
+ assertTrue(result.stdout.contains("void main(java.lang.String[])"));
+ assertTrue(result.stdout.contains("shaking1.Unused"));
+ assertTrue(result.stdout.contains("-printseeds"));
+ assertTrue(result.stdout.contains("-printusage"));
+ assertTrue(result.stdout.contains("-printconfiguration"));
+ }
+
private R8Command parse(String... args) throws CompilationFailedException {
return R8Command.parse(args, EmbeddedOrigin.INSTANCE).build();
}
diff --git a/src/test/java/com/android/tools/r8/shaking/PrintConfigurationTest.java b/src/test/java/com/android/tools/r8/shaking/PrintConfigurationTest.java
new file mode 100644
index 0000000..7621522
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/shaking/PrintConfigurationTest.java
@@ -0,0 +1,56 @@
+// 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.shaking;
+
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.utils.FileUtils;
+import com.google.common.base.Charsets;
+import com.google.common.collect.ImmutableList;
+import java.nio.file.Path;
+import org.junit.Test;
+
+class PrintConfigurationTestClass {
+
+ public static void main(String[] args) {
+
+ }
+}
+
+public class PrintConfigurationTest extends TestBase {
+ @Test
+ public void testSingleCOnfiguration() throws Exception {
+ Class mainClass = PrintConfigurationTestClass.class;
+ String proguardConfig = keepMainProguardConfiguration(mainClass);
+ Path printConfigurationFile = temp.newFile().toPath();
+ proguardConfig += "\n-printconfiguration " + printConfigurationFile.toString();
+ compileWithR8(ImmutableList.of(mainClass), proguardConfig);
+ assertEquals(proguardConfig, FileUtils.readTextFile(printConfigurationFile, Charsets.UTF_8));
+ }
+
+ @Test
+ public void testIncludeFile() throws Exception {
+ Class mainClass = PrintConfigurationTestClass.class;
+ String includeProguardConfig = keepMainProguardConfiguration(mainClass);
+ Path includeFile = temp.newFile().toPath();
+ FileUtils.writeTextFile(includeFile, includeProguardConfig);
+ Path printConfigurationFile = temp.newFile().toPath();
+ String proguardConfig = String.join(System.lineSeparator(), ImmutableList.of(
+ "-include " + includeFile.toString(),
+ "-printconfiguration " + printConfigurationFile.toString()
+ ));
+
+ String expected = String.join(System.lineSeparator(), ImmutableList.of(
+ "", // The -include line turns into an empty line.
+ includeProguardConfig,
+ "", // Writing to the file adds an ending line separator
+ "", // An empty line is emitted between two parts
+ "-printconfiguration " + printConfigurationFile.toString()
+ ));
+ compileWithR8(ImmutableList.of(mainClass), proguardConfig);
+ assertEquals(expected, FileUtils.readTextFile(printConfigurationFile, Charsets.UTF_8));
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
index 5dc4ec6..83ae311 100644
--- a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
@@ -944,6 +944,32 @@
}
@Test
+ public void parse_printconfiguration_noArguments() throws Exception {
+ ProguardConfigurationParser parser =
+ new ProguardConfigurationParser(new DexItemFactory(), reporter);
+ parser.parse(createConfigurationForTesting(ImmutableList.of(
+ "-printconfiguration"
+ )));
+ verifyParserEndsCleanly();
+ ProguardConfiguration config = parser.getConfig();
+ assertTrue(config.isPrintConfiguration());
+ assertNull(config.getPrintConfigurationFile());
+ }
+
+ @Test
+ public void parse_printconfiguration_argument() throws Exception {
+ ProguardConfigurationParser parser =
+ new ProguardConfigurationParser(new DexItemFactory(), reporter);
+ parser.parse(createConfigurationForTesting(ImmutableList.of(
+ "-printconfiguration file_name"
+ )));
+ verifyParserEndsCleanly();
+ ProguardConfiguration config = parser.getConfig();
+ assertTrue(config.isPrintConfiguration());
+ assertEquals("./file_name", config.getPrintConfigurationFile().toString());
+ }
+
+ @Test
public void parsePrintUsage() throws Exception {
ProguardConfigurationParser parser =
new ProguardConfigurationParser(new DexItemFactory(), reporter);