Merge changes from topic 'conflicts-with-merge' into stable-2.11

* changes:
  Fix "Conflicts With" when current change is a merge commit
  Fix "Conflicts With" when other change is a merge-commit
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..e356f64 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
@@ -42,8 +42,12 @@
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.revwalk.RevFlag;
 import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.revwalk.filter.RevFilter;
+import org.eclipse.jgit.treewalk.TreeWalk;
+import org.eclipse.jgit.treewalk.filter.TreeFilter;
 
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
 
@@ -64,8 +68,7 @@
     for (final Change c : changes) {
       final ChangeDataCache changeDataCache = new ChangeDataCache(
           c, db, args.changeDataFactory, args.projectCache);
-      List<String> files = args.changeDataFactory.create(db.get(), c)
-          .currentFilePaths();
+      List<String> files = listFiles(c, args, changeDataCache);
       List<Predicate<ChangeData>> filePredicates =
           Lists.newArrayListWithCapacity(files.size());
       for (String file : files) {
@@ -81,7 +84,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) {
 
@@ -171,6 +199,42 @@
     return changePredicates;
   }
 
+  private static List<String> listFiles(Change c, Arguments args,
+      ChangeDataCache changeDataCache) throws OrmException {
+    try (Repository repo = args.repoManager.openRepository(c.getProject());
+        RevWalk rw = new RevWalk(repo)) {
+      RevCommit ps = rw.parseCommit(changeDataCache.getTestAgainst());
+      if (ps.getParentCount() > 1) {
+        String dest = c.getDest().get();
+        Ref destBranch = repo.getRefDatabase().getRef(dest);
+        destBranch.getObjectId();
+        rw.setRevFilter(RevFilter.MERGE_BASE);
+        rw.markStart(rw.parseCommit(destBranch.getObjectId()));
+        rw.markStart(ps);
+        RevCommit base = rw.next();
+        // TODO(zivkov): handle the case with multiple merge bases
+
+        List<String> files = new ArrayList<>();
+        try (TreeWalk tw = new TreeWalk(repo)) {
+          if (base != null) {
+            tw.setFilter(TreeFilter.ANY_DIFF);
+            tw.addTree(base.getTree());
+          }
+          tw.addTree(ps.getTree());
+          tw.setRecursive(true);
+          while (tw.next()) {
+            files.add(tw.getPathString());
+          }
+        }
+        return files;
+      } else {
+        return args.changeDataFactory.create(args.db.get(), c).currentFilePaths();
+      }
+    } catch (IOException e) {
+      throw new OrmException(e);
+    }
+  }
+
   @Override
   public String toString() {
     return ChangeQueryBuilder.FIELD_CONFLICTS + ":" + value;