Merge "Refactor code to make predicates negatable"
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());