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",