Revise -dontwarn [class_filter] to use ProguardClassNameList.

Bug: 36799092
Change-Id: Ib700430c35651bb2b9c5ebb810da94d2c90d043d
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index c6fcc22..39e0342 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -31,8 +31,8 @@
 import com.android.tools.r8.shaking.DiscardedChecker;
 import com.android.tools.r8.shaking.Enqueuer;
 import com.android.tools.r8.shaking.MainDexListBuilder;
+import com.android.tools.r8.shaking.ProguardClassNameList;
 import com.android.tools.r8.shaking.ProguardRuleParserException;
-import com.android.tools.r8.shaking.ProguardTypeMatcher;
 import com.android.tools.r8.shaking.ProguardTypeMatcher.MatchSpecificType;
 import com.android.tools.r8.shaking.ReasonPrinter;
 import com.android.tools.r8.shaking.RootSetBuilder;
@@ -153,15 +153,15 @@
   }
 
   private Set<DexType> filterMissingClasses(Set<DexType> missingClasses,
-      Set<ProguardTypeMatcher> dontWarnPatterns) {
+      ProguardClassNameList dontWarnPatterns) {
     Set<DexType> result = new HashSet<>(missingClasses);
-    for (ProguardTypeMatcher matcher : dontWarnPatterns) {
+    dontWarnPatterns.forEachTypeMatcher(matcher -> {
       if (matcher instanceof MatchSpecificType) {
         result.remove(((MatchSpecificType) matcher).type);
       } else {
         result.removeIf(matcher::matches);
       }
-    }
+    });
     return result;
   }
 
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardClassNameList.java b/src/main/java/com/android/tools/r8/shaking/ProguardClassNameList.java
index cd1c5fc..979d238 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardClassNameList.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardClassNameList.java
@@ -12,6 +12,7 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
+import java.util.function.Consumer;
 import java.util.stream.Collectors;
 
 public abstract class ProguardClassNameList {
@@ -20,6 +21,10 @@
     return new Builder();
   }
 
+  public static ProguardClassNameList emptyList() {
+    return new EmptyClassNameList();
+  }
+
   public static ProguardClassNameList singletonList(ProguardTypeMatcher matcher) {
     return new SingleClassNameList(matcher);
   }
@@ -69,6 +74,37 @@
 
   public abstract boolean matches(DexType type);
 
+  public abstract void forEachTypeMatcher(Consumer<ProguardTypeMatcher> consumer);
+
+  private static class EmptyClassNameList extends ProguardClassNameList {
+
+    private EmptyClassNameList() {
+    }
+
+    @Override
+    public int size() {
+      return 0;
+    }
+
+    @Override
+    public void writeTo(StringBuilder builder) {
+    }
+
+    @Override
+    public List<DexType> asSpecificDexTypes() {
+      return null;
+    }
+
+    @Override
+    public boolean matches(DexType type) {
+      return false;
+    }
+
+    @Override
+    public void forEachTypeMatcher(Consumer<ProguardTypeMatcher> consumer) {
+    }
+  }
+
   private static class SingleClassNameList extends ProguardClassNameList {
 
     private final ProguardTypeMatcher className;
@@ -97,6 +133,11 @@
     public boolean matches(DexType type) {
       return className.matches(type);
     }
+
+    @Override
+    public void forEachTypeMatcher(Consumer<ProguardTypeMatcher> consumer) {
+      consumer.accept(className);
+    }
   }
 
   private static class PositiveClassNameList extends ProguardClassNameList {
@@ -137,6 +178,11 @@
     public boolean matches(DexType type) {
       return classNames.stream().anyMatch(name -> name.matches(type));
     }
+
+    @Override
+    public void forEachTypeMatcher(Consumer<ProguardTypeMatcher> consumer) {
+      classNames.forEach(consumer);
+    }
   }
 
   private static class MixedClassNameList extends ProguardClassNameList {
@@ -182,5 +228,10 @@
       }
       return false;
     }
+
+    @Override
+    public void forEachTypeMatcher(Consumer<ProguardTypeMatcher> consumer) {
+      classNames.object2BooleanEntrySet().forEach(entry -> consumer.accept(entry.getKey()));
+    }
   }
 }
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 239f9bc..10daea7 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
@@ -8,12 +8,9 @@
 import com.android.tools.r8.utils.InternalOptions.KeepAttributeOptions;
 import com.android.tools.r8.utils.InternalOptions.PackageObfuscationMode;
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
 import java.nio.file.Path;
 import java.util.ArrayList;
-import java.util.HashSet;
 import java.util.List;
-import java.util.Set;
 
 public class ProguardConfiguration {
 
@@ -36,7 +33,7 @@
     private boolean verbose = false;
     private String renameSourceFileAttribute = null;
     private final List<String> keepAttributePatterns = new ArrayList<>();
-    private final Set<ProguardTypeMatcher> dontWarnPatterns = new HashSet<>();
+    private ProguardClassNameList dontWarnPatterns = ProguardClassNameList.emptyList();
     protected final List<ProguardConfigurationRule> rules = new ArrayList<>();
     private final DexItemFactory dexItemFactory;
     private boolean printSeeds;
@@ -133,8 +130,8 @@
       this.rules.add(rule);
     }
 
-    public void addDontWarnPattern(ProguardTypeMatcher pattern) {
-      dontWarnPatterns.add(pattern);
+    public void setDontWarnPatterns(ProguardClassNameList patterns) {
+      dontWarnPatterns = patterns;
     }
 
     public void setSeedFile(Path seedFile) {
@@ -223,7 +220,7 @@
   private final boolean verbose;
   private final String renameSourceFileAttribute;
   private final ImmutableList<String> keepAttributesPatterns;
-  private final ImmutableSet<ProguardTypeMatcher> dontWarnPatterns;
+  private final ProguardClassNameList dontWarnPatterns;
   protected final ImmutableList<ProguardConfigurationRule> rules;
   private final boolean printSeeds;
   private final Path seedFile;
@@ -252,7 +249,7 @@
       boolean verbose,
       String renameSourceFileAttribute,
       List<String> keepAttributesPatterns,
-      Set<ProguardTypeMatcher> dontWarnPatterns,
+      ProguardClassNameList dontWarnPatterns,
       List<ProguardConfigurationRule> rules,
       boolean printSeeds,
       Path seedFile,
@@ -279,7 +276,7 @@
     this.verbose = verbose;
     this.renameSourceFileAttribute = renameSourceFileAttribute;
     this.keepAttributesPatterns = ImmutableList.copyOf(keepAttributesPatterns);
-    this.dontWarnPatterns = ImmutableSet.copyOf(dontWarnPatterns);
+    this.dontWarnPatterns = dontWarnPatterns;
     this.rules = ImmutableList.copyOf(rules);
     this.printSeeds = printSeeds;
     this.seedFile = seedFile;
@@ -377,7 +374,7 @@
     return keepAttributesPatterns;
   }
 
-  public ImmutableSet<ProguardTypeMatcher> getDontWarnPatterns() {
+  public ProguardClassNameList getDontWarnPatterns() {
     return dontWarnPatterns;
   }
 
@@ -430,7 +427,7 @@
           false                 /* verbose */,
           null                  /* renameSourceFileAttribute */,
           KeepAttributeOptions.KEEP_ALL,
-          ImmutableSet.of()     /* dontWarnPatterns */,
+          ProguardClassNameList.emptyList(),
           ImmutableList.of(ProguardKeepRule.defaultKeepAllRule()),
           false                 /* printSeeds */,
           null                  /* seedFile */,
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 08a7eca..70bad56 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
@@ -198,11 +198,12 @@
       } else if (acceptString("ignorewarnings")) {
         configurationBuilder.setIgnoreWarnings(true);
       } else if (acceptString("dontwarn")) {
-        do {
-          ProguardTypeMatcher pattern = ProguardTypeMatcher.create(parseClassName(),
-              ClassOrType.CLASS, dexItemFactory);
-          configurationBuilder.addDontWarnPattern(pattern);
-        } while (acceptChar(','));
+        if (isOptionalArgumentGiven()) {
+          configurationBuilder.setDontWarnPatterns(parseClassNames());
+        } else {
+          configurationBuilder.setDontWarnPatterns(
+              ProguardClassNameList.singletonList(ProguardTypeMatcher.defaultAllMatcher()));
+        }
       } else if (acceptString("repackageclasses")) {
         if (configurationBuilder.getPackageObfuscationMode() == PackageObfuscationMode.FLATTEN) {
           warnOverridingOptions("repackageclasses", "flattenpackagehierarchy");
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 3f44025..c0121db 100644
--- a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
@@ -145,6 +145,51 @@
   }
 
   @Test
+  public void testDontWarn() throws Exception {
+    DexItemFactory dexItemFactory = new DexItemFactory();
+    ProguardConfigurationParser parser = new ProguardConfigurationParser(dexItemFactory);
+    String dontwarn = "-dontwarn !foobar,*bar";
+    parser.parse(new ProguardConfigurationSourceStrings(ImmutableList.of(dontwarn)));
+    ProguardConfiguration config = parser.getConfig();
+    assertFalse(
+        config.getDontWarnPatterns().matches(dexItemFactory.createType("Lboobaz;")));
+    assertTrue(
+        config.getDontWarnPatterns().matches(dexItemFactory.createType("Lboobar;")));
+    assertFalse(
+        config.getDontWarnPatterns().matches(dexItemFactory.createType("Lfoobar;")));
+  }
+
+  @Test
+  public void testDontWarnAllExplicitly() throws Exception {
+    DexItemFactory dexItemFactory = new DexItemFactory();
+    ProguardConfigurationParser parser = new ProguardConfigurationParser(dexItemFactory);
+    String dontwarnAll = "-dontwarn *";
+    parser.parse(new ProguardConfigurationSourceStrings(ImmutableList.of(dontwarnAll)));
+    ProguardConfiguration config = parser.getConfig();
+    assertTrue(
+        config.getDontWarnPatterns().matches(dexItemFactory.createType("Lboobaz;")));
+    assertTrue(
+        config.getDontWarnPatterns().matches(dexItemFactory.createType("Lboobar;")));
+    assertTrue(
+        config.getDontWarnPatterns().matches(dexItemFactory.createType("Lfoobar;")));
+  }
+
+  @Test
+  public void testDontWarnAllImplicitly() throws Exception {
+    DexItemFactory dexItemFactory = new DexItemFactory();
+    ProguardConfigurationParser parser = new ProguardConfigurationParser(dexItemFactory);
+    String dontwarnAll = "-dontwarn";
+    parser.parse(new ProguardConfigurationSourceStrings(ImmutableList.of(dontwarnAll)));
+    ProguardConfiguration config = parser.getConfig();
+    assertTrue(
+        config.getDontWarnPatterns().matches(dexItemFactory.createType("Lboobaz;")));
+    assertTrue(
+        config.getDontWarnPatterns().matches(dexItemFactory.createType("Lboobar;")));
+    assertTrue(
+        config.getDontWarnPatterns().matches(dexItemFactory.createType("Lfoobar;")));
+  }
+
+  @Test
   public void parseAccessFlags() throws IOException, ProguardRuleParserException {
     ProguardConfigurationParser parser = new ProguardConfigurationParser(new DexItemFactory());
     parser.parse(Paths.get(ACCESS_FLAGS_FILE));
diff --git a/src/test/java/com/android/tools/r8/shaking/ProguardNameMatchingTest.java b/src/test/java/com/android/tools/r8/shaking/ProguardNameMatchingTest.java
index af87086..2737971 100644
--- a/src/test/java/com/android/tools/r8/shaking/ProguardNameMatchingTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ProguardNameMatchingTest.java
@@ -62,6 +62,9 @@
     assertTrue(matchClassName("java.lang.Object", "!java.util.**", "java**"));
     assertFalse(matchClassName("java.lang.Object", "!java.**", "java.lang.*"));
     assertTrue(matchClassName("java.lang.Object", "java.lang.*", "!java.**"));
+
+    assertTrue(matchClassName("boobar", "!foobar", "*bar"));
+    assertFalse(matchClassName("foobar", "!foobar", "*bar"));
   }
 
   private void assertMatchesBasicTypes(String pattern) {