Version 1.3.53
Cherry-pick: Avoid using 'R' as a renamed class name.
CL: https://r8-review.googlesource.com/c/r8/+/33240
along with lots of test infra updates.
Also, update AvoidRTest a bit since 1.3 branch still has a default keep
rule behavior.
Bug: 123092153, 122937067
Change-Id: I64e448a4561e7e073d70e1132a8fe5f13cf67266
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index ff38d1b..58aecf0 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -78,6 +78,7 @@
private final List<ProguardConfigurationSource> mainDexRules = new ArrayList<>();
private Consumer<ProguardConfiguration.Builder> proguardConfigurationConsumer = null;
+ private Consumer<List<ProguardConfigurationRule>> syntheticProguardRulesConsumer = null;
private final List<ProguardConfigurationSource> proguardConfigs = new ArrayList<>();
private boolean disableTreeShaking = false;
private boolean disableMinification = false;
@@ -463,6 +464,15 @@
};
}
+ void addSyntheticProguardRulesConsumerForTesting(
+ Consumer<List<ProguardConfigurationRule>> consumer) {
+ syntheticProguardRulesConsumer =
+ syntheticProguardRulesConsumer == null
+ ? consumer
+ : syntheticProguardRulesConsumer.andThen(consumer);
+
+ }
+
// Internal for-testing method to add post-processors of the proguard configuration.
void allowPartiallyImplementedProguardOptions() {
allowPartiallyImplementedProguardOptions = true;
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index 6438e9b..2cedaf5 100644
--- a/src/main/java/com/android/tools/r8/Version.java
+++ b/src/main/java/com/android/tools/r8/Version.java
@@ -11,7 +11,7 @@
// This field is accessed from release scripts using simple pattern matching.
// Therefore, changing this field could break our release scripts.
- public static final String LABEL = "1.3.52";
+ public static final String LABEL = "1.3.53";
private Version() {
}
diff --git a/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java b/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java
index ecf7158..f74009e 100644
--- a/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java
@@ -455,6 +455,11 @@
.toCharArray();
this.packageDictionaryIterator = packageDictionary.iterator();
this.classDictionaryIterator = classDictionary.iterator();
+
+ // R.class in Android, which contains constant IDs to assets, can be bundled at any time.
+ // Insert `R` immediately so that the class name minifier can skip that name by default.
+ StringBuilder rBuilder = new StringBuilder().append(packagePrefix).append("R;");
+ usedTypeNames.add(appInfo.dexItemFactory.createString(rBuilder.toString()));
}
public String getPackageName() {
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 ec157e9..2f351ed 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -46,6 +46,11 @@
}
public final DexItemFactory itemFactory;
+
+ public ProguardConfiguration getProguardConfiguration() {
+ return proguardConfiguration;
+ }
+
public final ProguardConfiguration proguardConfiguration;
public final Reporter reporter;
diff --git a/src/test/java/com/android/tools/r8/D8TestCompileResult.java b/src/test/java/com/android/tools/r8/D8TestCompileResult.java
index 178d351..21d7af9 100644
--- a/src/test/java/com/android/tools/r8/D8TestCompileResult.java
+++ b/src/test/java/com/android/tools/r8/D8TestCompileResult.java
@@ -7,18 +7,23 @@
import com.android.tools.r8.ToolHelper.ProcessResult;
import com.android.tools.r8.utils.AndroidApp;
-public class D8TestCompileResult extends TestCompileResult<D8TestRunResult> {
+public class D8TestCompileResult extends TestCompileResult<D8TestCompileResult, D8TestRunResult> {
D8TestCompileResult(TestState state, AndroidApp app) {
super(state, app);
}
@Override
+ public D8TestCompileResult self() {
+ return this;
+ }
+
+ @Override
public Backend getBackend() {
return Backend.DEX;
}
@Override
- public D8TestRunResult createRunResult(AndroidApp app, ProcessResult result) {
+ public D8TestRunResult createRunResult(ProcessResult result) {
return new D8TestRunResult(app, result);
}
}
diff --git a/src/test/java/com/android/tools/r8/D8TestRunResult.java b/src/test/java/com/android/tools/r8/D8TestRunResult.java
index d14f12d..1aa095a 100644
--- a/src/test/java/com/android/tools/r8/D8TestRunResult.java
+++ b/src/test/java/com/android/tools/r8/D8TestRunResult.java
@@ -7,9 +7,14 @@
import com.android.tools.r8.ToolHelper.ProcessResult;
import com.android.tools.r8.utils.AndroidApp;
-public class D8TestRunResult extends TestRunResult {
+public class D8TestRunResult extends TestRunResult<D8TestRunResult> {
public D8TestRunResult(AndroidApp app, ProcessResult result) {
super(app, result);
}
+
+ @Override
+ protected D8TestRunResult self() {
+ return this;
+ }
}
diff --git a/src/test/java/com/android/tools/r8/DXTestCompileResult.java b/src/test/java/com/android/tools/r8/DXTestCompileResult.java
index fa1f314..2de0a67 100644
--- a/src/test/java/com/android/tools/r8/DXTestCompileResult.java
+++ b/src/test/java/com/android/tools/r8/DXTestCompileResult.java
@@ -7,19 +7,24 @@
import com.android.tools.r8.ToolHelper.ProcessResult;
import com.android.tools.r8.utils.AndroidApp;
-public class DXTestCompileResult extends TestCompileResult<DXTestRunResult> {
+public class DXTestCompileResult extends TestCompileResult<DXTestCompileResult, DXTestRunResult> {
DXTestCompileResult(TestState state, AndroidApp app) {
super(state, app);
}
@Override
+ public DXTestCompileResult self() {
+ return this;
+ }
+
+ @Override
public Backend getBackend() {
return Backend.DEX;
}
@Override
- public DXTestRunResult createRunResult(AndroidApp app, ProcessResult result) {
+ public DXTestRunResult createRunResult(ProcessResult result) {
return new DXTestRunResult(app, result);
}
}
diff --git a/src/test/java/com/android/tools/r8/DXTestRunResult.java b/src/test/java/com/android/tools/r8/DXTestRunResult.java
index c1df193..830cbd8 100644
--- a/src/test/java/com/android/tools/r8/DXTestRunResult.java
+++ b/src/test/java/com/android/tools/r8/DXTestRunResult.java
@@ -7,9 +7,14 @@
import com.android.tools.r8.ToolHelper.ProcessResult;
import com.android.tools.r8.utils.AndroidApp;
-public class DXTestRunResult extends TestRunResult {
+public class DXTestRunResult extends TestRunResult<DXTestRunResult> {
public DXTestRunResult(AndroidApp app, ProcessResult result) {
super(app, result);
}
+
+ @Override
+ protected DXTestRunResult self() {
+ return this;
+ }
}
diff --git a/src/test/java/com/android/tools/r8/JvmTestBuilder.java b/src/test/java/com/android/tools/r8/JvmTestBuilder.java
index 4e0bedf..9c9a977 100644
--- a/src/test/java/com/android/tools/r8/JvmTestBuilder.java
+++ b/src/test/java/com/android/tools/r8/JvmTestBuilder.java
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8;
+import com.android.tools.r8.ProgramResource.Kind;
import com.android.tools.r8.ToolHelper.ProcessResult;
import com.android.tools.r8.debug.CfDebugTestConfig;
import com.android.tools.r8.debug.DebugTestConfig;
@@ -24,7 +25,7 @@
import java.util.List;
import java.util.Set;
-public class JvmTestBuilder extends TestBuilder<JvmTestBuilder> {
+public class JvmTestBuilder extends TestBuilder<JvmTestRunResult, JvmTestBuilder> {
private static class ClassFileResource implements ProgramResource {
@@ -107,9 +108,9 @@
}
@Override
- public TestRunResult run(String mainClass) throws IOException {
+ public JvmTestRunResult run(String mainClass) throws IOException {
ProcessResult result = ToolHelper.runJava(classpath, mainClass);
- return new TestRunResult(builder.build(), result);
+ return new JvmTestRunResult(builder.build(), result);
}
@Override
@@ -124,20 +125,7 @@
@Override
public JvmTestBuilder addProgramClasses(Collection<Class<?>> classes) {
- // Adding a collection of classes will build a jar of exactly those classes so that no other
- // classes are made available via a too broad classpath directory.
- List<ProgramResource> resources = ListUtils.map(classes, ClassFileResource::new);
- AndroidApp build = AndroidApp.builder()
- .addProgramResourceProvider(new ClassFileResourceProvider(resources)).build();
- Path out;
- try {
- out = getState().getNewTempFolder().resolve("out.zip");
- build.writeToZip(out, OutputMode.ClassFile);
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- classpath.add(out);
- builder.addProgramFiles(out);
+ addProgramResources(ListUtils.map(classes, ClassFileResource::new));
return self();
}
@@ -147,6 +135,18 @@
"No support for adding paths directly (we need to compute the descriptor)");
}
+ @Override
+ public JvmTestBuilder addProgramClassFileData(Collection<byte[]> files) {
+ addProgramResources(
+ ListUtils.map(files, data ->
+ ProgramResource.fromBytes(
+ Origin.unknown(),
+ Kind.CF,
+ data,
+ Collections.singleton(TestBase.extractClassDescriptor(data)))));
+ return self();
+ }
+
public JvmTestBuilder addClasspath(Path... paths) {
return addClasspath(Arrays.asList(paths));
}
@@ -162,4 +162,22 @@
public JvmTestBuilder addTestClasspath() {
return addClasspath(ToolHelper.getClassPathForTests());
}
+
+ // Adding a collection of resources will build a jar of exactly those classes so that no other
+ // classes are made available via a too broad classpath directory.
+ private void addProgramResources(List<ProgramResource> resources) {
+ AndroidApp build =
+ AndroidApp.builder()
+ .addProgramResourceProvider(new ClassFileResourceProvider(resources))
+ .build();
+ Path out;
+ try {
+ out = getState().getNewTempFolder().resolve("out.zip");
+ build.writeToZip(out, OutputMode.ClassFile);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ classpath.add(out);
+ builder.addProgramFiles(out);
+ }
}
diff --git a/src/test/java/com/android/tools/r8/JvmTestRunResult.java b/src/test/java/com/android/tools/r8/JvmTestRunResult.java
new file mode 100644
index 0000000..b7a71fd
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/JvmTestRunResult.java
@@ -0,0 +1,20 @@
+// 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;
+
+import com.android.tools.r8.ToolHelper.ProcessResult;
+import com.android.tools.r8.utils.AndroidApp;
+
+public class JvmTestRunResult extends TestRunResult<JvmTestRunResult> {
+
+ public JvmTestRunResult(AndroidApp app, ProcessResult result) {
+ super(app, result);
+ }
+
+ @Override
+ protected JvmTestRunResult self() {
+ return this;
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/ProguardTestBuilder.java b/src/test/java/com/android/tools/r8/ProguardTestBuilder.java
index 28ce1e6..0841770 100644
--- a/src/test/java/com/android/tools/r8/ProguardTestBuilder.java
+++ b/src/test/java/com/android/tools/r8/ProguardTestBuilder.java
@@ -6,9 +6,11 @@
import com.android.tools.r8.R8Command.Builder;
import com.android.tools.r8.TestBase.Backend;
import com.android.tools.r8.ToolHelper.ProcessResult;
+import com.android.tools.r8.debug.DebugTestConfig;
import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.origin.PathOrigin;
+import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.FileUtils;
@@ -98,9 +100,16 @@
// Ordered list of injar entries.
private List<Path> injars = new ArrayList<>();
+
+ // Ordered list of libraryjar entries.
+ private List<Path> libraryjars = new ArrayList<>();
+
// Proguard configuration file lines.
private List<String> config = new ArrayList<>();
+ // Additional Proguard configuration files.
+ private List<Path> proguardConfigFiles = new ArrayList<>();
+
private ProguardTestBuilder(TestState state, Builder builder, Backend backend) {
super(state, builder, backend);
}
@@ -132,26 +141,40 @@
command.add("-injars");
command.add(injar.toString());
}
- command.add("-libraryjars");
- // TODO(sgjesse): Add support for running with Android Jar.
- // command.add(ToolHelper.getAndroidJar(AndroidApiLevel.P).toString());
- command.add(ToolHelper.getJava8RuntimeJar().toString());
+ for (Path libraryjar : libraryjars) {
+ command.add("-libraryjars");
+ command.add(libraryjar.toString());
+ }
+ if (libraryjars.isEmpty()) {
+ command.add("-libraryjars");
+ // TODO(sgjesse): Add support for running with Android Jar.
+ // command.add(ToolHelper.getAndroidJar(AndroidApiLevel.P).toString());
+ command.add(ToolHelper.getJava8RuntimeJar().toString());
+ }
command.add("-include");
command.add(configFile.toString());
+ for (Path proguardConfigFile : proguardConfigFiles) {
+ command.add("-include");
+ command.add(proguardConfigFile.toAbsolutePath().toString());
+ }
command.add("-outjar");
command.add(outJar.toString());
command.add("-printmapping");
command.add(mapFile.toString());
+ if (!enableTreeShaking) {
+ command.add("-dontshrink");
+ }
+ if (!enableMinification) {
+ command.add("-dontobfuscate");
+ }
ProcessBuilder pbuilder = new ProcessBuilder(command);
ProcessResult result = ToolHelper.runProcess(pbuilder);
if (result.exitCode != 0) {
throw new CompilationFailedException(result.toString());
}
- AndroidApp.Builder aaabuilder = AndroidApp.builder();
- aaabuilder.addProgramFiles(outJar);
String proguardMap =
Files.exists(mapFile) ? FileUtils.readTextFile(mapFile, Charsets.UTF_8) : "";
- return new ProguardTestCompileResult(getState(), aaabuilder.build(), proguardMap);
+ return new ProguardTestCompileResult(getState(), outJar, proguardMap);
} catch (IOException e) {
throw new CompilationFailedException(e);
}
@@ -179,8 +202,27 @@
@Override
public ProguardTestBuilder addProgramFiles(Collection<Path> files) {
+ for (Path file : files) {
+ if (FileUtils.isJarFile(file)) {
+ injars.add(file);
+ } else {
+ throw new Unimplemented(
+ "No support for adding class files directly (we need to compute the descriptor)");
+ }
+ }
+ return self();
+ }
+
+ @Override
+ public ProguardTestBuilder addProgramClassFileData(Collection<byte[]> classes) {
throw new Unimplemented(
- "No support for adding paths directly (we need to compute the descriptor)");
+ "No support for adding class files directly (we need to compute the descriptor)");
+ }
+
+ @Override
+ public ProguardTestBuilder addKeepRuleFiles(List<Path> proguardConfigFiles) {
+ this.proguardConfigFiles.addAll(proguardConfigFiles);
+ return self();
}
@Override
@@ -188,4 +230,51 @@
config.addAll(rules);
return self();
}
+ @Override
+ public ProguardTestBuilder addLibraryFiles(Collection<Path> files) {
+ for (Path file : files) {
+ if (FileUtils.isJarFile(file)) {
+ libraryjars.add(file);
+ } else {
+ throw new Unimplemented(
+ "No support for adding class files directly (we need to compute the descriptor)");
+ }
+ }
+ return self();
+ }
+
+ @Override
+ public ProguardTestBuilder setProgramConsumer(ProgramConsumer programConsumer) {
+ throw new Unimplemented("No support for program consumer");
+ }
+
+ @Override
+ public ProguardTestBuilder setMinApi(AndroidApiLevel minApiLevel) {
+ throw new Unimplemented("No support for setting min api");
+ }
+
+ @Override
+ public ProguardTestBuilder addMainDexListFiles(Collection<Path> files) {
+ throw new Unimplemented("No support for adding main dex list files");
+ }
+
+ @Override
+ public ProguardTestBuilder setMode(CompilationMode mode) {
+ throw new Unimplemented("No support for setting compilation mode");
+ }
+
+ @Override
+ public ProguardTestBuilder noDesugaring() {
+ throw new Unimplemented("No support for disabling desugaring");
+ }
+
+ @Override
+ public DebugTestConfig debugConfig() {
+ throw new Unimplemented("No support for debug config");
+ }
+
+ @Override
+ public ProguardTestBuilder addOptionsModification(Consumer<InternalOptions> optionsConsumer) {
+ throw new Unimplemented("No support for changing internal options");
+ }
}
diff --git a/src/test/java/com/android/tools/r8/ProguardTestCompileResult.java b/src/test/java/com/android/tools/r8/ProguardTestCompileResult.java
index bef1e02..34144c7 100644
--- a/src/test/java/com/android/tools/r8/ProguardTestCompileResult.java
+++ b/src/test/java/com/android/tools/r8/ProguardTestCompileResult.java
@@ -8,17 +8,30 @@
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import java.io.IOException;
+import java.nio.file.Path;
import java.util.concurrent.ExecutionException;
-public class ProguardTestCompileResult extends TestCompileResult<ProguardTestRunResult> {
+public class ProguardTestCompileResult
+ extends TestCompileResult<ProguardTestCompileResult, ProguardTestRunResult> {
+ private final Path outputJar;
private final String proguardMap;
- ProguardTestCompileResult(TestState state, AndroidApp app, String proguardMap) {
- super(state, app);
+ ProguardTestCompileResult(TestState state, Path outputJar, String proguardMap) {
+ super(state, AndroidApp.builder().addProgramFiles(outputJar).build());
+ this.outputJar = outputJar;
this.proguardMap = proguardMap;
}
+ public Path outputJar() {
+ return outputJar;
+ }
+
+ @Override
+ public ProguardTestCompileResult self() {
+ return this;
+ }
+
@Override
public Backend getBackend() {
return Backend.CF;
@@ -30,7 +43,7 @@
}
@Override
- public ProguardTestRunResult createRunResult(AndroidApp app, ProcessResult result) {
+ public ProguardTestRunResult createRunResult(ProcessResult result) {
return new ProguardTestRunResult(app, result, proguardMap);
}
}
diff --git a/src/test/java/com/android/tools/r8/ProguardTestRunResult.java b/src/test/java/com/android/tools/r8/ProguardTestRunResult.java
index 9e0d875..e242a38 100644
--- a/src/test/java/com/android/tools/r8/ProguardTestRunResult.java
+++ b/src/test/java/com/android/tools/r8/ProguardTestRunResult.java
@@ -12,7 +12,7 @@
import java.io.IOException;
import java.util.concurrent.ExecutionException;
-public class ProguardTestRunResult extends TestRunResult {
+public class ProguardTestRunResult extends TestRunResult<ProguardTestRunResult> {
private final String proguardMap;
@@ -22,6 +22,11 @@
}
@Override
+ protected ProguardTestRunResult self() {
+ return this;
+ }
+
+ @Override
public CodeInspector inspector() throws IOException, ExecutionException {
// See comment in base class.
assertSuccess();
diff --git a/src/test/java/com/android/tools/r8/R8TestBuilder.java b/src/test/java/com/android/tools/r8/R8TestBuilder.java
index 5550415..3be4e00 100644
--- a/src/test/java/com/android/tools/r8/R8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/R8TestBuilder.java
@@ -7,8 +7,11 @@
import com.android.tools.r8.TestBase.Backend;
import com.android.tools.r8.TestBase.R8Mode;
import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.shaking.ProguardConfiguration;
+import com.android.tools.r8.shaking.ProguardConfigurationRule;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.InternalOptions;
+import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@@ -32,6 +35,7 @@
private boolean enableInliningAnnotations = false;
private boolean enableClassInliningAnnotations = false;
private boolean enableMergeAnnotations = false;
+ private List<String> keepRules = new ArrayList<>();
@Override
R8TestBuilder self() {
@@ -45,10 +49,32 @@
if (enableInliningAnnotations || enableClassInliningAnnotations || enableMergeAnnotations) {
ToolHelper.allowTestProguardOptions(builder);
}
+ if (!keepRules.isEmpty()) {
+ builder.addProguardConfiguration(keepRules, Origin.unknown());
+ }
StringBuilder proguardMapBuilder = new StringBuilder();
+ builder.setDisableTreeShaking(!enableTreeShaking);
+ builder.setDisableMinification(!enableMinification);
builder.setProguardMapConsumer((string, ignore) -> proguardMapBuilder.append(string));
- ToolHelper.runR8WithoutResult(builder.build(), optionsConsumer);
- return new R8TestCompileResult(getState(), backend, app.get(), proguardMapBuilder.toString());
+
+ class Box {
+ private List<ProguardConfigurationRule> syntheticProguardRules;
+ private ProguardConfiguration proguardConfiguration;
+ }
+ Box box = new Box();
+ ToolHelper.addSyntheticProguardRulesConsumerForTesting(
+ builder, rules -> box.syntheticProguardRules = rules);
+ ToolHelper.runR8WithoutResult(
+ builder.build(),
+ optionsConsumer.andThen(
+ options -> box.proguardConfiguration = options.getProguardConfiguration()));
+ return new R8TestCompileResult(
+ getState(),
+ backend,
+ app.get(),
+ box.proguardConfiguration,
+ box.syntheticProguardRules,
+ proguardMapBuilder.toString());
}
public R8TestBuilder addDataResources(List<DataEntryResource> resources) {
@@ -57,8 +83,16 @@
}
@Override
+ public R8TestBuilder addKeepRuleFiles(List<Path> files) {
+ builder.addProguardConfigurationFiles(files);
+ return self();
+ }
+
+ @Override
public R8TestBuilder addKeepRules(Collection<String> rules) {
- builder.addProguardConfiguration(new ArrayList<>(rules), Origin.unknown());
+ // Delay adding the actual rules so that we only associate a single origin and unique lines to
+ // each actual rule.
+ keepRules.addAll(rules);
return self();
}
diff --git a/src/test/java/com/android/tools/r8/R8TestCompileResult.java b/src/test/java/com/android/tools/r8/R8TestCompileResult.java
index 35cb176..149b5df 100644
--- a/src/test/java/com/android/tools/r8/R8TestCompileResult.java
+++ b/src/test/java/com/android/tools/r8/R8TestCompileResult.java
@@ -5,23 +5,42 @@
import com.android.tools.r8.TestBase.Backend;
import com.android.tools.r8.ToolHelper.ProcessResult;
+import com.android.tools.r8.shaking.ProguardConfiguration;
+import com.android.tools.r8.shaking.ProguardConfigurationRule;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import java.io.IOException;
+import java.util.List;
import java.util.concurrent.ExecutionException;
+import java.util.function.Consumer;
-public class R8TestCompileResult extends TestCompileResult<R8TestRunResult> {
+public class R8TestCompileResult extends TestCompileResult<R8TestCompileResult, R8TestRunResult> {
private final Backend backend;
+ private final ProguardConfiguration proguardConfiguration;
+ private final List<ProguardConfigurationRule> syntheticProguardRules;
private final String proguardMap;
- R8TestCompileResult(TestState state, Backend backend, AndroidApp app, String proguardMap) {
+ R8TestCompileResult(
+ TestState state,
+ Backend backend,
+ AndroidApp app,
+ ProguardConfiguration proguardConfiguration,
+ List<ProguardConfigurationRule> syntheticProguardRules,
+ String proguardMap) {
super(state, app);
this.backend = backend;
+ this.proguardConfiguration = proguardConfiguration;
+ this.syntheticProguardRules = syntheticProguardRules;
this.proguardMap = proguardMap;
}
@Override
+ public R8TestCompileResult self() {
+ return this;
+ }
+
+ @Override
public Backend getBackend() {
return backend;
}
@@ -31,8 +50,28 @@
return new CodeInspector(app, proguardMap);
}
+ public ProguardConfiguration getProguardConfiguration() {
+ return proguardConfiguration;
+ }
+
+ public R8TestCompileResult inspectProguardConfiguration(
+ Consumer<ProguardConfiguration> consumer) {
+ consumer.accept(getProguardConfiguration());
+ return self();
+ }
+
+ public List<ProguardConfigurationRule> getSyntheticProguardRules() {
+ return syntheticProguardRules;
+ }
+
+ public R8TestCompileResult inspectSyntheticProguardRules(
+ Consumer<List<ProguardConfigurationRule>> consumer) {
+ consumer.accept(getSyntheticProguardRules());
+ return self();
+ }
+
@Override
- public R8TestRunResult createRunResult(AndroidApp app, ProcessResult result) {
+ public R8TestRunResult createRunResult(ProcessResult result) {
return new R8TestRunResult(app, result, proguardMap);
}
}
diff --git a/src/test/java/com/android/tools/r8/R8TestRunResult.java b/src/test/java/com/android/tools/r8/R8TestRunResult.java
index 2c42b95..2203c84 100644
--- a/src/test/java/com/android/tools/r8/R8TestRunResult.java
+++ b/src/test/java/com/android/tools/r8/R8TestRunResult.java
@@ -12,20 +12,32 @@
import java.io.IOException;
import java.util.concurrent.ExecutionException;
-public class R8TestRunResult extends TestRunResult {
+public class R8TestRunResult extends TestRunResult<R8TestRunResult> {
private final String proguardMap;
- public R8TestRunResult(AndroidApp app, ProcessResult result, String proguardMap) {
+ public R8TestRunResult(
+ AndroidApp app,
+ ProcessResult result,
+ String proguardMap) {
super(app, result);
this.proguardMap = proguardMap;
}
@Override
+ protected R8TestRunResult self() {
+ return this;
+ }
+
+ @Override
public CodeInspector inspector() throws IOException, ExecutionException {
// See comment in base class.
assertSuccess();
assertNotNull(app);
return new CodeInspector(app, proguardMap);
}
+
+ public String proguardMap() {
+ return proguardMap;
+ }
}
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java
index a839c6f..a95ccfc 100644
--- a/src/test/java/com/android/tools/r8/TestBase.java
+++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -772,7 +772,15 @@
}
}
- private String extractClassName(byte[] ccc) {
+ public static String extractClassName(byte[] ccc) {
+ return DescriptorUtils.descriptorToJavaType(extractClassDescriptor(ccc));
+ }
+
+ public static String extractClassDescriptor(byte[] ccc) {
+ return "L" + extractClassInternalType(ccc) + ";";
+ }
+
+ private static String extractClassInternalType(byte[] ccc) {
class ClassNameExtractor extends ClassVisitor {
private String className;
@@ -788,13 +796,10 @@
String signature,
String superName,
String[] interfaces) {
- className =
- name.replace(
- DescriptorUtils.DESCRIPTOR_PACKAGE_SEPARATOR,
- DescriptorUtils.JAVA_PACKAGE_SEPARATOR);
+ className = name;
}
- String getClassName() {
+ String getClassInternalType() {
return className;
}
}
@@ -803,7 +808,7 @@
ClassNameExtractor extractor = new ClassNameExtractor();
reader.accept(
extractor, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
- return extractor.getClassName();
+ return extractor.getClassInternalType();
}
protected Path writeToJar(List<byte[]> classes) throws IOException {
diff --git a/src/test/java/com/android/tools/r8/TestBaseBuilder.java b/src/test/java/com/android/tools/r8/TestBaseBuilder.java
new file mode 100644
index 0000000..5fcd1b5
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/TestBaseBuilder.java
@@ -0,0 +1,50 @@
+// 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;
+
+import com.android.tools.r8.origin.Origin;
+import java.nio.file.Path;
+import java.util.Collection;
+
+public abstract class TestBaseBuilder<
+ C extends BaseCommand,
+ B extends BaseCommand.Builder<C, B>,
+ CR extends TestBaseResult<CR, RR>,
+ RR extends TestRunResult,
+ T extends TestBaseBuilder<C, B, CR, RR, T>>
+ extends TestBuilder<RR, T> {
+
+ final B builder;
+
+ TestBaseBuilder(TestState state, B builder) {
+ super(state);
+ this.builder = builder;
+ }
+
+ @Override
+ public T addProgramClassFileData(Collection<byte[]> classes) {
+ for (byte[] clazz : classes) {
+ builder.addClassProgramData(clazz, Origin.unknown());
+ }
+ return self();
+ }
+
+ @Override
+ public T addProgramFiles(Collection<Path> files) {
+ builder.addProgramFiles(files);
+ return self();
+ }
+
+ @Override
+ public T addLibraryFiles(Collection<Path> files) {
+ builder.addLibraryFiles(files);
+ return self();
+ }
+
+ public T addMainDexListFiles(Collection<Path> files) {
+ builder.addMainDexListFiles(files);
+ return self();
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/TestBaseResult.java b/src/test/java/com/android/tools/r8/TestBaseResult.java
new file mode 100644
index 0000000..e7623a3
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/TestBaseResult.java
@@ -0,0 +1,15 @@
+// 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;
+
+public abstract class TestBaseResult<CR extends TestBaseResult<CR, RR>, RR extends TestRunResult> {
+ final TestState state;
+
+ TestBaseResult(TestState state) {
+ this.state = state;
+ }
+
+ public abstract CR self();
+}
diff --git a/src/test/java/com/android/tools/r8/TestBuilder.java b/src/test/java/com/android/tools/r8/TestBuilder.java
index 4977d94..c67c05c 100644
--- a/src/test/java/com/android/tools/r8/TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestBuilder.java
@@ -3,18 +3,14 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8;
-import static com.android.tools.r8.utils.FileUtils.CLASS_EXTENSION;
-
import com.android.tools.r8.debug.DebugTestConfig;
import com.android.tools.r8.utils.ListUtils;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collection;
-import java.util.HashSet;
-import java.util.Set;
-public abstract class TestBuilder<T extends TestBuilder<T>> {
+public abstract class TestBuilder<RR extends TestRunResult, T extends TestBuilder<RR, T>> {
private final TestState state;
@@ -28,10 +24,10 @@
abstract T self();
- public abstract TestRunResult run(String mainClass)
+ public abstract RR run(String mainClass)
throws IOException, CompilationFailedException;
- public TestRunResult run(Class mainClass) throws IOException, CompilationFailedException {
+ public RR run(Class mainClass) throws IOException, CompilationFailedException {
return run(mainClass.getTypeName());
}
@@ -39,6 +35,12 @@
public abstract T addProgramFiles(Collection<Path> files);
+ public abstract T addProgramClassFileData(Collection<byte[]> classes);
+
+ public T addProgramClassFileData(byte[]... classes) {
+ return addProgramClassFileData(Arrays.asList(classes));
+ }
+
public T addProgramClasses(Class<?>... classes) {
return addProgramClasses(Arrays.asList(classes));
}
@@ -86,14 +88,6 @@
}
static Collection<Path> getFilesForInnerClasses(Collection<Class<?>> classes) throws IOException {
- Set<Path> paths = new HashSet<>();
- for (Class clazz : classes) {
- Path path = ToolHelper.getClassFileForTestClass(clazz);
- String prefix = path.toString().replace(CLASS_EXTENSION, "$");
- paths.addAll(
- ToolHelper.getClassFilesForTestDirectory(
- path.getParent(), p -> p.toString().startsWith(prefix)));
- }
- return paths;
+ return ToolHelper.getClassFilesForInnerClasses(classes);
}
}
diff --git a/src/test/java/com/android/tools/r8/TestCompileResult.java b/src/test/java/com/android/tools/r8/TestCompileResult.java
index 12d1990..acc76bf 100644
--- a/src/test/java/com/android/tools/r8/TestCompileResult.java
+++ b/src/test/java/com/android/tools/r8/TestCompileResult.java
@@ -11,25 +11,32 @@
import com.android.tools.r8.debug.DebugTestConfig;
import com.android.tools.r8.debug.DexDebugTestConfig;
import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.graph.invokesuper.Consumer;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
import java.util.concurrent.ExecutionException;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
-public abstract class TestCompileResult<RR extends TestRunResult> {
- final TestState state;
+public abstract class TestCompileResult<
+ CR extends TestCompileResult<CR, RR>, RR extends TestRunResult>
+ extends TestBaseResult<CR, RR> {
+
public final AndroidApp app;
+ final List<Path> additionalRunClassPath = new ArrayList<>();
TestCompileResult(TestState state, AndroidApp app) {
- this.state = state;
+ super(state);
this.app = app;
}
public abstract Backend getBackend();
- protected abstract RR createRunResult(AndroidApp add, ProcessResult result);
+ protected abstract RR createRunResult(ProcessResult result);
public RR run(Class<?> mainClass) throws IOException {
return run(mainClass.getTypeName());
@@ -38,27 +45,31 @@
public RR run(String mainClass) throws IOException {
switch (getBackend()) {
case DEX:
- return runArt(mainClass);
+ return runArt(additionalRunClassPath, mainClass);
case CF:
- return runJava(mainClass);
+ return runJava(additionalRunClassPath, mainClass);
default:
throw new Unreachable();
}
}
- public TestCompileResult writeToZip(Path file) throws IOException {
+ public CR addRunClasspath(List<Path> classpath) {
+ additionalRunClassPath.addAll(classpath);
+ return self();
+ }
+
+ public CR writeToZip(Path file) throws IOException {
app.writeToZip(file, getBackend() == DEX ? OutputMode.DexIndexed : OutputMode.ClassFile);
- return this;
+ return self();
}
public CodeInspector inspector() throws IOException, ExecutionException {
return new CodeInspector(app);
}
- public TestCompileResult<RR> inspect(Consumer<CodeInspector> consumer)
- throws IOException, ExecutionException {
+ public CR inspect(Consumer<CodeInspector> consumer) throws IOException, ExecutionException {
consumer.accept(inspector());
- return this;
+ return self();
}
public DebugTestConfig debugConfig() {
@@ -85,17 +96,25 @@
}
}
- private RR runJava(String mainClass) throws IOException {
+ private RR runJava(List<Path> additionalClassPath, String mainClass) throws IOException {
Path out = state.getNewTempFolder().resolve("out.zip");
app.writeToZip(out, OutputMode.ClassFile);
- ProcessResult result = ToolHelper.runJava(out, mainClass);
- return createRunResult(app, result);
+ List<Path> classPath = ImmutableList.<Path>builder()
+ .addAll(additionalClassPath)
+ .add(out)
+ .build();
+ ProcessResult result = ToolHelper.runJava(classPath, mainClass);
+ return createRunResult(result);
}
- private RR runArt(String mainClass) throws IOException {
+ private RR runArt(List<Path> additionalClassPath, String mainClass) throws IOException {
Path out = state.getNewTempFolder().resolve("out.zip");
app.writeToZip(out, OutputMode.DexIndexed);
- ProcessResult result = ToolHelper.runArtRaw(out.toString(), mainClass);
- return createRunResult(app, result);
+ List<String> classPath = ImmutableList.<String>builder()
+ .addAll(additionalClassPath.stream().map(Path::toString).collect(Collectors.toList()))
+ .add(out.toString())
+ .build();
+ ProcessResult result = ToolHelper.runArtRaw(classPath, mainClass, dummy -> {});
+ return createRunResult(result);
}
}
diff --git a/src/test/java/com/android/tools/r8/TestCompilerBuilder.java b/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
index 810d292..b2b6047 100644
--- a/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
@@ -11,6 +11,7 @@
import com.android.tools.r8.utils.InternalOptions;
import com.google.common.base.Suppliers;
import java.io.IOException;
+import java.io.PrintStream;
import java.nio.file.Path;
import java.util.Collection;
import java.util.function.Consumer;
@@ -19,10 +20,10 @@
public abstract class TestCompilerBuilder<
C extends BaseCompilerCommand,
B extends BaseCompilerCommand.Builder<C, B>,
- CR extends TestCompileResult<RR>,
+ CR extends TestCompileResult<CR, RR>,
RR extends TestRunResult,
T extends TestCompilerBuilder<C, B, CR, RR, T>>
- extends TestBuilder<T> {
+ extends TestBaseBuilder<C, B, CR, RR, T> {
public static final Consumer<InternalOptions> DEFAULT_OPTIONS =
new Consumer<InternalOptions>() {
@@ -30,7 +31,6 @@
public void accept(InternalOptions options) {}
};
- final B builder;
final Backend backend;
// Default initialized setup. Can be overwritten if needed.
@@ -38,10 +38,10 @@
private ProgramConsumer programConsumer;
private AndroidApiLevel defaultMinApiLevel = ToolHelper.getMinApiLevelForDexVm();
private Consumer<InternalOptions> optionsConsumer = DEFAULT_OPTIONS;
+ private PrintStream stdout = null;
TestCompilerBuilder(TestState state, B builder, Backend backend) {
- super(state);
- this.builder = builder;
+ super(state, builder);
this.backend = backend;
defaultLibrary = TestBase.runtimeJar(backend);
programConsumer = TestBase.emptyConsumer(backend);
@@ -54,7 +54,9 @@
throws CompilationFailedException;
public T addOptionsModification(Consumer<InternalOptions> optionsConsumer) {
- this.optionsConsumer = this.optionsConsumer.andThen(optionsConsumer);
+ if (optionsConsumer != null) {
+ this.optionsConsumer = this.optionsConsumer.andThen(optionsConsumer);
+ }
return self();
}
@@ -67,11 +69,21 @@
if (backend == Backend.DEX && defaultMinApiLevel != null) {
builder.setMinApiLevel(defaultMinApiLevel.getLevel());
}
- return internalCompile(builder, optionsConsumer, Suppliers.memoize(sink::build));
+ PrintStream oldOut = System.out;
+ try {
+ if (stdout != null) {
+ System.setOut(stdout);
+ }
+ return internalCompile(builder, optionsConsumer, Suppliers.memoize(sink::build));
+ } finally {
+ if (stdout != null) {
+ System.setOut(oldOut);
+ }
+ }
}
@Override
- public TestRunResult run(String mainClass) throws IOException, CompilationFailedException {
+ public RR run(String mainClass) throws IOException, CompilationFailedException {
return compile().run(mainClass);
}
@@ -113,15 +125,19 @@
}
@Override
- public T addProgramFiles(Collection<Path> files) {
- builder.addProgramFiles(files);
+ public T addLibraryFiles(Collection<Path> files) {
+ defaultLibrary = null;
+ return super.addLibraryFiles(files);
+ }
+
+ public T noDesugaring() {
+ builder.setDisableDesugaring(true);
return self();
}
- @Override
- public T addLibraryFiles(Collection<Path> files) {
- defaultLibrary = null;
- builder.addLibraryFiles(files);
+ public T redirectStdOut(PrintStream printStream) {
+ assert stdout == null;
+ stdout = printStream;
return self();
}
}
diff --git a/src/test/java/com/android/tools/r8/TestRunResult.java b/src/test/java/com/android/tools/r8/TestRunResult.java
index 46dc4cc..07390b7 100644
--- a/src/test/java/com/android/tools/r8/TestRunResult.java
+++ b/src/test/java/com/android/tools/r8/TestRunResult.java
@@ -15,9 +15,10 @@
import java.io.IOException;
import java.io.PrintStream;
import java.util.concurrent.ExecutionException;
+import java.util.function.Function;
import org.hamcrest.Matcher;
-public class TestRunResult {
+public abstract class TestRunResult<RR extends TestRunResult<?>> {
protected final AndroidApp app;
private final ProcessResult result;
@@ -26,33 +27,55 @@
this.result = result;
}
- public TestRunResult assertSuccess() {
+ abstract RR self();
+
+ public AndroidApp app() {
+ return app;
+ }
+
+ public String getStdOut() {
+ return result.stdout;
+ }
+
+ public String getStdErr() {
+ return result.stderr;
+ }
+
+ public int getExitCode() {
+ return result.exitCode;
+ }
+
+ public RR assertSuccess() {
assertEquals(errorMessage("Expected run to succeed."), 0, result.exitCode);
- return this;
+ return self();
}
- public TestRunResult assertFailure() {
+ public RR assertFailure() {
assertNotEquals(errorMessage("Expected run to fail."), 0, result.exitCode);
- return this;
+ return self();
}
- public TestRunResult assertFailureWithOutput(String expected) {
+ public RR assertFailureWithOutput(String expected) {
assertFailure();
assertEquals(errorMessage("Run stdout incorrect.", expected), expected, result.stdout);
- return this;
+ return self();
}
- public TestRunResult assertFailureWithErrorThatMatches(Matcher<String> matcher) {
+ public RR assertFailureWithErrorThatMatches(Matcher<String> matcher) {
assertFailure();
assertThat(
errorMessage("Run stderr incorrect.", matcher.toString()), result.stderr, matcher);
- return this;
+ return self();
}
- public TestRunResult assertSuccessWithOutput(String expected) {
+ public RR assertSuccessWithOutput(String expected) {
assertSuccess();
assertEquals(errorMessage("Run stdout incorrect.", expected), expected, result.stdout);
- return this;
+ return self();
+ }
+
+ public <R> R map(Function<RR, R> mapper) {
+ return mapper.apply(self());
}
public CodeInspector inspector() throws IOException, ExecutionException {
@@ -63,17 +86,24 @@
return new CodeInspector(app);
}
- public TestRunResult inspect(Consumer<CodeInspector> consumer)
+ public RR inspect(Consumer<CodeInspector> consumer)
throws IOException, ExecutionException {
consumer.accept(inspector());
- return this;
+ return self();
}
- private String errorMessage(String message) {
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ appendInfo(builder);
+ return builder.toString();
+ }
+
+ String errorMessage(String message) {
return errorMessage(message, null);
}
- private String errorMessage(String message, String expected) {
+ String errorMessage(String message, String expected) {
StringBuilder builder = new StringBuilder(message).append('\n');
if (expected != null) {
if (expected.contains(System.lineSeparator())) {
@@ -102,24 +132,24 @@
builder.append("COMMAND: ").append(result.command).append('\n').append(result);
}
- public TestRunResult writeInfo(PrintStream ps) {
+ public RR writeInfo(PrintStream ps) {
StringBuilder sb = new StringBuilder();
appendInfo(sb);
ps.println(sb.toString());
- return this;
+ return self();
}
- public TestRunResult writeApplicaion(PrintStream ps) {
+ public RR writeApplicaion(PrintStream ps) {
StringBuilder sb = new StringBuilder();
appendApplication(sb);
ps.println(sb.toString());
- return this;
+ return self();
}
- public TestRunResult writeProcessResult(PrintStream ps) {
+ public RR writeProcessResult(PrintStream ps) {
StringBuilder sb = new StringBuilder();
appendProcessResult(sb);
ps.println(sb.toString());
- return this;
+ return self();
}
}
diff --git a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
index 2704039..916e1a8 100644
--- a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
@@ -5,22 +5,51 @@
package com.android.tools.r8;
import com.android.tools.r8.TestBase.Backend;
-import com.android.tools.r8.utils.StringUtils;
+import java.io.IOException;
+import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collection;
+import java.util.List;
public abstract class TestShrinkerBuilder<
C extends BaseCompilerCommand,
B extends BaseCompilerCommand.Builder<C, B>,
- CR extends TestCompileResult<RR>,
+ CR extends TestCompileResult<CR, RR>,
RR extends TestRunResult,
T extends TestCompilerBuilder<C, B, CR, RR, T>>
extends TestCompilerBuilder<C, B, CR, RR, T> {
+ protected boolean enableMinification = true;
+ protected boolean enableTreeShaking = true;
+
TestShrinkerBuilder(TestState state, B builder, Backend backend) {
super(state, builder, backend);
}
+ public T treeShaking(boolean enable) {
+ enableTreeShaking = enable;
+ return self();
+ }
+
+ public T noTreeShaking() {
+ return treeShaking(false);
+ }
+
+ public T minification(boolean enable) {
+ enableMinification = enable;
+ return self();
+ }
+
+ public T noMinification() {
+ return minification(false);
+ }
+
+ public abstract T addKeepRuleFiles(List<Path> files);
+
+ public T addKeepRuleFiles(Path... files) throws IOException {
+ return addKeepRuleFiles(Arrays.asList(files));
+ }
+
public abstract T addKeepRules(Collection<String> rules);
public T addKeepRules(String... rules) {
@@ -38,6 +67,13 @@
return self();
}
+ public T addKeepClassAndMembersRules(Class<?>... classes) {
+ for (Class<?> clazz : classes) {
+ addKeepRules("-keep class " + clazz.getTypeName() + " { *; }");
+ }
+ return self();
+ }
+
public T addKeepPackageRules(Package pkg) {
return addKeepRules("-keep class " + pkg.getName() + ".*");
}
@@ -48,9 +84,6 @@
public T addKeepMainRule(String mainClass) {
return addKeepRules(
- StringUtils.joinLines(
- "-keep class " + mainClass + " {",
- " public static void main(java.lang.String[]);",
- "}"));
+ "-keep class " + mainClass + " { public static void main(java.lang.String[]); }");
}
}
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index c1ba2c5..b41899f 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8;
+import static com.android.tools.r8.utils.FileUtils.CLASS_EXTENSION;
import static com.android.tools.r8.utils.FileUtils.isDexFile;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -19,6 +20,7 @@
import com.android.tools.r8.shaking.FilteredClassPath;
import com.android.tools.r8.shaking.ProguardConfiguration;
import com.android.tools.r8.shaking.ProguardConfigurationParser;
+import com.android.tools.r8.shaking.ProguardConfigurationRule;
import com.android.tools.r8.shaking.ProguardRuleParserException;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.AndroidApp;
@@ -56,6 +58,7 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
+import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -748,6 +751,19 @@
Paths.get("", parts.toArray(new String[parts.size() - 1])));
}
+ public static Collection<Path> getClassFilesForInnerClasses(Collection<Class<?>> classes)
+ throws IOException {
+ Set<Path> paths = new HashSet<>();
+ for (Class clazz : classes) {
+ Path path = ToolHelper.getClassFileForTestClass(clazz);
+ String prefix = path.toString().replace(CLASS_EXTENSION, "$");
+ paths.addAll(
+ ToolHelper.getClassFilesForTestDirectory(
+ path.getParent(), p -> p.toString().startsWith(prefix)));
+ }
+ return paths;
+ }
+
public static String getJarEntryForTestPackage(Package pkg) {
List<String> parts = getNamePartsForTestPackage(pkg);
return String.join("/", parts);
@@ -1607,6 +1623,12 @@
return builder;
}
+ public static R8Command.Builder addSyntheticProguardRulesConsumerForTesting(
+ R8Command.Builder builder, Consumer<List<ProguardConfigurationRule>> consumer) {
+ builder.addSyntheticProguardRulesConsumerForTesting(consumer);
+ return builder;
+ }
+
public static R8Command.Builder allowPartiallyImplementedProguardOptions(
R8Command.Builder builder) {
builder.allowPartiallyImplementedProguardOptions();
diff --git a/src/test/java/com/android/tools/r8/naming/AvoidRTest.java b/src/test/java/com/android/tools/r8/naming/AvoidRTest.java
new file mode 100644
index 0000000..e1d073c
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/naming/AvoidRTest.java
@@ -0,0 +1,147 @@
+// 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.naming;
+
+import static com.android.tools.r8.utils.DescriptorUtils.getSimpleClassNameFromDescriptor;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isRenamed;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.R8TestBuilder;
+import com.android.tools.r8.jasmin.JasminBuilder;
+import com.android.tools.r8.jasmin.JasminTestBase;
+import com.android.tools.r8.utils.FileUtils;
+import com.android.tools.r8.utils.StringUtils;
+import com.google.common.collect.ImmutableSet;
+import java.nio.file.Path;
+import java.util.HashSet;
+import java.util.Set;
+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 AvoidRTest extends JasminTestBase {
+ private Backend backend;
+
+ @Parameters(name = "Backend: {0}")
+ public static Backend[] data() {
+ return Backend.values();
+ }
+
+ public AvoidRTest(Backend backend) {
+ this.backend = backend;
+ }
+
+ @Test
+ public void test_withObfuscationDictionary() throws Exception {
+ Path dictionary = temp.newFile("dictionary.txt").toPath();
+ FileUtils.writeTextFile(dictionary, StringUtils.lines("P", "Q", "R", "S", "T"));
+ Set<String> expectedNames = ImmutableSet.of("P", "Q", "S", "T");
+
+ JasminBuilder jasminBuilder = new JasminBuilder();
+ R8TestBuilder builder = testForR8(backend);
+ for (int i = 0; i < 4; i++) {
+ jasminBuilder.addClass("TopLevel" + Integer.toString(i));
+ }
+ for (int i = 0; i < 4; i++) {
+ jasminBuilder.addClass("p1/SecondLevel" + Integer.toString(i));
+ }
+ for (int i = 0; i < 4; i++) {
+ jasminBuilder.addClass("p1/p2/ThirdLevel" + Integer.toString(i));
+ }
+ for (int i = 0; i < 4; i++) {
+ jasminBuilder.addClass("p2/SecondLevel" + Integer.toString(i));
+ }
+ builder.addKeepRules("-keep,allowobfuscation class *");
+ builder.addProgramClassFileData(jasminBuilder.buildClasses());
+ Set<String> usedDescriptors = new HashSet<>();
+ builder.noTreeShaking()
+ .addKeepRules("-classobfuscationdictionary " + dictionary)
+ .compile()
+ .inspect(codeInspector -> {
+ codeInspector.forAllClasses(classSubject -> {
+ assertThat(classSubject, isRenamed());
+ String renamedDescriptor = classSubject.getFinalDescriptor();
+ assertTrue(usedDescriptors.add(renamedDescriptor));
+ assertNotEquals("R", getSimpleClassNameFromDescriptor(renamedDescriptor));
+ assertTrue(expectedNames.contains(getSimpleClassNameFromDescriptor(renamedDescriptor)));
+ });
+ });
+ }
+
+ @Test
+ public void test_withoutPackageHierarchy() throws Exception {
+ JasminBuilder jasminBuilder = new JasminBuilder();
+ R8TestBuilder builder = testForR8(backend);
+ for (int i = 0; i < 26 * 2; i++) {
+ jasminBuilder.addClass("TestClass" + Integer.toString(i));
+ }
+ builder.addKeepRules("-keep,allowobfuscation class *");
+ builder.addProgramClassFileData(jasminBuilder.buildClasses());
+ Set<String> usedNames = new HashSet<>();
+ builder.noTreeShaking()
+ .compile()
+ .inspect(codeInspector -> {
+ codeInspector.forAllClasses(classSubject -> {
+ assertThat(classSubject, isRenamed());
+ assertTrue(usedNames.add(classSubject.getFinalName()));
+ assertNotEquals("R", classSubject.getFinalName());
+ });
+ });
+ assertTrue(usedNames.contains("Q"));
+ assertTrue(usedNames.contains("S"));
+ }
+
+ private void test_withPackageHierarchy(String keepRule) throws Exception {
+ R8TestBuilder builder = testForR8(backend);
+ JasminBuilder jasminBuilder = new JasminBuilder();
+ for (int i = 0; i < 26 * 2; i++) {
+ jasminBuilder.addClass("TopLevel" + Integer.toString(i));
+ }
+ for (int i = 0; i < 26 * 2; i++) {
+ jasminBuilder.addClass("p1/SecondLevel" + Integer.toString(i));
+ }
+ for (int i = 0; i < 26 * 2; i++) {
+ jasminBuilder.addClass("p1/p2/ThirdLevel" + Integer.toString(i));
+ }
+ for (int i = 0; i < 26 * 2; i++) {
+ jasminBuilder.addClass("p2/SecondLevel" + Integer.toString(i));
+ }
+ builder.addKeepRules("-keep,allowobfuscation class *");
+ builder.addProgramClassFileData(jasminBuilder.buildClasses());
+ Set<String> usedDescriptors = new HashSet<>();
+ builder.noTreeShaking()
+ .addKeepRules(keepRule)
+ .compile()
+ .inspect(codeInspector -> {
+ codeInspector.forAllClasses(classSubject -> {
+ assertThat(classSubject, isRenamed());
+ String renamedDescriptor = classSubject.getFinalDescriptor();
+ assertTrue(usedDescriptors.add(renamedDescriptor));
+ assertNotEquals("R", getSimpleClassNameFromDescriptor(renamedDescriptor));
+ });
+ });
+ }
+
+ @Test
+ public void test_withPackageHierarchy_default() throws Exception {
+ test_withPackageHierarchy("");
+ }
+
+ @Test
+ public void test_withPackageHierarchy_repackage() throws Exception {
+ // Repackage every class to the top-level.
+ test_withPackageHierarchy("-repackageclasses");
+ }
+
+ @Test
+ public void test_withPackageHierarchy_flatten() throws Exception {
+ // Repackage every package to the top-level.
+ test_withPackageHierarchy("-flattenpackagehierarchy");
+ }
+
+}
diff --git a/src/test/java/com/android/tools/r8/shaking/fields/FieldsTestBase.java b/src/test/java/com/android/tools/r8/shaking/fields/FieldsTestBase.java
index e5f9799..ce9b84d 100644
--- a/src/test/java/com/android/tools/r8/shaking/fields/FieldsTestBase.java
+++ b/src/test/java/com/android/tools/r8/shaking/fields/FieldsTestBase.java
@@ -6,12 +6,12 @@
import com.android.tools.r8.NeverMerge;
import com.android.tools.r8.TestBase;
-import com.android.tools.r8.graph.invokesuper.Consumer;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.google.common.collect.ImmutableList;
import java.util.Collection;
import java.util.List;
+import java.util.function.Consumer;
public abstract class FieldsTestBase extends TestBase {