Merge "Always keep default constructor in force proguard compatibility mode"
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index 39aadcb..67add9c 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -399,6 +399,14 @@
if (annotations != null) {
annotations.forEach(this::handleAnnotationOfLiveType);
}
+
+ // For Proguard compatibility mark default initializer for live type as live.
+ if (options.forceProguardCompatibility) {
+ if (holder.hasDefaultInitializer()) {
+ DexEncodedMethod init = holder.getDefaultInitializer();
+ markDirectStaticOrConstructorMethodAsLive(init, KeepReason.reachableFromLiveType(type));
+ }
+ }
}
}
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java
index 384c1ff..ea51c65 100644
--- a/src/test/java/com/android/tools/r8/TestBase.java
+++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -76,7 +76,7 @@
for (Class clazz : classes) {
try (FileInputStream in =
new FileInputStream(ToolHelper.getClassFileForTestClass(clazz).toFile())) {
- out.putNextEntry(new ZipEntry(clazz.getCanonicalName().replace('.', '/') + ".class"));
+ out.putNextEntry(new ZipEntry(ToolHelper.getJarEntryForTestClass(clazz)));
ByteStreams.copy(in, out);
out.closeEntry();
}
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index 92d12c1..5753d84 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -75,6 +75,8 @@
private static final String ANDROID_JAR_PATTERN = "third_party/android_jar/lib-v%d/android.jar";
private static final int DEFAULT_MIN_SDK = AndroidApiLevel.I.getLevel();
+ private static final String PROGUARD = "third_party/proguard/proguard5.2.1/bin/proguard.sh";
+
public enum DexVm {
ART_4_4_4_TARGET(Version.V4_4_4, Kind.TARGET),
ART_4_4_4_HOST(Version.V4_4_4, Kind.HOST),
@@ -567,7 +569,7 @@
return Paths.get(BUILD_DIR, "classes", "test");
}
- public static Path getClassFileForTestClass(Class clazz) {
+ private static List<String> getNamePartsForTestClass(Class clazz) {
List<String> parts = Lists.newArrayList(clazz.getCanonicalName().split("\\."));
Class enclosing = clazz;
while (enclosing.getEnclosingClass() != null) {
@@ -576,10 +578,20 @@
enclosing = clazz.getEnclosingClass();
}
parts.set(parts.size() - 1, parts.get(parts.size() - 1) + ".class");
+ return parts;
+ }
+
+ public static Path getClassFileForTestClass(Class clazz) {
+ List<String> parts = getNamePartsForTestClass(clazz);
return getClassPathForTests().resolve(
Paths.get("", parts.toArray(new String[parts.size() - 1])));
}
+ public static String getJarEntryForTestClass(Class clazz) {
+ List<String> parts = getNamePartsForTestClass(clazz);
+ return String.join("/", parts);
+ }
+
public static DexApplication buildApplication(List<String> fileNames)
throws IOException, ExecutionException {
return buildApplicationWithAndroidJar(fileNames, getDefaultAndroidJar());
@@ -958,6 +970,26 @@
}
}
+ public static void runProguard(Path inJar, Path outJar, Path config) throws IOException {
+ List<String> command = new ArrayList<>();
+ command.add(PROGUARD);
+ command.add("-forceprocessing"); // Proguard just checks the creation time on the in/out jars.
+ command.add("-injars");
+ command.add(inJar.toString());
+ command.add("-libraryjars");
+ command.add(ToolHelper.getDefaultAndroidJar());
+ command.add("@" + config);
+ command.add("-outjar");
+ command.add(outJar.toString());
+ command.add("-printmapping");
+ ProcessBuilder builder = new ProcessBuilder(command);
+ ToolHelper.ProcessResult result = ToolHelper.runProcess(builder);
+ if (result.exitCode != 0) {
+ fail("Proguard failed, exit code " + result.exitCode + ", stderr:\n" + result.stderr);
+ }
+ }
+
+
public static class ProcessResult {
public final int exitCode;
diff --git a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ForceProguardCompatibilityTest.java b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ForceProguardCompatibilityTest.java
index 298876f..dae1163 100644
--- a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ForceProguardCompatibilityTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/ForceProguardCompatibilityTest.java
@@ -5,7 +5,6 @@
package com.android.tools.r8.shaking.forceproguardcompatibility;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.R8Command;
@@ -16,12 +15,18 @@
import com.android.tools.r8.utils.DexInspector;
import com.android.tools.r8.utils.DexInspector.ClassSubject;
import com.android.tools.r8.utils.DexInspector.MethodSubject;
+import com.android.tools.r8.utils.FileUtils;
import com.google.common.collect.ImmutableList;
+import java.io.File;
+import java.nio.file.Path;
+import java.util.List;
import org.junit.Test;
public class ForceProguardCompatibilityTest extends TestBase {
- private void test(Class mainClass, Class mentionedClass, boolean arrayClass,
- boolean forceProguardCompatibility)
+ // Actually running Proguard should only be during development.
+ private final boolean RUN_PROGUARD = false;
+
+ private void test(Class mainClass, Class mentionedClass, boolean forceProguardCompatibility)
throws Exception {
String proguardConfig = keepMainProguardConfiguration(mainClass, true, false);
DexInspector inspector = new DexInspector(
@@ -32,28 +37,24 @@
assertTrue(inspector.clazz(mainClass.getCanonicalName()).isPresent());
ClassSubject clazz = inspector.clazz(getJavacGeneratedClassName(mentionedClass));
assertTrue(clazz.isPresent());
- if (arrayClass) {
- MethodSubject defaultInitializer = clazz.method(MethodSignature.initializer(new String[]{}));
- assertFalse(defaultInitializer.isPresent());
- } else {
- MethodSubject defaultInitializer = clazz.method(MethodSignature.initializer(new String[]{}));
- assertEquals(forceProguardCompatibility, defaultInitializer.isPresent());
- }
+ MethodSubject defaultInitializer = clazz.method(MethodSignature.initializer(new String[]{}));
+ assertEquals(forceProguardCompatibility, defaultInitializer.isPresent());
}
@Test
public void testKeepDefaultInitializer() throws Exception {
- test(TestMain.class, TestMain.MentionedClass.class, false, true);
- test(TestMain.class, TestMain.MentionedClass.class, false, false);
+ test(TestMain.class, TestMain.MentionedClass.class, true);
+ test(TestMain.class, TestMain.MentionedClass.class, false);
}
@Test
public void testKeepDefaultInitializerArrayType() throws Exception {
- test(TestMainArrayType.class, TestMainArrayType.MentionedClass.class, true, true);
- test(TestMainArrayType.class, TestMainArrayType.MentionedClass.class, true, false);
+ test(TestMainArrayType.class, TestMainArrayType.MentionedClass.class, true);
+ test(TestMainArrayType.class, TestMainArrayType.MentionedClass.class, false);
}
- private void runAnnotationsTest(boolean forceProguardCompatibility, boolean keepAnnotations) throws Exception {
+ private void runAnnotationsTest(boolean forceProguardCompatibility, boolean keepAnnotations)
+ throws Exception {
R8Command.Builder builder =
new CompatProguardCommandBuilder(forceProguardCompatibility, false);
// Add application classes including the annotation class.
@@ -93,4 +94,35 @@
runAnnotationsTest(false, true);
runAnnotationsTest(false, false);
}
+
+ private void runDefaultConstructorTest(boolean forceProguardCompatibility,
+ Class<?> testClass, boolean hasDefaultConstructor) throws Exception {
+ R8Command.Builder builder = new CompatProguardCommandBuilder(forceProguardCompatibility, false);
+ builder.addProgramFiles(ToolHelper.getClassFileForTestClass(testClass));
+ List<String> proguardConfig = ImmutableList.of(
+ "-keep class " + testClass.getCanonicalName() + " {",
+ " public void method();",
+ "}");
+ builder.addProguardConfiguration(proguardConfig);
+ DexInspector inspector = new DexInspector(ToolHelper.runR8(builder.build()));
+ ClassSubject clazz = inspector.clazz(getJavacGeneratedClassName(testClass));
+ assertTrue(clazz.isPresent());
+ assertEquals(forceProguardCompatibility && hasDefaultConstructor,
+ clazz.init(ImmutableList.of()).isPresent());
+
+ if (RUN_PROGUARD) {
+ Path proguardedJar = File.createTempFile("proguarded", ".jar", temp.getRoot()).toPath();
+ Path proguardConfigFile = File.createTempFile("proguard", ".config", temp.getRoot()).toPath();
+ FileUtils.writeTextFile(proguardConfigFile, proguardConfig);
+ ToolHelper.runProguard(jarTestClasses(testClass), proguardedJar, proguardConfigFile);
+ }
+ }
+
+ @Test
+ public void testDefaultConstructor() throws Exception {
+ runDefaultConstructorTest(true, TestClassWithDefaultConstructor.class, true);
+ runDefaultConstructorTest(true, TestClassWithoutDefaultConstructor.class, false);
+ runDefaultConstructorTest(false, TestClassWithDefaultConstructor.class, true);
+ runDefaultConstructorTest(false, TestClassWithoutDefaultConstructor.class, false);
+ }
}
diff --git a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/TestClassWithDefaultConstructor.java b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/TestClassWithDefaultConstructor.java
new file mode 100644
index 0000000..fd7909d
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/TestClassWithDefaultConstructor.java
@@ -0,0 +1,16 @@
+// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.shaking.forceproguardcompatibility;
+
+public class TestClassWithDefaultConstructor {
+ public TestClassWithDefaultConstructor() {
+ }
+
+ public TestClassWithDefaultConstructor(int i) {
+ }
+
+ public void method() {
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/TestClassWithoutDefaultConstructor.java b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/TestClassWithoutDefaultConstructor.java
new file mode 100644
index 0000000..9a5679d
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/TestClassWithoutDefaultConstructor.java
@@ -0,0 +1,13 @@
+// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.shaking.forceproguardcompatibility;
+
+public class TestClassWithoutDefaultConstructor {
+ public TestClassWithoutDefaultConstructor(int i) {
+ }
+
+ public void method() {
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/shaking/includedescriptorclasses/IncludeDescriptorClassesTest.java b/src/test/java/com/android/tools/r8/shaking/includedescriptorclasses/IncludeDescriptorClassesTest.java
index b09ef9b..8bff0b3 100644
--- a/src/test/java/com/android/tools/r8/shaking/includedescriptorclasses/IncludeDescriptorClassesTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/includedescriptorclasses/IncludeDescriptorClassesTest.java
@@ -6,13 +6,11 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.utils.DexInspector;
import com.google.common.collect.ImmutableList;
-import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
@@ -26,29 +24,6 @@
public class IncludeDescriptorClassesTest extends TestBase {
- private static String PROGUARD = "third_party/proguard/proguard5.2.1/bin/proguard.sh";
-
- private Path runProguard(Path inJar, Path config) throws IOException {
- Path outJar = File.createTempFile("junit", ".jar", temp.getRoot()).toPath();
- List<String> command = new ArrayList<>();
- command.add(PROGUARD);
- command.add("-forceprocessing"); // Proguard just checks the creation time on the in/out jars.
- command.add("-injars");
- command.add(inJar.toString());
- command.add("-libraryjars");
- command.add(ToolHelper.getDefaultAndroidJar());
- command.add("@" + config);
- command.add("-outjar");
- command.add(outJar.toString());
- command.add("-printmapping");
- ProcessBuilder builder = new ProcessBuilder(command);
- ToolHelper.ProcessResult result = ToolHelper.runProcess(builder);
- if (result.exitCode != 0) {
- fail("Proguard failed, exit code " + result.exitCode + ", stderr:\n" + result.stderr);
- }
- return outJar;
- }
-
private Set<String> readJarClasses(Path jar) throws IOException {
Set<String> result = new HashSet<>();
try (ZipFile zipFile = new ZipFile(jar.toFile())) {
@@ -115,7 +90,8 @@
Set<String> classesAfterProguard = null;
// Actually running Proguard should only be during development.
if (false) {
- Path proguardedJar = runProguard(jarTestClasses(classes), proguardConfig);
+ Path proguardedJar = temp.newFile("proguarded.jar").toPath();
+ ToolHelper.runProguard(jarTestClasses(classes), proguardedJar, proguardConfig);
classesAfterProguard = readJarClasses(proguardedJar);
}
diff --git a/src/test/java/com/android/tools/r8/utils/DexInspector.java b/src/test/java/com/android/tools/r8/utils/DexInspector.java
index 086287c..4b2b6ae 100644
--- a/src/test/java/com/android/tools/r8/utils/DexInspector.java
+++ b/src/test/java/com/android/tools/r8/utils/DexInspector.java
@@ -270,6 +270,10 @@
return method("void", "<clinit>", ImmutableList.of());
}
+ public MethodSubject init(List<String> parameters) {
+ return method("void", "<init>", parameters);
+ }
+
public MethodSubject method(MethodSignature signature) {
return method(signature.type, signature.name, ImmutableList.copyOf(signature.parameters));
}