Merge "Fix FilteredClassPathTest on windows."
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index ab9155b..e237cf6 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -455,9 +455,7 @@
     internal.useDiscardedChecker = useDiscardedChecker();
     assert !internal.ignoreMissingClasses;
     internal.ignoreMissingClasses = ignoreMissingClasses;
-    for (String pattern : proguardConfiguration.getAttributesRemovalPatterns()) {
-      internal.attributeRemoval.applyPattern(pattern);
-    }
+    internal.attributeRemoval.applyPatterns(proguardConfiguration.getAttributesRemovalPatterns());
     internal.ignoreMissingClasses |= proguardConfiguration.isIgnoreWarnings();
     assert !internal.verbose;
     internal.verbose |= proguardConfiguration.isVerbose();
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 05fb09c..d0c5478 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
@@ -113,8 +113,8 @@
       this.verbose = verbose;
     }
 
-    public void addAttributeRemovalPattern(String attributesRemovalPattern) {
-      this.attributesRemovalPatterns.add(attributesRemovalPattern);
+    public void addAttributeRemovalPatterns(List<String> attributesRemovalPatterns) {
+      this.attributesRemovalPatterns.addAll(attributesRemovalPatterns);
     }
 
     public void addRule(ProguardConfigurationRule rule) {
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 a61017c..cc1120c 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
@@ -289,11 +289,11 @@
     }
 
     private void parseKeepAttributes() throws ProguardRuleParserException {
-      String attributesPattern = acceptPatternList();
-      if (attributesPattern == null) {
+      List<String> attributesPatterns = acceptPatternList();
+      if (attributesPatterns.isEmpty()) {
         throw parseError("Expected attribute pattern list");
       }
-      configurationBuilder.addAttributeRemovalPattern(attributesPattern);
+      configurationBuilder.addAttributeRemovalPatterns(attributesPatterns);
     }
 
     private boolean skipFlag(String name) {
@@ -1006,7 +1006,25 @@
       return contents.substring(start, end);
     }
 
-    private String acceptPatternList() {
+    private List<String> acceptPatternList() throws ProguardRuleParserException {
+      List<String> patterns = new ArrayList<>();
+      String pattern = acceptPattern();
+      while (pattern != null) {
+        patterns.add(pattern);
+        skipWhitespace();
+        if (acceptChar(',')) {
+          pattern = acceptPattern();
+          if (pattern == null) {
+            throw parseError("Expected list element");
+          }
+        } else {
+          pattern = null;
+        }
+      }
+      return patterns;
+    }
+
+    private String acceptPattern() {
       skipWhitespace();
       int start = position;
       int end = position;
@@ -1014,8 +1032,7 @@
         char current = contents.charAt(end);
         if (Character.isJavaIdentifierPart(current) ||
             current == '!' ||
-            current == '*' ||
-            current == ',') {
+            current == '*') {
           end++;
         } else {
           break;
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index e98ecb9..95762e4 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -243,7 +243,7 @@
 
     public static AttributeRemovalOptions filterOnlySignatures() {
       AttributeRemovalOptions result = new AttributeRemovalOptions();
-      result.applyPattern("*");
+      result.applyPatterns(ImmutableList.of("*"));
       result.signature = false;
       return result;
     }
@@ -253,7 +253,7 @@
      *
      * @see <a href="https://www.guardsquare.com/en/proguard/manual/attributes">ProGuard manual</a>.
      */
-    private boolean update(boolean previous, String text, String[] patterns) {
+    private boolean update(boolean previous, String text, List<String> patterns) {
       for (String pattern : patterns) {
         if (previous) {
           return true;
@@ -289,8 +289,7 @@
       return textPos == text.length();
     }
 
-    public void applyPattern(String pattern) {
-      String[] patterns = pattern.split(",");
+    public void applyPatterns(List<String> patterns) {
       innerClasses = update(innerClasses, INNER_CLASSES, patterns);
       enclosingMethod = update(enclosingMethod, ENCLOSING_METHOD, patterns);
       signature = update(signature, SIGNATURE, patterns);
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 c96d603..a47ee57 100644
--- a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
@@ -16,6 +16,7 @@
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.utils.FileUtils;
 import com.android.tools.r8.utils.InternalOptions.PackageObfuscationMode;
+import com.google.common.collect.ImmutableList;
 import java.io.IOException;
 import java.nio.file.Path;
 import java.nio.file.Paths;
@@ -587,4 +588,37 @@
     );
     parser.parse(proguardConfig);
   }
+
+  private void testKeepattributes(List<String> expected, String config) throws Exception {
+    ProguardConfigurationParser parser = new ProguardConfigurationParser(new DexItemFactory());
+    parser.parse(new ProguardConfigurationSourceStrings(ImmutableList.of(config)));
+    assertEquals(expected, parser.getConfig().getAttributesRemovalPatterns());
+  }
+
+  @Test
+  public void parseKeepattributes() throws Exception {
+    List<String> xxxYYY = ImmutableList.of("xxx", "yyy");
+    testKeepattributes(xxxYYY, "-keepattributes xxx,yyy");
+    testKeepattributes(xxxYYY, "-keepattributes xxx, yyy");
+    testKeepattributes(xxxYYY, "-keepattributes xxx ,yyy");
+    testKeepattributes(xxxYYY, "-keepattributes xxx   ,   yyy");
+    testKeepattributes(xxxYYY, "-keepattributes       xxx   ,   yyy     ");
+    testKeepattributes(xxxYYY, "-keepattributes       xxx   ,   yyy     \n");
+    String config = "-keepattributes Exceptions,InnerClasses,Signature,Deprecated,\n" +
+                    "                SourceFile,LineNumberTable,*Annotation*,EnclosingMethod\n";
+    List<String> expected = ImmutableList.of("Exceptions", "InnerClasses", "Signature", "Deprecated",
+        "SourceFile", "LineNumberTable", "*Annotation*", "EnclosingMethod");
+    testKeepattributes(expected, config);
+  }
+
+  @Test
+  public void parseInvalidKeepattributes() throws Exception {
+    try {
+      ProguardConfigurationParser parser = new ProguardConfigurationParser(new DexItemFactory());
+      parser.parse(new ProguardConfigurationSourceStrings(ImmutableList.of("-keepattributes xxx,")));
+      fail();
+    } catch (ProguardRuleParserException e) {
+      assertTrue(e.getMessage().contains("Expected list element at "));
+    }
+  }
 }