Proguard config parser: allow spaces and quotes in class name list.
Bug: 124181032
Change-Id: Iee3877252efed525cdc5fe3f08842518141533c7
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 e3a8273..5acd2a8 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
@@ -1433,11 +1433,27 @@
}
private IdentifierPatternWithWildcards acceptIdentifierWithBackreference(IdentifierType kind) {
+ IdentifierPatternWithWildcardsAndNegation pattern =
+ acceptIdentifierWithBackreference(kind, false);
+ if (pattern == null) {
+ return null;
+ }
+ assert !pattern.negated;
+ return pattern.patternWithWildcards;
+ }
+
+ private IdentifierPatternWithWildcardsAndNegation acceptIdentifierWithBackreference(
+ IdentifierType kind, boolean allowNegation) {
ImmutableList.Builder<ProguardWildcard> wildcardsCollector = ImmutableList.builder();
StringBuilder currentAsterisks = null;
int asteriskCount = 0;
StringBuilder currentBackreference = null;
skipWhitespace();
+
+ final char quote = acceptQuoteIfPresent();
+ final boolean quoted = isQuote(quote);
+ final boolean negated = allowNegation ? acceptChar('!') : false;
+
int start = position;
int end = position;
while (!eof(end)) {
@@ -1516,9 +1532,17 @@
currentBackreference = new StringBuilder();
end += Character.charCount(current);
} else {
+ if (quoted && quote != current) {
+ throw reporter.fatalError(
+ new StringDiagnostic(
+ "Invalid character '" + (char) current + "', expected end-quote.",
+ origin,
+ getPosition()));
+ }
break;
}
}
+ position = quoted ? end + 1 : end;
if (currentAsterisks != null) {
wildcardsCollector.add(new ProguardWildcard.Pattern(currentAsterisks.toString()));
}
@@ -1530,10 +1554,8 @@
if (start == end) {
return null;
}
- position = end;
- return new IdentifierPatternWithWildcards(
- contents.substring(start, end),
- wildcardsCollector.build());
+ return new IdentifierPatternWithWildcardsAndNegation(
+ contents.substring(start, end), wildcardsCollector.build(), negated);
}
private String acceptFieldNameOrIntegerForReturn() {
@@ -1627,20 +1649,20 @@
}
}
+ private void parseClassNameAddToBuilder(ProguardClassNameList.Builder builder)
+ throws ProguardRuleParserException {
+ IdentifierPatternWithWildcardsAndNegation name = parseClassName(true);
+ builder.addClassName(
+ name.negated,
+ ProguardTypeMatcher.create(name.patternWithWildcards, ClassOrType.CLASS, dexItemFactory));
+ skipWhitespace();
+ }
+
private ProguardClassNameList parseClassNames() throws ProguardRuleParserException {
ProguardClassNameList.Builder builder = ProguardClassNameList.builder();
- skipWhitespace();
- boolean negated = acceptChar('!');
- builder.addClassName(negated,
- ProguardTypeMatcher.create(parseClassName(), ClassOrType.CLASS, dexItemFactory));
- skipWhitespace();
- while (acceptChar(',')) {
- skipWhitespace();
- negated = acceptChar('!');
- builder.addClassName(negated,
- ProguardTypeMatcher.create(parseClassName(), ClassOrType.CLASS, dexItemFactory));
- skipWhitespace();
- }
+ do {
+ parseClassNameAddToBuilder(builder);
+ } while (acceptChar(','));
return builder.build();
}
@@ -1650,8 +1672,15 @@
}
private IdentifierPatternWithWildcards parseClassName() throws ProguardRuleParserException {
- IdentifierPatternWithWildcards name =
- acceptIdentifierWithBackreference(IdentifierType.CLASS_NAME);
+ IdentifierPatternWithWildcardsAndNegation name = parseClassName(false);
+ assert !name.negated;
+ return name.patternWithWildcards;
+ }
+
+ private IdentifierPatternWithWildcardsAndNegation parseClassName(boolean allowNegation)
+ throws ProguardRuleParserException {
+ IdentifierPatternWithWildcardsAndNegation name =
+ acceptIdentifierWithBackreference(IdentifierType.CLASS_NAME, allowNegation);
if (name == null) {
throw parseError("Class name expected");
}
@@ -1838,4 +1867,15 @@
return false;
}
}
+
+ static class IdentifierPatternWithWildcardsAndNegation {
+ final IdentifierPatternWithWildcards patternWithWildcards;
+ final boolean negated;
+
+ IdentifierPatternWithWildcardsAndNegation(
+ String pattern, List<ProguardWildcard> wildcards, boolean negated) {
+ patternWithWildcards = new IdentifierPatternWithWildcards(pattern, wildcards);
+ this.negated = negated;
+ }
+ }
}
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 f3aba75..cac6dd3 100644
--- a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
@@ -2402,12 +2402,14 @@
@Test
public void b124181032() throws Exception {
+ // Test spaces and quotes in class name list.
ProguardConfigurationParser parser;
parser = new ProguardConfigurationParser(new DexItemFactory(), reporter);
parser.parse(
createConfigurationForTesting(
ImmutableList.of(
- "-keepclassmembers class a.b.c.**, !**Client, !**Interceptor {",
+ "-keepclassmembers class \"a.b.c.**\" ,"
+ + " !**d , '!**e' , \"!**f\" , g , 'h' , \"i\" { ",
"<fields>;",
"<init>();",
"}")));
@@ -2415,6 +2417,6 @@
assertEquals(1, rules.size());
ProguardConfigurationRule rule = rules.get(0);
assertEquals(ProguardKeepRuleType.KEEP_CLASS_MEMBERS.toString(), rule.typeString());
- assertEquals("a.b.c.**,!**Client,!**Interceptor", rule.getClassNames().toString());
+ assertEquals("a.b.c.**,!**d,!**e,!**f,g,h,i", rule.getClassNames().toString());
}
}