Allow whitespace between @ and interface in Proguard rules
Bug: 79925760
Change-Id: Ibfc0b9cd0336469a0786c0ce1e7b4aad477f5694
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
index 91cab92..36b5ec7 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
@@ -714,6 +714,11 @@
}
}
+ private StringDiagnostic parseClassTypeUnexpected(Origin origin, TextPosition start) {
+ return new StringDiagnostic(
+ "Expected [!]interface|@interface|class|enum", origin, getPosition(start));
+ }
+
private void parseClassType(
ProguardClassSpecification.Builder builder) throws ProguardRuleParserException {
skipWhitespace();
@@ -721,17 +726,21 @@
if (acceptChar('!')) {
builder.setClassTypeNegated(true);
}
- if (acceptString("interface")) {
+ if (acceptChar('@')) {
+ skipWhitespace();
+ if (acceptString("interface")) {
+ builder.setClassType(ProguardClassType.ANNOTATION_INTERFACE);
+ } else {
+ throw reporter.fatalError(parseClassTypeUnexpected(origin, start));
+ }
+ } else if (acceptString("interface")) {
builder.setClassType(ProguardClassType.INTERFACE);
- } else if (acceptString("@interface")) {
- builder.setClassType(ProguardClassType.ANNOTATION_INTERFACE);
} else if (acceptString("class")) {
builder.setClassType(ProguardClassType.CLASS);
} else if (acceptString("enum")) {
builder.setClassType(ProguardClassType.ENUM);
} else {
- throw reporter.fatalError(new StringDiagnostic(
- "Expected [!]interface|@interface|class|enum", origin, getPosition(start)));
+ throw reporter.fatalError(parseClassTypeUnexpected(origin, start));
}
}
diff --git a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
index 1012421..28ddd4a 100644
--- a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
@@ -139,6 +139,8 @@
private Reporter reporter;
private KeepingDiagnosticHandler handler;
private ProguardConfigurationParser parser;
+ private List<String> whiteSpace = ImmutableList.of("", " ", " ", "\t", " \t", " \t", " \t ", " \t\t \t ");
+
@Before
public void reset() {
@@ -789,12 +791,10 @@
@Test
public void parseKeepModifiers() {
- List<String> ws = ImmutableList.of("", " ", " ", "\t", " \t", " \t", " \t ", " \t\t \t ");
-
- for (String before : ws) {
- for (String after : ws) {
+ for (String before : whiteSpace) {
+ for (String after : whiteSpace) {
reset();
- ProguardConfiguration config = parseAndVerifyParserEndsCleanly(ImmutableList.of(
+ parseAndVerifyParserEndsCleanly(ImmutableList.of(
"-keep"
+ before + "," + after + "includedescriptorclasses"
+ before + "," + after + "allowshrinking"
@@ -807,6 +807,16 @@
}
@Test
+ public void parseKeepAnnotation() {
+ for (String space : whiteSpace) {
+ reset();
+ parseAndVerifyParserEndsCleanly(ImmutableList.of(
+ "-keep @" + space + "interface A"
+ ));
+ }
+ }
+
+ @Test
public void regress78442725() {
parseAndVerifyParserEndsCleanly(ImmutableList.of(
"-keep, includedescriptorclasses class in.uncod.android.bypass.Document { *; }",
@@ -1706,6 +1716,24 @@
verifyWithProguard(proguardConfig);
}
+ @Test
+ public void parse_regress79925760() throws Exception {
+ Path proguardConfig = writeTextToTempFile(
+ "-keep public @ interface test.MyAnnotation"
+ );
+ ProguardConfigurationParser parser =
+ new ProguardConfigurationParser(new DexItemFactory(), reporter);
+ parser.parse(proguardConfig);
+ verifyParserEndsCleanly();
+
+ ProguardConfiguration config = parser.getConfig();
+ assertEquals(1, config.getRules().size());
+ ProguardKeepRule rule = (ProguardKeepRule) config.getRules().get(0);
+ assertEquals(ProguardClassType.ANNOTATION_INTERFACE, rule.getClassType());
+
+ verifyWithProguard(proguardConfig);
+ }
+
private ProguardConfiguration parseAndVerifyParserEndsCleanly(List<String> config) {
parser.parse(createConfigurationForTesting(config));
verifyParserEndsCleanly();