Fix "Conflicts With" when other change is a merge-commit

The "Conflicts With" list often didn't consider the merge-commit changes
because the list of changed files for a merge commit consists of only
those files which had a conflict during that merge and we only
considered those changes with overlapping file-set as potential conflict
candidates.

Check for all open merge-commit changes if they will conflict with the
current change. This fix is reasonable as the number of merge-commits in
review is usually low.

Note that this only fixes the case when a candidate for the "Conflicts
With" list is a merge commit. The case when the current change, on which
the "Conflicts With" is computed, is a merge commit requires a different
fix.

Bug: issue 3052
Change-Id: I137497fe1bbe262406e693cfd5fdec2ad4a67722
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
index c9d7e6c..250b1f295 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
@@ -99,6 +99,7 @@
   public static final String FIELD_HASHTAG = "hashtag";
   public static final String FIELD_LABEL = "label";
   public static final String FIELD_LIMIT = "limit";
+  public static final String FIELD_MERGE = "merge";
   public static final String FIELD_MERGEABLE = "mergeable";
   public static final String FIELD_MESSAGE = "message";
   public static final String FIELD_OWNER = "owner";
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ConflictsPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ConflictsPredicate.java
index 2070746..95d0422 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ConflictsPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ConflictsPredicate.java
@@ -81,7 +81,32 @@
           new ProjectPredicate(c.getProject().get()));
       predicatesForOneChange.add(
           new RefPredicate(c.getDest().get()));
-      predicatesForOneChange.add(or(filePredicates));
+
+      OperatorPredicate<ChangeData> isMerge = new OperatorPredicate<ChangeData>(
+              ChangeQueryBuilder.FIELD_MERGE, value) {
+
+        @Override
+        public boolean match(ChangeData cd) throws OrmException {
+          ObjectId id = ObjectId.fromString(
+              cd.currentPatchSet().getRevision().get());
+          try (Repository repo =
+                args.repoManager.openRepository(cd.change().getProject());
+              RevWalk rw = CodeReviewCommit.newRevWalk(repo)) {
+            RevCommit commit = rw.parseCommit(id);
+            return commit.getParentCount() > 1;
+          } catch (IOException e) {
+            throw new IllegalStateException(e);
+          }
+        }
+
+        @Override
+        public int getCost() {
+          return 2;
+        }
+      };
+
+      predicatesForOneChange.add(or(or(filePredicates), isMerge));
+
       predicatesForOneChange.add(new OperatorPredicate<ChangeData>(
           ChangeQueryBuilder.FIELD_CONFLICTS, value) {