Refactor code to make predicates negatable

Previous refactoring of the stubs generator moved most of the API
membership logic into Predicate classes. Bits of the method filtering
logic, however, remained hard-coded in the API printer. This prevents
usage of more complicated predicates, namely predicates filtering
members that are *not* present in the public API. This patch refactors
the code further to enable these use cases.

Test: dbrazdil@ checked that generated files have not changed
Change-Id: I8f329de5154d2e16614361990f7615cb5f80ea9e
diff --git a/src/com/google/doclava/Stubs.java b/src/com/google/doclava/Stubs.java
index 30d0f88..a6d2039 100644
--- a/src/com/google/doclava/Stubs.java
+++ b/src/com/google/doclava/Stubs.java
@@ -217,11 +217,18 @@
 
     final boolean ignoreShown = Doclava.showUnannotated;
 
+    FilterPredicate apiFilter = new FilterPredicate(new ApiPredicate().setIgnoreShown(ignoreShown));
+    ApiPredicate apiReference = new ApiPredicate().setIgnoreShown(true);
+    Predicate<MemberInfo> apiEmit = apiFilter.and(new ElidingPredicate(apiReference));
+
+    FilterPredicate removedFilter =
+        new FilterPredicate(new ApiPredicate().setIgnoreShown(ignoreShown).setMatchRemoved(true));
+    ApiPredicate removedReference = new ApiPredicate().setIgnoreShown(true).setIgnoreRemoved(true);
+    Predicate<MemberInfo> removedEmit = removedFilter.and(new ElidingPredicate(removedReference));
+
     // Write out the current API
     if (apiWriter != null) {
-      writeApi(apiWriter, packages,
-          new ApiPredicate().setIgnoreShown(ignoreShown),
-          new ApiPredicate().setIgnoreShown(true));
+      writeApi(apiWriter, packages, apiEmit, apiReference);
       apiWriter.close();
     }
 
@@ -239,9 +246,7 @@
               || stubPackages.contains(ci.containingPackage().qualifiedName()))
           .collect(Collectors.groupingBy(ClassInfo::containingPackage));
 
-      writeApi(removedApiWriter, allClassesByPackage,
-          new ApiPredicate().setIgnoreShown(ignoreShown).setMatchRemoved(true),
-          new ApiPredicate().setIgnoreShown(true).setIgnoreRemoved(true));
+      writeApi(removedApiWriter, allClassesByPackage, removedEmit, removedReference);
       removedApiWriter.close();
     }
   }
@@ -1304,17 +1309,39 @@
       // override then we can elide it.
       if (member instanceof MethodInfo) {
         MethodInfo method = (MethodInfo) member;
-        String methodRaw = writeMethodApiWithoutDefault(method);
-        return (method.findPredicateOverriddenMethod(new Predicate<MemberInfo>() {
-          @Override
-          public boolean test(MemberInfo test) {
-            // We're looking for included and perfect signature
-            return (wrapped.test(test)
-                && writeMethodApiWithoutDefault((MethodInfo) test).equals(methodRaw));
-          }
-        }) == null);
-      } else {
+        if (method.returnType() != null) {  // not a constructor
+          String methodRaw = writeMethodApiWithoutDefault(method);
+          return (method.findPredicateOverriddenMethod(new Predicate<MemberInfo>() {
+            @Override
+            public boolean test(MemberInfo test) {
+              // We're looking for included and perfect signature
+              return (wrapped.test(test)
+                  && writeMethodApiWithoutDefault((MethodInfo) test).equals(methodRaw));
+            }
+          }) == null);
+        }
+      }
+      return true;
+    }
+  }
+
+  public static class FilterPredicate implements Predicate<MemberInfo> {
+    private final Predicate<MemberInfo> wrapped;
+
+    public FilterPredicate(Predicate<MemberInfo> wrapped) {
+      this.wrapped = wrapped;
+    }
+
+    @Override
+    public boolean test(MemberInfo member) {
+      if (wrapped.test(member)) {
         return true;
+      } else if (member instanceof MethodInfo) {
+        MethodInfo method = (MethodInfo) member;
+        return method.returnType() != null &&  // not a constructor
+               method.findPredicateOverriddenMethod(wrapped) != null;
+      } else {
+        return false;
       }
     }
   }
@@ -1347,8 +1374,7 @@
 
     List<MethodInfo> constructors = cl.getExhaustiveConstructors().stream().filter(filterEmit)
         .sorted(MethodInfo.comparator).collect(Collectors.toList());
-    List<MethodInfo> methods = cl.filteredMethods(filterEmit).stream()
-        .filter(new ElidingPredicate(filterReference))
+    List<MethodInfo> methods = cl.getExhaustiveMethods().stream().filter(filterEmit)
         .sorted(MethodInfo.comparator).collect(Collectors.toList());
     List<FieldInfo> enums = cl.getExhaustiveEnumConstants().stream().filter(filterEmit)
         .sorted(FieldInfo.comparator).collect(Collectors.toList());