Version 1.5.13-q1
Cherry-pick: Ensure compatdx and compatproguard proper extensions of R8.
CL: https://r8-review.googlesource.com/c/r8/+/38640
Cherry-pick: Correctly handle multiple access modifiers in Proguard rules
CL: https://r8-review.googlesource.com/c/r8/+/36702
Bug: 132911943
Bug: 129781627
Change-Id: Id2d87642bb18bb08e5fa252f3e51575b8f7f9113
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index 3e368b0..a0e04a4 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.5.13";
+ public static final String LABEL = "1.5.13-q1";
private Version() {
}
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardAccessFlags.java b/src/main/java/com/android/tools/r8/shaking/ProguardAccessFlags.java
index e857165..1593543 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardAccessFlags.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardAccessFlags.java
@@ -12,6 +12,9 @@
public class ProguardAccessFlags {
+ private final static int PPP_MASK =
+ new ProguardAccessFlags().setPublic().setProtected().setPrivate().flags;
+
private int flags = 0;
// Ordered list of flag names. Must be consistent with getPredicates.
@@ -50,7 +53,12 @@
}
private boolean containsAll(int other) {
- return (flags & other) == flags;
+ // ppp flags are the flags public, protected and private.
+ return
+ // All non-ppp flags set must match (a 0 in non-ppp flags means don't care).
+ (((flags & ~PPP_MASK) & (other & ~PPP_MASK)) == (flags & ~PPP_MASK))
+ // With no ppp flags any flags match, with ppp flags there must be an overlap to match.
+ && (((flags & PPP_MASK) == 0) || ((flags & PPP_MASK) & (other & PPP_MASK)) != 0);
}
private boolean containsNone(int other) {
@@ -69,24 +77,27 @@
this.flags = other.getOriginalAccessFlags();
}
- public void setPublic() {
+ public ProguardAccessFlags setPublic() {
set(Constants.ACC_PUBLIC);
+ return this;
}
public boolean isPublic() {
return isSet(Constants.ACC_PUBLIC);
}
- public void setPrivate() {
+ public ProguardAccessFlags setPrivate() {
set(Constants.ACC_PRIVATE);
+ return this;
}
public boolean isPrivate() {
return isSet(Constants.ACC_PRIVATE);
}
- public void setProtected() {
+ public ProguardAccessFlags setProtected() {
set(Constants.ACC_PROTECTED);
+ return this;
}
public boolean isProtected() {
diff --git a/src/main/keep-compatdx.txt b/src/main/keep-compatdx.txt
index 75a8012..e4c5688 100644
--- a/src/main/keep-compatdx.txt
+++ b/src/main/keep-compatdx.txt
@@ -2,5 +2,9 @@
# 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.
--keep public class com.android.tools.r8.compatdx.CompatDx { public static void main(java.lang.String[]); }
--keepattributes LineNumberTable
+# This entry must remain a proper extension of R8 to ensure all required parts are kept.
+-include keep.txt
+
+-keep public class com.android.tools.r8.compatdx.CompatDx {
+ public static void main(java.lang.String[]);
+}
diff --git a/src/main/keep-compatproguard.txt b/src/main/keep-compatproguard.txt
index e29d13e..80ca009 100644
--- a/src/main/keep-compatproguard.txt
+++ b/src/main/keep-compatproguard.txt
@@ -2,5 +2,9 @@
# 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.
--keep public class com.android.tools.r8.compatproguard.CompatProguard { public static void main(java.lang.String[]); }
--keepattributes LineNumberTable
+# This entry must remain a proper extension of R8 to ensure all required parts are kept.
+-include keep.txt
+
+-keep public class com.android.tools.r8.compatproguard.CompatProguard {
+ public static void main(java.lang.String[]);
+}
diff --git a/src/test/java/com/android/tools/r8/shaking/modifiers/AccessFlagsCombinationsTest.java b/src/test/java/com/android/tools/r8/shaking/modifiers/AccessFlagsCombinationsTest.java
new file mode 100644
index 0000000..fc70ae2
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/shaking/modifiers/AccessFlagsCombinationsTest.java
@@ -0,0 +1,209 @@
+// 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.shaking.modifiers;
+
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import java.util.function.Consumer;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class AccessFlagsCombinationsTest extends TestBase {
+
+ enum Expect {
+ STATICS_ONLY,
+ NON_STATICS_ONLY,
+ BOTH_STATICS_AND_NON_STATICS
+ }
+
+ private final TestParameters parameters;
+ private static final int PPP =
+ Constants.ACC_PUBLIC | Constants.ACC_PROTECTED | Constants.ACC_PRIVATE;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimes().build();
+ }
+
+ public AccessFlagsCombinationsTest(TestParameters parameters) {
+ assertEquals(7, PPP);
+ this.parameters = parameters;
+ }
+
+ private void checkKeptMembers(CodeInspector inspector, Integer flags, Expect expect) {
+ ClassSubject classSubject = inspector.clazz(TestClass.class);
+
+ boolean includeStatic =
+ expect == Expect.STATICS_ONLY || expect == Expect.BOTH_STATICS_AND_NON_STATICS;
+ boolean includeNonStatic =
+ expect == Expect.NON_STATICS_ONLY || expect == Expect.BOTH_STATICS_AND_NON_STATICS;
+
+
+ boolean includePublic = (flags & PPP) == 0 || (flags & Constants.ACC_PUBLIC) != 0;
+ boolean includeProtected = (flags & PPP) == 0 || (flags & Constants.ACC_PROTECTED) != 0;
+ boolean includePrivate = (flags & PPP) == 0 || (flags & Constants.ACC_PRIVATE) != 0;
+ boolean includePackagePrivate = (flags & PPP) == 0;
+
+ assertEquals(
+ includePublic && includeNonStatic,
+ classSubject.uniqueMethodWithName("publicMethod").isPresent());
+ assertEquals(
+ includeProtected && includeNonStatic,
+ classSubject.uniqueMethodWithName("protectedMethod").isPresent());
+ assertEquals(
+ includePrivate && includeNonStatic,
+ classSubject.uniqueMethodWithName("privateMethod").isPresent());
+ assertEquals(
+ includePackagePrivate && includeNonStatic,
+ classSubject.uniqueMethodWithName("packagePrivateMethod").isPresent());
+ assertEquals(
+ includePublic && includeStatic,
+ classSubject.uniqueMethodWithName("publicStaticMethod").isPresent());
+ assertEquals(
+ includeProtected && includeStatic,
+ classSubject.uniqueMethodWithName("protectedStaticMethod").isPresent());
+ assertEquals(
+ includePrivate && includeStatic,
+ classSubject.uniqueMethodWithName("privateStaticMethod").isPresent());
+ assertEquals(
+ includePackagePrivate && includeStatic,
+ classSubject.uniqueMethodWithName("packagePrivateStaticMethod").isPresent());
+ assertEquals(
+ includePublic && includeNonStatic,
+ classSubject.uniqueFieldWithName("publicField").isPresent());
+ assertEquals(
+ includeProtected && includeNonStatic,
+ classSubject.uniqueFieldWithName("protectedField").isPresent());
+ assertEquals(
+ includePrivate && includeNonStatic,
+ classSubject.uniqueFieldWithName("privateField").isPresent());
+ assertEquals(
+ includePackagePrivate && includeNonStatic,
+ classSubject.uniqueFieldWithName("packagePrivateField").isPresent());
+ assertEquals(
+ includePublic && includeStatic,
+ classSubject.uniqueFieldWithName("publicStaticField").isPresent());
+ assertEquals(
+ includeProtected && includeStatic,
+ classSubject.uniqueFieldWithName("protectedStaticField").isPresent());
+ assertEquals(
+ includePrivate && includeStatic,
+ classSubject.uniqueFieldWithName("privateStaticField").isPresent());
+ assertEquals(
+ includePackagePrivate && includeStatic,
+ classSubject.uniqueFieldWithName("packagePrivateStaticField").isPresent());
+ }
+
+ public void runTest(List<String> keepRules, Consumer<CodeInspector> inspector) throws Exception {
+ String expectedOutput = StringUtils.lines("Hello, world");
+ testForR8(parameters.getBackend())
+ .addInnerClasses(AccessFlagsCombinationsTest.class)
+ .addKeepMainRule(TestClass.class)
+ .addKeepRules(keepRules)
+ // Commented out for the 1.5.13 branch as this is currently not merged.
+ //.setMinApi(parameters.getRuntime())
+ .compile()
+ .inspect(inspector)
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(expectedOutput);
+ }
+
+ private String flagString(int flags) {
+ return new StringBuilder()
+ .append((flags & Constants.ACC_PUBLIC) != 0 ? " public" : "")
+ .append((flags & Constants.ACC_PROTECTED) != 0 ? " protected" : "")
+ .append((flags & Constants.ACC_PRIVATE) != 0 ? " private" : "")
+ .toString();
+ }
+
+ @Test
+ public void testImplicitBothStaticAndNonStaticMembers() throws Exception {
+ for (int flags = 0; flags <= PPP; flags++) {
+ Integer finalFlags = flags;
+ runTest(
+ ImmutableList.of("-keep class **.*TestClass {" + flagString(flags) + " *; }"),
+ inspector ->
+ checkKeptMembers(inspector, finalFlags, Expect.BOTH_STATICS_AND_NON_STATICS));
+ }
+ }
+
+ @Test
+ public void testExplicitNotStaticMembers() throws Exception {
+ for (int flags = 0; flags <= PPP; flags++) {
+ Integer finalFlags = flags;
+ runTest(
+ ImmutableList.of("-keep class **.*TestClass { !static" + flagString(flags) + " *; }"),
+ inspector -> checkKeptMembers(inspector, finalFlags, Expect.NON_STATICS_ONLY));
+ }
+ }
+
+ @Test
+ public void testStaticMembers() throws Exception {
+ for (int flags = 0; flags <= PPP; flags++) {
+ Integer finalFlags = flags | Constants.ACC_STATIC;
+ runTest(
+ ImmutableList.of("-keep class **.*TestClass { static" + flagString(flags) + " *; }"),
+ inspector -> checkKeptMembers(inspector, finalFlags, Expect.STATICS_ONLY));
+ }
+ }
+
+ static class TestClass {
+ public static int publicStaticField;
+ protected static int protectedStaticField;
+ private static int privateStaticField;
+ static int packagePrivateStaticField;
+ public int publicField;
+ protected int protectedField;
+ private int privateField;
+ int packagePrivateField;
+
+ public static void publicStaticMethod() {
+
+ }
+
+ protected static void protectedStaticMethod() {
+
+ }
+
+ private static void privateStaticMethod() {
+
+ }
+
+ static void packagePrivateStaticMethod() {
+
+ }
+
+ public void publicMethod() {
+
+ }
+
+ protected void protectedMethod() {
+
+ }
+
+ private void privateMethod() {
+
+ }
+
+ void packagePrivateMethod() {
+
+ }
+
+ public static void main(String[] args) {
+ System.out.println("Hello, world");
+ }
+ }
+}
\ No newline at end of file