Fail in case of stdout/stderr unless explicitly allowed
Change-Id: I4fee93dadee8455220cb4dc12f6ffa9c94a32a85
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteBuilderShrinker.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteBuilderShrinker.java
index e2881ad..37a8dc6 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteBuilderShrinker.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteBuilderShrinker.java
@@ -95,9 +95,6 @@
OptimizationFeedback feedback,
MethodProcessor methodProcessor,
Inliner inliner) {
- if (method.method.toSourceString().contains("proto2.BuilderWithReusedSettersTestClass")) {
- System.out.println();
- }
strengthenCheckCastInstructions(code);
ProtoInliningReasonStrategy inliningReasonStrategy =
diff --git a/src/test/examples/classmerging/keep-rules.txt b/src/test/examples/classmerging/keep-rules.txt
index 5297ee9..64ce874 100644
--- a/src/test/examples/classmerging/keep-rules.txt
+++ b/src/test/examples/classmerging/keep-rules.txt
@@ -72,5 +72,3 @@
-neverinline class * {
@classmerging.NeverInline <methods>;
}
-
--printmapping
diff --git a/src/test/java/com/android/tools/r8/DXTestBuilder.java b/src/test/java/com/android/tools/r8/DXTestBuilder.java
index 84ecee1..e621784 100644
--- a/src/test/java/com/android/tools/r8/DXTestBuilder.java
+++ b/src/test/java/com/android/tools/r8/DXTestBuilder.java
@@ -53,7 +53,10 @@
List<String> args = new ArrayList<>();
args.add("--output=" + outJar.toString());
args.addAll(injars.stream().map(Path::toString).collect(Collectors.toList()));
- ProcessResult result = ToolHelper.runDX(args.toArray(StringUtils.EMPTY_ARRAY));
+ ProcessResult result =
+ ToolHelper.runProcess(
+ ToolHelper.createProcessBuilderForRunningDx(args.toArray(StringUtils.EMPTY_ARRAY)),
+ getStdoutForTesting());
if (result.exitCode != 0) {
throw new CompilationFailedException(result.toString());
}
diff --git a/src/test/java/com/android/tools/r8/ExternalR8TestBuilder.java b/src/test/java/com/android/tools/r8/ExternalR8TestBuilder.java
index 0ebe047..11e6692 100644
--- a/src/test/java/com/android/tools/r8/ExternalR8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/ExternalR8TestBuilder.java
@@ -137,7 +137,7 @@
command.addAll(programJars.stream().map(Path::toString).collect(Collectors.toList()));
ProcessBuilder processBuilder = new ProcessBuilder(command);
- ProcessResult processResult = ToolHelper.runProcess(processBuilder);
+ ProcessResult processResult = ToolHelper.runProcess(processBuilder, getStdoutForTesting());
assertEquals(processResult.stderr, 0, processResult.exitCode);
String proguardMap =
proguardMapFile.toFile().exists()
diff --git a/src/test/java/com/android/tools/r8/ProguardTestBuilder.java b/src/test/java/com/android/tools/r8/ProguardTestBuilder.java
index 9012ca4..9463a49 100644
--- a/src/test/java/com/android/tools/r8/ProguardTestBuilder.java
+++ b/src/test/java/com/android/tools/r8/ProguardTestBuilder.java
@@ -101,7 +101,7 @@
command.add("-dontobfuscate");
}
ProcessBuilder pbuilder = new ProcessBuilder(command);
- ProcessResult result = ToolHelper.runProcess(pbuilder);
+ ProcessResult result = ToolHelper.runProcess(pbuilder, getStdoutForTesting());
if (result.exitCode != 0) {
throw new CompilationFailedException(result.toString());
}
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java
index c1a612f..5e0b7d8 100644
--- a/src/test/java/com/android/tools/r8/TestBase.java
+++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -72,7 +72,6 @@
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.common.io.ByteStreams;
@@ -82,7 +81,6 @@
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -437,12 +435,12 @@
protected static AndroidApp.Builder buildClasses(
Collection<Class<?>> programClasses, Collection<Class<?>> libraryClasses) throws IOException {
AndroidApp.Builder builder = AndroidApp.builder();
- for (Class clazz : programClasses) {
+ for (Class<?> clazz : programClasses) {
builder.addProgramFiles(ToolHelper.getClassFileForTestClass(clazz));
}
if (!libraryClasses.isEmpty()) {
PreloadedClassFileProvider.Builder libraryBuilder = PreloadedClassFileProvider.builder();
- for (Class clazz : libraryClasses) {
+ for (Class<?> clazz : libraryClasses) {
Path file = ToolHelper.getClassFileForTestClass(clazz);
libraryBuilder.addResource(DescriptorUtils.javaTypeToDescriptor(clazz.getCanonicalName()),
Files.readAllBytes(file));
@@ -455,7 +453,7 @@
protected static AndroidApp readClassesAndRuntimeJar(
List<Class<?>> programClasses, Backend backend) throws IOException {
AndroidApp.Builder builder = AndroidApp.builder();
- for (Class clazz : programClasses) {
+ for (Class<?> clazz : programClasses) {
builder.addProgramFiles(ToolHelper.getClassFileForTestClass(clazz));
}
if (backend == Backend.DEX) {
@@ -477,7 +475,7 @@
* Copy test classes to the specified directory.
*/
protected void copyTestClasses(Path dest, Class... classes) throws IOException {
- for (Class clazz : classes) {
+ for (Class<?> clazz : classes) {
Path path = dest.resolve(clazz.getCanonicalName().replace('.', '/') + ".class");
Files.createDirectories(path.getParent());
Files.copy(ToolHelper.getClassFileForTestClass(clazz), path);
@@ -510,7 +508,7 @@
/** Create a temporary JAR file containing the specified test classes. */
protected void addTestClassesToJar(JarOutputStream out, Iterable<Class<?>> classes)
throws IOException {
- for (Class clazz : classes) {
+ for (Class<?> clazz : classes) {
try (FileInputStream in =
new FileInputStream(ToolHelper.getClassFileForTestClass(clazz).toFile())) {
out.putNextEntry(new ZipEntry(ToolHelper.getJarEntryForTestClass(clazz)));
@@ -645,7 +643,7 @@
}
protected static DexMethod buildNullaryVoidMethod(
- Class clazz, String name, DexItemFactory factory) {
+ Class<?> clazz, String name, DexItemFactory factory) {
return buildMethod(
Reference.method(Reference.classFromClass(clazz), name, Collections.emptyList(), null),
factory);
@@ -659,7 +657,7 @@
}
private static List<ProguardConfigurationRule> buildKeepRuleForClass(
- Class clazz, DexItemFactory factory) {
+ Class<?> clazz, DexItemFactory factory) {
Builder keepRuleBuilder = ProguardKeepRule.builder();
keepRuleBuilder.setSource("buildKeepRuleForClass " + clazz.getTypeName());
keepRuleBuilder.setType(ProguardKeepRuleType.KEEP);
@@ -671,7 +669,7 @@
}
private static List<ProguardConfigurationRule> buildKeepRuleForClassAndMethods(
- Class clazz, DexItemFactory factory) {
+ Class<?> clazz, DexItemFactory factory) {
Builder keepRuleBuilder = ProguardKeepRule.builder();
keepRuleBuilder.setSource("buildKeepRuleForClass " + clazz.getTypeName());
keepRuleBuilder.setType(ProguardKeepRuleType.KEEP);
@@ -735,20 +733,6 @@
return jarTestClasses(classes.toArray(new Class<?>[]{}));
}
- /**
- * Get the class name generated by javac.
- */
- protected static String getJavacGeneratedClassName(Class clazz) {
- List<String> parts = Lists.newArrayList(clazz.getCanonicalName().split("\\."));
- Class enclosing = clazz;
- while (enclosing.getEnclosingClass() != null) {
- parts.set(parts.size() - 2, parts.get(parts.size() - 2) + "$" + parts.get(parts.size() - 1));
- parts.remove(parts.size() - 1);
- enclosing = clazz.getEnclosingClass();
- }
- return String.join(".", parts);
- }
-
protected static List<Object[]> buildParameters(Object... arraysOrIterables) {
Function<Object, List<Object>> arrayOrIterableToList =
arrayOrIterable -> {
@@ -897,23 +881,16 @@
* Generate a Proguard configuration for keeping the "static void main(String[])" method of the
* specified class.
*/
- public static String keepMainProguardConfiguration(Class clazz) {
- return keepMainProguardConfiguration(clazz, ImmutableList.of());
+ public static String keepMainProguardConfiguration(Class<?> clazz) {
+ return keepMainProguardConfiguration(clazz.getTypeName());
}
/**
* Generate a Proguard configuration for keeping the "static void main(String[])" method of the
* specified class.
*/
- public static String keepMainProguardConfiguration(Class clazz, List<String> additionalLines) {
- String modifier = (clazz.getModifiers() & Modifier.PUBLIC) == Modifier.PUBLIC ? "public " : "";
- return String.join(System.lineSeparator(),
- Iterables.concat(ImmutableList.of(
- "-keep " + modifier + "class " + getJavacGeneratedClassName(clazz) + " {",
- " public static void main(java.lang.String[]);",
- "}",
- "-printmapping"),
- additionalLines));
+ public static String keepMainProguardConfiguration(Class<?> clazz, List<String> additionalLines) {
+ return keepMainProguardConfiguration(clazz.getTypeName()) + StringUtils.lines(additionalLines);
}
/**
@@ -923,15 +900,12 @@
* The class is assumed to be public.
*/
public static String keepMainProguardConfiguration(String clazz) {
- return "-keep public class " + clazz + " {\n"
- + " public static void main(java.lang.String[]);\n"
- + "}\n"
- + "-printmapping\n";
+ return StringUtils.lines(
+ "-keep class " + clazz + " {", " public static void main(java.lang.String[]);", "}");
}
public static String noShrinkingNoMinificationProguardConfiguration() {
- return "-dontshrink\n"
- + "-dontobfuscate\n";
+ return StringUtils.lines("-dontshrink", "-dontobfuscate");
}
/**
@@ -939,7 +913,7 @@
* specified class and specify if -allowaccessmodification and -dontobfuscate are added as well.
*/
public static String keepMainProguardConfiguration(
- Class clazz, boolean allowaccessmodification, boolean obfuscate) {
+ Class<?> clazz, boolean allowaccessmodification, boolean obfuscate) {
return keepMainProguardConfiguration(clazz)
+ (allowaccessmodification ? "-allowaccessmodification\n" : "")
+ (obfuscate ? "-printmapping\n" : "-dontobfuscate\n");
@@ -956,7 +930,7 @@
* Generate a Proguard configuration for keeping the "static void main(String[])" method of the
* specified class and add rules to inline methods with the inlining annotation.
*/
- public static String keepMainProguardConfigurationWithInliningAnnotation(Class clazz) {
+ public static String keepMainProguardConfigurationWithInliningAnnotation(Class<?> clazz) {
return "-forceinline class * { @com.android.tools.r8.ForceInline *; }"
+ System.lineSeparator()
+ "-neverinline class * { @com.android.tools.r8.NeverInline *; }"
diff --git a/src/test/java/com/android/tools/r8/TestCompilerBuilder.java b/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
index 628e9c5..5f0843f 100644
--- a/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
@@ -3,6 +3,10 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
import com.android.tools.r8.TestBase.Backend;
import com.android.tools.r8.debug.DebugTestConfig;
import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase.KeepRuleConsumer;
@@ -12,6 +16,7 @@
import com.android.tools.r8.utils.AndroidAppConsumers;
import com.android.tools.r8.utils.ForwardingOutputStream;
import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.ThrowingOutputStream;
import com.google.common.base.Suppliers;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -52,7 +57,9 @@
private AndroidApiLevel defaultMinApiLevel = ToolHelper.getMinApiLevelForDexVm();
private Consumer<InternalOptions> optionsConsumer = DEFAULT_OPTIONS;
private ByteArrayOutputStream stdout = null;
+ private PrintStream oldStdout = null;
private ByteArrayOutputStream stderr = null;
+ private PrintStream oldStderr = null;
protected OutputMode outputMode = OutputMode.DexIndexed;
TestCompilerBuilder(TestState state, B builder, Backend backend) {
@@ -95,34 +102,43 @@
builder.addLibraryFiles(TestBase.runtimeJar(backend));
}
}
- PrintStream oldOut = System.out;
- PrintStream oldErr = System.err;
- CR cr = null;
+ assertNull(oldStdout);
+ oldStdout = System.out;
+ assertNull(oldStderr);
+ oldStderr = System.err;
+ CR cr;
try {
if (stdout != null) {
+ assertTrue(allowStdoutMessages);
System.setOut(new PrintStream(new ForwardingOutputStream(stdout, System.out)));
+ } else if (!allowStdoutMessages) {
+ System.setOut(
+ new PrintStream(
+ new ThrowingOutputStream<>(
+ () -> new AssertionError("Unexpected print to stdout"))));
}
if (stderr != null) {
+ assertTrue(allowStderrMessages);
System.setErr(new PrintStream(new ForwardingOutputStream(stderr, System.err)));
+ } else if (!allowStderrMessages) {
+ System.setErr(
+ new PrintStream(
+ new ThrowingOutputStream<>(
+ () -> new AssertionError("Unexpected print to stderr"))));
}
- cr = internalCompile(builder, optionsConsumer, Suppliers.memoize(sink::build));
- cr.addRunClasspathFiles(additionalRunClassPath);
+ cr =
+ internalCompile(builder, optionsConsumer, Suppliers.memoize(sink::build))
+ .addRunClasspathFiles(additionalRunClassPath);
return cr;
} finally {
if (stdout != null) {
getState().setStdout(stdout.toString());
- System.setOut(oldOut);
- if (cr != null && !allowStdoutMessages) {
- cr.assertNoStdout();
- }
}
+ System.setOut(oldStdout);
if (stderr != null) {
getState().setStderr(stderr.toString());
- System.setErr(oldErr);
- if (cr != null && !allowStderrMessages) {
- cr.assertNoStderr();
- }
}
+ System.setErr(oldStderr);
}
}
@@ -319,6 +335,16 @@
return allowStdoutMessages();
}
+ /**
+ * If {@link #allowStdoutMessages} is false, then {@link System#out} will be replaced temporarily
+ * by a {@link ThrowingOutputStream}. To allow the testing infrastructure to print messages to the
+ * terminal, this method provides a reference to the original {@link System#out}.
+ */
+ public PrintStream getStdoutForTesting() {
+ assertNotNull(oldStdout);
+ return oldStdout;
+ }
+
public T allowStderrMessages() {
allowStdoutMessages = true;
return self();
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index effe9d9..648126c 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -1244,6 +1244,15 @@
}
public static ProcessResult runDX(Path workingDirectory, String... args) throws IOException {
+ return runProcess(createProcessBuilderForRunningDx(workingDirectory, args));
+ }
+
+ public static ProcessBuilder createProcessBuilderForRunningDx(String... args) {
+ return createProcessBuilderForRunningDx(null, args);
+ }
+
+ public static ProcessBuilder createProcessBuilderForRunningDx(
+ Path workingDirectory, String... args) {
Assume.assumeTrue(ToolHelper.artSupported());
DXCommandBuilder builder = new DXCommandBuilder();
for (String arg : args) {
@@ -1253,7 +1262,7 @@
if (workingDirectory != null) {
pb.directory(workingDirectory.toFile());
}
- return runProcess(pb);
+ return pb;
}
public static ProcessResult runJava(Class clazz) throws Exception {
@@ -1968,8 +1977,13 @@
}
public static ProcessResult runProcess(ProcessBuilder builder) throws IOException {
+ return runProcess(builder, System.out);
+ }
+
+ public static ProcessResult runProcess(ProcessBuilder builder, PrintStream out)
+ throws IOException {
String command = String.join(" ", builder.command());
- System.out.println(command);
+ out.println(command);
return drainProcessOutputStreams(builder.start(), command);
}
diff --git a/src/test/java/com/android/tools/r8/bridgeremoval/RemoveVisibilityBridgeMethodsTest.java b/src/test/java/com/android/tools/r8/bridgeremoval/RemoveVisibilityBridgeMethodsTest.java
index c37c71b..6bc3814 100644
--- a/src/test/java/com/android/tools/r8/bridgeremoval/RemoveVisibilityBridgeMethodsTest.java
+++ b/src/test/java/com/android/tools/r8/bridgeremoval/RemoveVisibilityBridgeMethodsTest.java
@@ -5,67 +5,65 @@
package com.android.tools.r8.bridgeremoval;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
import com.android.tools.r8.TestBase;
-import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.ProcessResult;
-import com.android.tools.r8.bridgeremoval.bridgestoremove.Main;
-import com.android.tools.r8.bridgeremoval.bridgestoremove.Outer;
+import com.android.tools.r8.TestParameters;
import com.android.tools.r8.jasmin.JasminBuilder;
import com.android.tools.r8.jasmin.JasminBuilder.ClassBuilder;
-import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import com.google.common.collect.ImmutableList;
-import java.lang.reflect.Method;
-import java.nio.file.Path;
import java.util.Collections;
import java.util.List;
import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+@RunWith(Parameterized.class)
public class RemoveVisibilityBridgeMethodsTest extends TestBase {
- private void run(boolean obfuscate) throws Exception {
- List<Class<?>> classes = ImmutableList.of(Outer.class, Main.class);
- String proguardConfig = keepMainProguardConfiguration(Main.class, true, obfuscate);
- CodeInspector inspector = new CodeInspector(compileWithR8(classes, proguardConfig));
+ private final boolean minification;
+ private final TestParameters parameters;
- List<Method> removedMethods = ImmutableList.of(
- Outer.SubClass.class.getMethod("method"),
- Outer.StaticSubClass.class.getMethod("method"));
+ @Parameterized.Parameters(name = "{1}, minification: {0}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
+ }
- removedMethods.forEach(method -> assertFalse(inspector.method(method).isPresent()));
+ public RemoveVisibilityBridgeMethodsTest(boolean minification, TestParameters parameters) {
+ this.minification = minification;
+ this.parameters = parameters;
}
@Test
- public void testWithObfuscation() throws Exception {
- run(true);
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(RemoveVisibilityBridgeMethodsTest.class)
+ .addKeepMainRule(Main.class)
+ .allowAccessModification()
+ .minification(minification)
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .inspect(this::inspect)
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccess();
}
- @Test
- public void testWithoutObfuscation() throws Exception {
- run(false);
- }
-
- @Test
- public void regressionTest_b76383728_WithObfuscation() throws Exception {
- runRegressionTest_b76383728(true);
- }
-
- @Test
- public void regressionTest_b76383728_WithoutObfuscation() throws Exception {
- runRegressionTest_b76383728(false);
+ private void inspect(CodeInspector inspector) throws Exception {
+ assertThat(inspector.method(Outer.SubClass.class.getMethod("method")), not(isPresent()));
+ assertThat(inspector.method(Outer.StaticSubClass.class.getMethod("method")), not(isPresent()));
}
/**
* Regression test for b76383728 to make sure we correctly identify and remove real visibility
* forward bridge methods synthesized by javac.
*/
- private void runRegressionTest_b76383728(boolean obfuscate) throws Exception {
+ @Test
+ public void regressionTest_b76383728() throws Exception {
JasminBuilder jasminBuilder = new JasminBuilder();
ClassBuilder superClass = jasminBuilder.addClass("SuperClass");
@@ -92,39 +90,71 @@
"dup",
"invokespecial " + subclass.name + "/<init>()V",
"invokevirtual " + subclass.name + "/getMethod()Ljava/lang/String;",
- "invokevirtual java/io/PrintStream/print(Ljava/lang/String;)V",
- "return"
- );
+ "invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V",
+ "return");
- final String mainClassName = mainClass.name;
-
- String proguardConfig = keepMainProguardConfiguration(mainClass.name, true, obfuscate);
+ List<byte[]> programClassFileData = jasminBuilder.buildClasses();
// Run input program on java.
- Path outputDirectory = temp.newFolder().toPath();
- jasminBuilder.writeClassFiles(outputDirectory);
- ProcessResult javaResult = ToolHelper.runJava(outputDirectory, mainClassName);
- assertEquals(0, javaResult.exitCode);
+ if (parameters.isCfRuntime()) {
+ testForJvm()
+ .addProgramClassFileData(programClassFileData)
+ .run(parameters.getRuntime(), mainClass.name)
+ .assertSuccessWithOutputLines("Hello World");
+ }
- AndroidApp optimizedApp = compileWithR8(jasminBuilder.build(), proguardConfig,
- // Disable inlining to avoid the (short) tested method from being inlined and then removed.
- internalOptions -> internalOptions.enableInlining = false);
+ testForR8(parameters.getBackend())
+ .addProgramClassFileData(programClassFileData)
+ .addKeepMainRule(mainClass.name)
+ .addOptionsModification(options -> options.enableInlining = false)
+ .allowAccessModification()
+ .minification(minification)
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .inspect(
+ inspector -> {
+ ClassSubject classSubject = inspector.clazz(superClass.name);
+ assertThat(classSubject, isPresent());
+ MethodSubject methodSubject =
+ classSubject.method("java.lang.String", "method", Collections.emptyList());
+ assertThat(methodSubject, isPresent());
- // Run optimized (output) program on ART
- String artResult = runOnArt(optimizedApp, mainClassName);
- assertEquals(javaResult.stdout, artResult);
+ classSubject = inspector.clazz(subclass.name);
+ assertThat(classSubject, isPresent());
+ methodSubject =
+ classSubject.method("java.lang.String", "getMethod", Collections.emptyList());
+ assertThat(methodSubject, isPresent());
+ })
+ .run(parameters.getRuntime(), mainClass.name)
+ .assertSuccessWithOutputLines("Hello World");
+ }
- CodeInspector inspector = new CodeInspector(optimizedApp);
+ static class Main {
- ClassSubject classSubject = inspector.clazz(superClass.name);
- assertThat(classSubject, isPresent());
- MethodSubject methodSubject = classSubject
- .method("java.lang.String", "method", Collections.emptyList());
- assertThat(methodSubject, isPresent());
+ public static void main(String[] args) {
+ new Outer().create().method();
+ new Outer.StaticSubClass().method();
+ }
+ }
- classSubject = inspector.clazz(subclass.name);
- assertThat(classSubject, isPresent());
- methodSubject = classSubject.method("java.lang.String", "getMethod", Collections.emptyList());
- assertThat(methodSubject, isPresent());
+ static class Outer {
+
+ class SuperClass {
+ public void method() {}
+ }
+
+ // As SuperClass is package private SubClass will have a bridge method for "method".
+ public class SubClass extends SuperClass {}
+
+ public SubClass create() {
+ return new SubClass();
+ }
+
+ static class StaticSuperClass {
+ public void method() {}
+ }
+
+ // As SuperClass is package private SubClass will have a bridge method for "method".
+ public static class StaticSubClass extends StaticSuperClass {}
}
}
diff --git a/src/test/java/com/android/tools/r8/bridgeremoval/bridgestoremove/Main.java b/src/test/java/com/android/tools/r8/bridgeremoval/bridgestoremove/Main.java
index 4c8ac31..28ad6b9 100644
--- a/src/test/java/com/android/tools/r8/bridgeremoval/bridgestoremove/Main.java
+++ b/src/test/java/com/android/tools/r8/bridgeremoval/bridgestoremove/Main.java
@@ -7,7 +7,7 @@
public class Main {
public static void main(String[] args) {
- (new Outer()).create().method();
- (new Outer.StaticSubClass()).method();
+ new Outer().create().method();
+ new Outer.StaticSubClass().method();
}
}
diff --git a/src/test/java/com/android/tools/r8/cf/InlineCmpDoubleTest.java b/src/test/java/com/android/tools/r8/cf/InlineCmpDoubleTest.java
index b81d457..16dfaa7 100644
--- a/src/test/java/com/android/tools/r8/cf/InlineCmpDoubleTest.java
+++ b/src/test/java/com/android/tools/r8/cf/InlineCmpDoubleTest.java
@@ -1,23 +1,77 @@
// 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.cf;
-public class InlineCmpDoubleTest {
- public static void main(String[] args) {
- inlinee(42);
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.naming.MemberNaming.MethodSignature;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+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 InlineCmpDoubleTest extends TestBase {
+
+ private final boolean enableInlining;
+ private final TestParameters parameters;
+
+ public InlineCmpDoubleTest(boolean enableInlining, TestParameters parameters) {
+ this.enableInlining = enableInlining;
+ this.parameters = parameters;
}
- public static void inlinee(int x) {
- inlineMe(x + 41);
+ @Parameters(name = "{1}, inlining: {0}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
}
- public static int inlineMe(int x) {
- // Side effect to ensure that the invocation is not removed simply because the method does not
- // have any side effects.
- System.out.println("In InlineCmpDoubleTest.inlineMe()");
- double a = x / 255.0;
- return a < 64.0 ? 42 : 43;
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addProgramClasses(TestClass.class)
+ .addKeepMainRule(TestClass.class)
+ .addOptionsModification(options -> options.enableInlining = enableInlining)
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .inspect(this::inspect)
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccess();
+ }
+
+ private void inspect(CodeInspector inspector) {
+ ClassSubject clazz = inspector.clazz(TestClass.class);
+ MethodSubject method =
+ clazz.method(new MethodSignature("inlineMe", "int", ImmutableList.of("int")));
+ assertEquals(enableInlining, !method.isPresent());
+ }
+
+ static class TestClass {
+
+ public static void main(String[] args) {
+ inlinee(42);
+ }
+
+ public static void inlinee(int x) {
+ inlineMe(x + 41);
+ }
+
+ public static int inlineMe(int x) {
+ // Side effect to ensure that the invocation is not removed simply because the method does not
+ // have any side effects.
+ System.out.println("In InlineCmpDoubleTest.inlineMe()");
+ double a = x / 255.0;
+ return a < 64.0 ? 42 : 43;
+ }
}
}
diff --git a/src/test/java/com/android/tools/r8/cf/InlineCmpDoubleTestRunner.java b/src/test/java/com/android/tools/r8/cf/InlineCmpDoubleTestRunner.java
deleted file mode 100644
index dbcf557..0000000
--- a/src/test/java/com/android/tools/r8/cf/InlineCmpDoubleTestRunner.java
+++ /dev/null
@@ -1,75 +0,0 @@
-// 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.cf;
-
-import static org.junit.Assert.assertEquals;
-
-import com.android.tools.r8.ClassFileConsumer.ArchiveConsumer;
-import com.android.tools.r8.CompilationMode;
-import com.android.tools.r8.R8Command;
-import com.android.tools.r8.TestBase;
-import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.naming.MemberNaming.MethodSignature;
-import com.android.tools.r8.origin.Origin;
-import com.android.tools.r8.utils.AndroidApp;
-import com.android.tools.r8.utils.AndroidAppConsumers;
-import com.android.tools.r8.utils.codeinspector.ClassSubject;
-import com.android.tools.r8.utils.codeinspector.CodeInspector;
-import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import com.google.common.collect.ImmutableList;
-import java.nio.file.Path;
-import java.util.List;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-
-@RunWith(Parameterized.class)
-public class InlineCmpDoubleTestRunner {
-
- private static final Class CLASS = InlineCmpDoubleTest.class;
-
- private final boolean enableInlining;
-
- @Rule
- public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest();
-
- public InlineCmpDoubleTestRunner(boolean enableInlining) {
- this.enableInlining = enableInlining;
- }
-
- @Parameters(name = "inlining={0}")
- public static Boolean[] data() {
- return new Boolean[]{true, false};
- }
-
- @Test
- public void test() throws Exception {
- byte[] inputClass = ToolHelper.getClassAsBytes(CLASS);
- AndroidAppConsumers appBuilder = new AndroidAppConsumers();
- Path outPath = temp.getRoot().toPath().resolve("out.jar");
- List<String> proguardKeepMain = ImmutableList.of(TestBase.keepMainProguardConfiguration(CLASS));
- R8Command command = R8Command.builder()
- .setMode(CompilationMode.RELEASE)
- .addLibraryFiles(ToolHelper.getJava8RuntimeJar())
- .setProgramConsumer(appBuilder.wrapClassFileConsumer(new ArchiveConsumer(outPath)))
- .addProguardConfiguration(proguardKeepMain, Origin.unknown())
- .addClassProgramData(inputClass, Origin.unknown())
- .build();
-
- AndroidApp app = ToolHelper.runR8(command, options -> {
- options.enableInlining = enableInlining;
- });
-
- assertEquals(0, ToolHelper.runJava(outPath, CLASS.getCanonicalName()).exitCode);
-
- CodeInspector inspector = new CodeInspector(app);
- ClassSubject clazz = inspector.clazz(CLASS);
- MethodSubject method =
- clazz.method(new MethodSignature("inlineMe", "int", ImmutableList.of("int")));
- assertEquals(enableInlining, !method.isPresent());
- }
-}
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexTracingTest.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexTracingTest.java
index 8bc0e79..d1ecf46 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexTracingTest.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexTracingTest.java
@@ -9,10 +9,18 @@
import static com.android.tools.r8.utils.FileUtils.withNativeFileSeparators;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
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.TestCompilerBuilder;
+import com.android.tools.r8.ThrowableConsumer;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ir.desugar.LambdaRewriter;
import com.android.tools.r8.references.Reference;
@@ -21,7 +29,6 @@
import com.android.tools.r8.utils.Box;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.FileUtils;
-import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.StringUtils;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -35,11 +42,9 @@
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.List;
-import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
-import org.junit.Assert;
import org.junit.Test;
public class MainDexTracingTest extends TestBase {
@@ -61,9 +66,10 @@
Paths.get(EXAMPLE_SRC_DIR, "multidex", "main-dex-rules-whyareyoukeeping.txt"),
Paths.get(EXAMPLE_SRC_DIR, "multidex001", "ref-list-1.txt"),
Paths.get(EXAMPLE_SRC_DIR, "multidex001", "ref-list-1.txt"),
- AndroidApiLevel.I);
+ AndroidApiLevel.I,
+ TestCompilerBuilder::allowStdoutMessages);
String output = new String(baos.toByteArray(), Charset.defaultCharset());
- Assert.assertThat(output, containsString("is referenced in keep rule:"));
+ assertThat(output, containsString("is referenced in keep rule:"));
System.setOut(stdout);
}
@@ -78,10 +84,12 @@
Paths.get(EXAMPLE_SRC_DIR, "multidex001", "ref-list-1.txt"),
Paths.get(EXAMPLE_SRC_DIR, "multidex001", "ref-list-1.txt"),
AndroidApiLevel.I,
- options -> {
- options.enableInlining = false;
- options.mainDexKeptGraphConsumer = graphConsumer;
- });
+ builder ->
+ builder.addOptionsModification(
+ options -> {
+ options.enableInlining = false;
+ options.mainDexKeptGraphConsumer = graphConsumer;
+ }));
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
graphConsumer.printWhyAreYouKeeping(
@@ -92,7 +100,7 @@
"multidex001.MainActivity",
"|- is referenced in keep rule:",
withNativeFileSeparators("| src/test/examples/multidex/main-dex-rules.txt:14:1"));
- Assert.assertEquals(expected, output);
+ assertEquals(expected, output);
}
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
@@ -110,7 +118,7 @@
"|- is referenced in keep rule:",
withNativeFileSeparators(
"| src/test/examples/multidex/main-dex-rules.txt:14:1"));
- Assert.assertEquals(expected, output);
+ assertEquals(expected, output);
}
}
@@ -271,9 +279,7 @@
expectedR8MainDexList,
expectedMainDexList,
minSdk,
- (options) -> {
- options.enableInlining = false;
- });
+ builder -> builder.addOptionsModification(options -> options.enableInlining = false));
}
private void doTest(
@@ -284,7 +290,7 @@
Path expectedR8MainDexList,
Path expectedMainDexList,
AndroidApiLevel minSdk,
- Consumer<InternalOptions> optionsConsumer)
+ ThrowableConsumer<R8FullTestBuilder> configuration)
throws Throwable {
Path out = temp.getRoot().toPath().resolve(testName + ZIP_EXTENSION);
@@ -328,7 +334,7 @@
.addProgramFiles(Paths.get(EXAMPLE_BUILD_DIR, "multidexfakeframeworks" + JAR_EXTENSION))
.addKeepRules("-keepattributes *Annotation*")
.addMainDexRuleFiles(mainDexRules)
- .addOptionsModification(optionsConsumer)
+ .apply(configuration)
.allowDiagnosticWarningMessages()
.assumeAllMethodsMayHaveSideEffects()
.setMinApi(minSdk)
@@ -351,7 +357,7 @@
for (int i = 0; i < r8RefList.length; i++) {
String reference = r8RefList[i].trim();
if (r8MainDexList.size() <= i) {
- Assert.fail("R8 main dex list is missing '" + reference + "'");
+ fail("R8 main dex list is missing '" + reference + "'");
}
checkSameMainDexEntry(reference, r8MainDexList.get(i));
}
@@ -363,7 +369,7 @@
// The main dex list generator does not do any lambda desugaring.
if (!isLambda(reference)) {
if (mainDexGeneratorMainDexList.size() <= i - nonLambdaOffset) {
- Assert.fail("Main dex list generator is missing '" + reference + "'");
+ fail("Main dex list generator is missing '" + reference + "'");
}
checkSameMainDexEntry(reference, mainDexGeneratorMainDexList.get(i - nonLambdaOffset));
checkSameMainDexEntry(
@@ -389,9 +395,9 @@
continue;
}
if (index == 0) {
- Assert.assertEquals("classes.dex", entry.getName());
+ assertEquals("classes.dex", entry.getName());
} else {
- Assert.assertEquals("classes" + (index + 1) + ".dex", entry.getName());
+ assertEquals("classes" + (index + 1) + ".dex", entry.getName());
}
index++;
}
@@ -399,7 +405,7 @@
String[] entriesUnsorted = entryNames.toArray(StringUtils.EMPTY_ARRAY);
String[] entriesSorted = entryNames.toArray(StringUtils.EMPTY_ARRAY);
Arrays.sort(entriesSorted);
- Assert.assertArrayEquals(entriesUnsorted, entriesSorted);
+ assertArrayEquals(entriesUnsorted, entriesSorted);
}
private boolean isLambda(String mainDexEntry) {
@@ -407,7 +413,7 @@
}
private String mainDexStringToDescriptor(String mainDexString) {
- Assert.assertTrue(mainDexString.endsWith(FileUtils.CLASS_EXTENSION));
+ assertTrue(mainDexString.endsWith(FileUtils.CLASS_EXTENSION));
return DescriptorUtils.getDescriptorFromClassBinaryName(
mainDexString.substring(0, mainDexString.length() - FileUtils.CLASS_EXTENSION.length()));
}
@@ -421,6 +427,6 @@
reference = reference.substring(0, reference.lastIndexOf('$'));
computed = computed.substring(0, computed.lastIndexOf('$'));
}
- Assert.assertEquals(reference, computed);
+ assertEquals(reference, computed);
}
}
diff --git a/src/test/java/com/android/tools/r8/maindexlist/whyareyoukeeping/MainDexListWhyAreYouKeeping.java b/src/test/java/com/android/tools/r8/maindexlist/whyareyoukeeping/MainDexListWhyAreYouKeeping.java
index cd80843..c4a616c 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/whyareyoukeeping/MainDexListWhyAreYouKeeping.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/whyareyoukeeping/MainDexListWhyAreYouKeeping.java
@@ -90,14 +90,15 @@
.setMinApi(AndroidApiLevel.K)
.addProgramClasses(CLASSES)
.addMainDexRules(keepMainProguardConfiguration(HelloWorldMain.class))
- .setMainDexKeptGraphConsumer(consumer);
+ .setMainDexKeptGraphConsumer(consumer)
+ .allowStdoutMessages();
if (rule != null) {
builder.addMainDexRules(rule);
}
builder.compile();
}
- private String runTest(Class clazz) throws Exception {
+ private String runTest(Class<?> clazz) throws Exception {
PrintStream stdout = System.out;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
String rule = null;
diff --git a/src/test/java/com/android/tools/r8/shaking/b113138046/NativeMethodTest.java b/src/test/java/com/android/tools/r8/shaking/b113138046/NativeMethodTest.java
index f1d0cda..15fba7f 100644
--- a/src/test/java/com/android/tools/r8/shaking/b113138046/NativeMethodTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/b113138046/NativeMethodTest.java
@@ -85,7 +85,6 @@
"-keep class " + Outer.class.getCanonicalName() + " {",
" onEvent(...);",
"}",
- "-printmapping",
"-keepattributes InnerClasses,EnclosingMethod,Signature",
"-allowaccessmodification");
test(config, compatMode);
@@ -106,7 +105,6 @@
" @**.Keep <fields>;",
" @**.Keep <methods>;",
"}",
- "-printmapping",
"-keepattributes InnerClasses,EnclosingMethod,Signature",
"-allowaccessmodification");
test(config, true);
diff --git a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/defaultctor/ImplicitlyKeptDefaultConstructorTest.java b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/defaultctor/ImplicitlyKeptDefaultConstructorTest.java
index ab46041..7752712 100644
--- a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/defaultctor/ImplicitlyKeptDefaultConstructorTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/defaultctor/ImplicitlyKeptDefaultConstructorTest.java
@@ -243,11 +243,11 @@
public void testStaticFieldWithoutInitializationStaticClassKept() throws Exception {
// An explicit keep rule keeps the default constructor.
Class<?> mainClass = MainGetStaticFieldNotInitialized.class;
- String proguardConfiguration = keepMainProguardConfiguration(
- mainClass,
- ImmutableList.of(
- "-keep class " + getJavacGeneratedClassName(StaticFieldNotInitialized.class) + " {",
- "}"));
+ String proguardConfiguration =
+ keepMainProguardConfiguration(
+ mainClass,
+ ImmutableList.of(
+ "-keep class " + StaticFieldNotInitialized.class.getTypeName() + " {", "}"));
runTest(
mainClass,
ImmutableList.of(mainClass, StaticFieldNotInitialized.class),
@@ -259,11 +259,11 @@
public void testStaticFieldWithInitializationStaticClassKept() throws Exception {
// An explicit keep rule keeps the default constructor.
Class<?> mainClass = MainGetStaticFieldInitialized.class;
- String proguardConfiguration = keepMainProguardConfiguration(
- mainClass,
- ImmutableList.of(
- "-keep class " + getJavacGeneratedClassName(StaticFieldInitialized.class) + " {",
- "}"));
+ String proguardConfiguration =
+ keepMainProguardConfiguration(
+ mainClass,
+ ImmutableList.of(
+ "-keep class " + StaticFieldInitialized.class.getTypeName() + " {", "}"));
runTest(
mainClass,
ImmutableList.of(mainClass, StaticFieldInitialized.class),
@@ -275,11 +275,10 @@
public void testStaticMethodStaticClassKept() throws Exception {
// An explicit keep rule keeps the default constructor.
Class<?> mainClass = MainCallStaticMethod.class;
- String proguardConfiguration = keepMainProguardConfiguration(
- mainClass,
- ImmutableList.of(
- "-keep class " + getJavacGeneratedClassName(StaticMethod.class) + " {",
- "}"));
+ String proguardConfiguration =
+ keepMainProguardConfiguration(
+ mainClass,
+ ImmutableList.of("-keep class " + StaticMethod.class.getTypeName() + " {", "}"));
runTest(
mainClass,
ImmutableList.of(mainClass, StaticMethod.class),
diff --git a/src/test/java/com/android/tools/r8/utils/ThrowingOutputStream.java b/src/test/java/com/android/tools/r8/utils/ThrowingOutputStream.java
new file mode 100644
index 0000000..2542264
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/utils/ThrowingOutputStream.java
@@ -0,0 +1,42 @@
+// 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.utils;
+
+import java.io.OutputStream;
+import java.util.function.Supplier;
+
+public class ThrowingOutputStream<T extends Error> extends OutputStream {
+
+ private final Supplier<T> exceptionSupplier;
+
+ public ThrowingOutputStream(Supplier<T> exceptionSupplier) {
+ this.exceptionSupplier = exceptionSupplier;
+ }
+
+ @Override
+ public void write(int b) {
+ throw exceptionSupplier.get();
+ }
+
+ @Override
+ public void write(byte[] b) {
+ throw exceptionSupplier.get();
+ }
+
+ @Override
+ public void write(byte[] b, int off, int len) {
+ throw exceptionSupplier.get();
+ }
+
+ @Override
+ public void flush() {
+ throw exceptionSupplier.get();
+ }
+
+ @Override
+ public void close() {
+ throw exceptionSupplier.get();
+ }
+}