Parse <n> wildcard in class names.
Bug: 73800755
Change-Id: I3fccb04f2aeae420c8b2ce976a0bb5b15bcb82e7
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 b526973..e96de6f 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
@@ -535,7 +535,7 @@
private ProguardIfRule parseIfRule(TextPosition optionStart)
throws ProguardRuleParserException {
ProguardIfRule.Builder ifRuleBuilder = ProguardIfRule.builder();
- parseClassSpec(ifRuleBuilder, true);
+ parseClassSpec(ifRuleBuilder, false);
// Required a subsequent keep rule.
skipWhitespace();
@@ -1086,15 +1086,52 @@
return Integer.parseInt(s);
}
+ private final Predicate<Character> CLASS_NAME_PREDICATE =
+ character -> IdentifierUtils.isDexIdentifierPart(character)
+ || character == '.'
+ || character == '*'
+ || character == '?'
+ || character == '%'
+ || character == '['
+ || character == ']';
+
private String acceptClassName() {
- return acceptString(character ->
- IdentifierUtils.isDexIdentifierPart(character)
- || character == '.'
- || character == '*'
- || character == '?'
- || character == '%'
- || character == '['
- || character == ']');
+ return acceptString(CLASS_NAME_PREDICATE);
+ }
+
+ private String acceptClassNameWithNthWildcard() {
+ StringBuilder nthWildcard = null;
+ skipWhitespace();
+ int start = position;
+ int end = position;
+ while (!eof(end)) {
+ char current = contents.charAt(end);
+ if (nthWildcard != null) {
+ if (current == '>') {
+ try {
+ Integer.parseUnsignedInt(nthWildcard.toString());
+ } catch (NullPointerException | NumberFormatException e) {
+ return null;
+ }
+ nthWildcard = null;
+ } else {
+ nthWildcard.append(current);
+ }
+ end++;
+ } else if (CLASS_NAME_PREDICATE.test(current)) {
+ end++;
+ } else if (current == '<') {
+ nthWildcard = new StringBuilder();
+ end++;
+ } else {
+ break;
+ }
+ }
+ if (start == end) {
+ return null;
+ }
+ position = end;
+ return contents.substring(start, end);
}
private String acceptFieldNameOrIntegerForReturn() {
@@ -1194,7 +1231,7 @@
}
private String parseClassName() throws ProguardRuleParserException {
- String name = acceptClassName();
+ String name = acceptClassNameWithNthWildcard();
if (name == null) {
throw parseError("Class name expected");
}
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 5f6a5cc..84f6a08 100644
--- a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
@@ -37,6 +37,7 @@
import java.util.Collections;
import java.util.List;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
public class ProguardConfigurationParserTest extends TestBase {
@@ -544,7 +545,7 @@
assertTrue(
config.getAdaptClassStrings().matches(dexItemFactory.createType("Lboobaz;")));
assertTrue(
- config.getAdaptClassStrings().matches(dexItemFactory.createType("Lboobaz;")));
+ config.getAdaptClassStrings().matches(dexItemFactory.createType("Lboobar;")));
assertTrue(
config.getAdaptClassStrings().matches(dexItemFactory.createType("Lfoobar;")));
}
@@ -561,12 +562,47 @@
assertTrue(
config.getAdaptClassStrings().matches(dexItemFactory.createType("Lboobaz;")));
assertTrue(
- config.getAdaptClassStrings().matches(dexItemFactory.createType("Lboobaz;")));
+ config.getAdaptClassStrings().matches(dexItemFactory.createType("Lboobar;")));
assertTrue(
config.getAdaptClassStrings().matches(dexItemFactory.createType("Lfoobar;")));
}
@Test
+ public void testAdaptClassStringsNthWildcard() throws Exception {
+ DexItemFactory dexItemFactory = new DexItemFactory();
+ ProguardConfigurationParser parser =
+ new ProguardConfigurationParser(dexItemFactory, reporter);
+ String wildcard = "-adaptclassstrings *foo<1>";
+ parser.parse(createConfigurationForTesting(ImmutableList.of(wildcard)));
+ verifyParserEndsCleanly();
+ ProguardConfiguration config = parser.getConfig();
+ assertFalse(
+ config.getAdaptClassStrings().matches(dexItemFactory.createType("Lfoobar;")));
+ assertFalse(
+ config.getAdaptClassStrings().matches(dexItemFactory.createType("Lboofoobar;")));
+ // TODO(b/73800755): Use <n> while matching class name list.
+ //assertTrue(
+ // config.getAdaptClassStrings().matches(dexItemFactory.createType("Lboofooboo;")));
+ }
+
+ @Ignore("b/73800755: verify the range of <n>")
+ @Test
+ public void testAdaptClassStringsNthWildcard_outOfRange() throws Exception {
+ Path proguardConfig = writeTextToTempFile(
+ "-adaptclassstrings *foo<2>"
+ );
+ try {
+ ProguardConfigurationParser parser =
+ new ProguardConfigurationParser(new DexItemFactory(), reporter);
+ parser.parse(proguardConfig);
+ fail();
+ } catch (AbortException e) {
+ checkDiagnostic(handler.errors, proguardConfig, 1, 1,
+ "wildcard", "out", "range");
+ }
+ }
+
+ @Test
public void testIdentifierNameString() throws Exception {
ProguardConfigurationParser parser =
new ProguardConfigurationParser(new DexItemFactory(), reporter);
@@ -1173,6 +1209,43 @@
}
@Test
+ public void parse_if_nthWildcard() throws Exception {
+ Path proguardConfig = writeTextToTempFile(
+ "-if class **$R**",
+ "-keep class **$D<2>" // <2> corresponds to the 2nd ** in -if rule.
+ );
+ ProguardConfigurationParser parser =
+ new ProguardConfigurationParser(new DexItemFactory(), reporter);
+ parser.parse(proguardConfig);
+ checkDiagnostic(handler.warnings, proguardConfig, 1, 1,
+ "Ignoring", "-if");
+ ProguardConfiguration config = parser.getConfig();
+ assertEquals(1, config.getRules().size());
+ ProguardIfRule if0 = (ProguardIfRule) config.getRules().get(0);
+ assertEquals("**$R**", if0.getClassNames().toString());
+ assertEquals(ProguardKeepRuleType.KEEP, if0.subsequentRule.getType());
+ assertEquals("**$D<2>", if0.subsequentRule.getClassNames().toString());
+ }
+
+ @Ignore("b/73800755: verify the range of <n>")
+ @Test
+ public void parse_if_nthWildcard_outOfRange() throws Exception {
+ Path proguardConfig = writeTextToTempFile(
+ "-if class **$R**",
+ "-keep class **D<4>" // There are 3 ** in this rule.
+ );
+ try {
+ ProguardConfigurationParser parser =
+ new ProguardConfigurationParser(new DexItemFactory(), reporter);
+ parser.parse(proguardConfig);
+ fail();
+ } catch (AbortException e) {
+ checkDiagnostic(handler.errors, proguardConfig, 1, 1,
+ "wildcard", "out", "range");
+ }
+ }
+
+ @Test
public void parse_if_if() throws Exception {
Path proguardConfig = writeTextToTempFile(
"-if class **$$ModuleAdapter",