Merge "Add the ability to specify packages or classes to ignore for ApiCheck." into lmp-mr1-app-dev
diff --git a/src/com/google/doclava/PackageInfo.java b/src/com/google/doclava/PackageInfo.java
index 02beaf7..c0f10da 100644
--- a/src/com/google/doclava/PackageInfo.java
+++ b/src/com/google/doclava/PackageInfo.java
@@ -394,9 +394,15 @@
     return mClasses;
   }
 
-  public boolean isConsistent(PackageInfo pInfo) {
+  public boolean isConsistent(PackageInfo pInfo, Collection<String> ignoredClasses) {
     boolean consistent = true;
     for (ClassInfo cInfo : mClasses.values()) {
+      // TODO: Add support for matching inner classes (e.g, something like
+      //  example.Type.* should match example.Type.InnerType)
+      if (ignoredClasses != null && ignoredClasses.contains(cInfo.qualifiedName())) {
+          // TODO: Log skipping this?
+          continue;
+      }
       if (pInfo.mClasses.containsKey(cInfo.name())) {
         if (!cInfo.isConsistent(pInfo.mClasses.get(cInfo.name()))) {
           consistent = false;
@@ -408,6 +414,10 @@
       }
     }
     for (ClassInfo cInfo : pInfo.mClasses.values()) {
+      if (ignoredClasses != null && ignoredClasses.contains(cInfo.qualifiedName())) {
+          // TODO: Log skipping this?
+          continue;
+      }
       if (!mClasses.containsKey(cInfo.name())) {
         Errors.error(Errors.ADDED_CLASS, cInfo.position(), "Added class " + cInfo.name()
             + " to package " + pInfo.name());
@@ -416,4 +426,8 @@
     }
     return consistent;
   }
+
+  public boolean isConsistent(PackageInfo pInfo) {
+    return isConsistent(pInfo, null);
+  }
 }
diff --git a/src/com/google/doclava/apicheck/ApiCheck.java b/src/com/google/doclava/apicheck/ApiCheck.java
index 28d7ce0..9698c89 100644
--- a/src/com/google/doclava/apicheck/ApiCheck.java
+++ b/src/com/google/doclava/apicheck/ApiCheck.java
@@ -23,6 +23,7 @@
 import java.io.PrintStream;
 import java.net.URL;
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.Set;
 import java.util.Stack;
 
@@ -39,7 +40,8 @@
     for (i = 0; i < allArgs.size(); i++) {
       // flags with one value attached
       String flag = allArgs.get(i);
-      if (flag.equals("-error") || flag.equals("-warning") || flag.equals("-hide")) {
+      if (flag.equals("-error") || flag.equals("-warning") || flag.equals("-hide")
+          || flag.equals("-ignoreClass") || flag.equals("-ignorePackage")) {
         String[] arg = new String[2];
         arg[0] = flag;
         arg[1] = allArgs.get(++i);
@@ -81,6 +83,11 @@
       args.add(a);
     }
 
+    // Not having having any classes or packages ignored is the common case.
+    // Avoid a hashCode call in a common loop by not passing in a HashSet in this case.
+    Set<String> ignoredPackages = null;
+    Set<String> ignoredClasses = null;
+
     ArrayList<String[]> flags = ApiCheck.parseFlags(args);
     for (String[] a : flags) {
       if (a[0].equals("-error") || a[0].equals("-warning") || a[0].equals("-hide")) {
@@ -98,6 +105,16 @@
           System.err.println("Bad argument: " + a[0] + " " + a[1]);
           return new Report(2, Errors.getErrors());
         }
+      } else if (a[0].equals("-ignoreClass")) {
+        if (ignoredClasses == null) {
+          ignoredClasses = new HashSet<String>();
+        }
+        ignoredClasses.add(a[1]);
+      } else if (a[0].equals("-ignorePackage")) {
+        if (ignoredPackages == null) {
+          ignoredPackages = new HashSet<String>();
+        }
+        ignoredPackages.add(a[1]);
       }
     }
 
@@ -121,11 +138,11 @@
 
     // only run the consistency check if we haven't had XML parse errors
     if (!Errors.hadError) {
-      oldApi.isConsistent(newApi);
+      oldApi.isConsistent(newApi, ignoredPackages, ignoredClasses);
     }
 
     if (!Errors.hadError) {
-      oldRemovedApi.isConsistent(newRemovedApi);
+      oldRemovedApi.isConsistent(newRemovedApi, ignoredPackages, ignoredClasses);
     }
 
     return new Report(Errors.hadError ? 1 : 0, Errors.getErrors());
diff --git a/src/com/google/doclava/apicheck/ApiInfo.java b/src/com/google/doclava/apicheck/ApiInfo.java
index 711a9f4..2752f3a 100644
--- a/src/com/google/doclava/apicheck/ApiInfo.java
+++ b/src/com/google/doclava/apicheck/ApiInfo.java
@@ -20,6 +20,7 @@
 import com.google.doclava.Errors;
 import com.google.doclava.PackageInfo;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -58,12 +59,25 @@
 
   /**
    * Checks to see if this api is consistent with a newer version.
+   *
+   * @param otherApi the other api to test consistency against
+   * @param ignoredPackages packages to skip consistency checks (will match by exact name)
+   * @param ignoredClasses classes to skip consistency checks (will match by exact fully qualified
+   * name)
    */
-  public boolean isConsistent(ApiInfo otherApi) {
+  public boolean isConsistent(ApiInfo otherApi,
+      Collection<String> ignoredPackages, Collection<String> ignoredClasses) {
     boolean consistent = true;
     for (PackageInfo pInfo : mPackages.values()) {
+      // TODO: Add support for matching subpackages (e.g, something like
+      // test.example.* should match test.example.subpackage, and
+      // test.example.** should match the above AND test.example.subpackage.more)
+      if (ignoredPackages != null && ignoredPackages.contains(pInfo.name())) {
+          // TODO: Log skipping this?
+          continue;
+      }
       if (otherApi.getPackages().containsKey(pInfo.name())) {
-        if (!pInfo.isConsistent(otherApi.getPackages().get(pInfo.name()))) {
+        if (!pInfo.isConsistent(otherApi.getPackages().get(pInfo.name()), ignoredClasses)) {
           consistent = false;
         }
       } else {
@@ -72,6 +86,10 @@
       }
     }
     for (PackageInfo pInfo : otherApi.mPackages.values()) {
+      if (ignoredPackages != null && ignoredPackages.contains(pInfo.name())) {
+          // TODO: Log skipping this?
+          continue;
+      }
       if (!mPackages.containsKey(pInfo.name())) {
         Errors.error(Errors.ADDED_PACKAGE, pInfo.position(), "Added package " + pInfo.name());
         consistent = false;
@@ -80,6 +98,13 @@
     return consistent;
   }
 
+  /**
+   * Checks to see if this api is consistent with a newer version.
+   */
+  public boolean isConsistent(ApiInfo otherApi) {
+    return isConsistent(otherApi, null, null);
+  }
+
   public HashMap<String, PackageInfo> getPackages() {
     return mPackages;
   }