Make no -keepattributes flag keep all in Proguard compatibility mode
When running with --force-proguard-compatibility for the compat proguard
command treat no -keepattributes flag as keep all attributes when not
minifying.
This should follow the Proguard semantics where -keepattributes is
documented as "Only applicable when obfuscating".
Bug: 68246915
Change-Id: Ib0e71cd8b0819af6ca148365d9b4d155db06e5e0
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index 5b3cfb5..1df56db 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -224,6 +224,7 @@
throw new CompilationException(e.getMessage(), e.getCause());
}
configurationBuilder = parser.getConfigurationBuilder();
+ configurationBuilder.setForceProguardCompatibility(forceProguardCompatibility);
}
if (proguardConfigurationConsumer != null) {
diff --git a/src/main/java/com/android/tools/r8/compatproguard/CompatProguardCommandBuilder.java b/src/main/java/com/android/tools/r8/compatproguard/CompatProguardCommandBuilder.java
index 2c7c43b..71bc6eb 100644
--- a/src/main/java/com/android/tools/r8/compatproguard/CompatProguardCommandBuilder.java
+++ b/src/main/java/com/android/tools/r8/compatproguard/CompatProguardCommandBuilder.java
@@ -7,7 +7,7 @@
import com.android.tools.r8.R8Command;
public class CompatProguardCommandBuilder extends R8Command.Builder {
- CompatProguardCommandBuilder(boolean forceProguardCompatibility) {
+ public CompatProguardCommandBuilder(boolean forceProguardCompatibility) {
super(true, forceProguardCompatibility);
setEnableDesugaring(false);
}
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
index 4a84321..b3cfcb2 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
@@ -44,6 +44,8 @@
private boolean useUniqueClassMemberNames;
private boolean keepParameterNames;
private ProguardClassFilter.Builder adaptClassStrings = ProguardClassFilter.builder();
+ private boolean forceProguardCompatibility = false;
+
private Builder(DexItemFactory dexItemFactory) {
this.dexItemFactory = dexItemFactory;
resetProguardDefaults();
@@ -205,7 +207,22 @@
adaptClassStrings.addPattern(pattern);
}
+ public void setForceProguardCompatibility(boolean forceProguardCompatibility) {
+ this.forceProguardCompatibility = forceProguardCompatibility;
+ }
+
public ProguardConfiguration build() throws CompilationException {
+ ProguardKeepAttributes keepAttributes;
+
+
+ if (forceProguardCompatibility
+ && !isObfuscating()
+ && keepAttributePatterns.size() == 0) {
+ keepAttributes = ProguardKeepAttributes.fromPatterns(ProguardKeepAttributes.KEEP_ALL);
+ } else {
+ keepAttributes = ProguardKeepAttributes.fromPatterns(keepAttributePatterns);
+ }
+
return new ProguardConfiguration(
dexItemFactory,
injars,
@@ -224,7 +241,7 @@
applyMappingFile,
verbose,
renameSourceFileAttribute,
- keepAttributePatterns,
+ keepAttributes,
dontWarnPatterns.build(),
rules,
printSeeds,
@@ -285,7 +302,7 @@
Path applyMappingFile,
boolean verbose,
String renameSourceFileAttribute,
- List<String> keepAttributesPatterns,
+ ProguardKeepAttributes keepAttributes,
ProguardClassFilter dontWarnPatterns,
List<ProguardConfigurationRule> rules,
boolean printSeeds,
@@ -313,7 +330,7 @@
this.applyMappingFile = applyMappingFile;
this.verbose = verbose;
this.renameSourceFileAttribute = renameSourceFileAttribute;
- this.keepAttributes = ProguardKeepAttributes.fromPatterns(keepAttributesPatterns);
+ this.keepAttributes = keepAttributes;
this.dontWarnPatterns = dontWarnPatterns;
this.rules = ImmutableList.copyOf(rules);
this.printSeeds = printSeeds;
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 4d59f63..1519f6c 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
@@ -8,7 +8,10 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import com.android.tools.r8.R8Command;
import com.android.tools.r8.TestBase;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.compatproguard.CompatProguardCommandBuilder;
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
import com.android.tools.r8.utils.DexInspector;
import com.android.tools.r8.utils.DexInspector.ClassSubject;
@@ -49,4 +52,45 @@
test(TestMainArrayType.class, TestMainArrayType.MentionedClass.class, true, true);
test(TestMainArrayType.class, TestMainArrayType.MentionedClass.class, true, false);
}
+
+ private void runAnnotationsTest(boolean forceProguardCompatibility, boolean keepAnnotations) throws Exception {
+ R8Command.Builder builder =
+ new CompatProguardCommandBuilder(forceProguardCompatibility);
+ // Add application classes including the annotation class.
+ Class mainClass = TestMain.class;
+ Class mentionedClassWithAnnotations = TestMain.MentionedClassWithAnnotation.class;
+ Class annotationClass = TestAnnotation.class;
+ builder.addProgramFiles(ToolHelper.getClassFileForTestClass(mainClass));
+ builder.addProgramFiles(ToolHelper.getClassFileForTestClass(TestMain.MentionedClass.class));
+ builder.addProgramFiles(ToolHelper.getClassFileForTestClass(mentionedClassWithAnnotations));
+ builder.addProgramFiles(ToolHelper.getClassFileForTestClass(annotationClass));
+ // Keep main class and the annotation class.
+ builder.addProguardConfiguration(
+ ImmutableList.of(keepMainProguardConfiguration(mainClass, true, false)));
+ builder.addProguardConfiguration(
+ ImmutableList.of("-keep class " + annotationClass.getCanonicalName() + " { }"));
+ if (keepAnnotations) {
+ builder.addProguardConfiguration(ImmutableList.of("-keepattributes *Annotation*"));
+ }
+
+ DexInspector inspector = new DexInspector(ToolHelper.runR8(builder.build()));
+ assertTrue(inspector.clazz(mainClass.getCanonicalName()).isPresent());
+ ClassSubject clazz = inspector.clazz(getJavacGeneratedClassName(mentionedClassWithAnnotations));
+ assertTrue(clazz.isPresent());
+
+ assertEquals(!keepAnnotations && forceProguardCompatibility,
+ clazz.annotation("dalvik.annotation.EnclosingClass").isPresent());
+ assertEquals(!keepAnnotations && forceProguardCompatibility,
+ clazz.annotation("dalvik.annotation.InnerClass").isPresent());
+ assertEquals(forceProguardCompatibility || keepAnnotations,
+ clazz.annotation(annotationClass.getCanonicalName()).isPresent());
+ }
+
+ @Test
+ public void testAnnotations() throws Exception {
+ runAnnotationsTest(true, true);
+ runAnnotationsTest(true, false);
+ runAnnotationsTest(false, true);
+ runAnnotationsTest(false, false);
+ }
}
diff --git a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/TestMain.java b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/TestMain.java
index 94a9d0a..1a484b5 100644
--- a/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/TestMain.java
+++ b/src/test/java/com/android/tools/r8/shaking/forceproguardcompatibility/TestMain.java
@@ -11,7 +11,14 @@
}
}
+ @TestAnnotation(0)
+ public static class MentionedClassWithAnnotation {
+ public MentionedClassWithAnnotation() {
+ }
+ }
+
public static void main(String[] args) {
System.out.println(MentionedClass.class.getCanonicalName());
+ System.out.println(MentionedClassWithAnnotation.class.getCanonicalName());
}
}