Use matcher's description in AnyOf when matcher has no explanation.

PiperOrigin-RevId: 675298308
Change-Id: I32d32cafebc7a63fd03e6d957c3a47043d71e5d9
diff --git a/googlemock/include/gmock/gmock-matchers.h b/googlemock/include/gmock/gmock-matchers.h
index 3daf617..26401d5 100644
--- a/googlemock/include/gmock/gmock-matchers.h
+++ b/googlemock/include/gmock/gmock-matchers.h
@@ -1419,34 +1419,55 @@
 
   bool MatchAndExplain(const T& x,
                        MatchResultListener* listener) const override {
+    // This method uses matcher's explanation when explaining the result.
+    // However, if matcher doesn't provide one, this method uses matcher's
+    // description.
     std::string no_match_result;
-
-    // If either matcher1_ or matcher2_ matches x, we just need to
-    // explain why *one* of them matches.
-    for (size_t i = 0; i < matchers_.size(); ++i) {
+    for (const Matcher<T>& matcher : matchers_) {
       StringMatchResultListener slistener;
-      if (matchers_[i].MatchAndExplain(x, &slistener)) {
-        *listener << slistener.str();
-        return true;
-      } else {
-        if (no_match_result.empty()) {
-          no_match_result = slistener.str();
+      // Return explanation for first match.
+      if (matcher.MatchAndExplain(x, &slistener)) {
+        const std::string explanation = slistener.str();
+        if (!explanation.empty()) {
+          *listener << explanation;
         } else {
-          std::string result = slistener.str();
-          if (!result.empty()) {
-            no_match_result += ", and ";
-            no_match_result += result;
-          }
+          *listener << "which matches (" << Describe(matcher) << ")";
+        }
+        return true;
+      }
+      // Keep track of explanations in case there is no match.
+      std::string explanation = slistener.str();
+      if (explanation.empty()) {
+        explanation = DescribeNegation(matcher);
+      }
+      if (no_match_result.empty()) {
+        no_match_result = explanation;
+      } else {
+        if (!explanation.empty()) {
+          no_match_result += ", and ";
+          no_match_result += explanation;
         }
       }
     }
 
-    // Otherwise we need to explain why *both* of them fail.
     *listener << no_match_result;
     return false;
   }
 
  private:
+  // Returns matcher description as a string.
+  std::string Describe(const Matcher<T>& matcher) const {
+    StringMatchResultListener listener;
+    matcher.DescribeTo(listener.stream());
+    return listener.str();
+  }
+
+  std::string DescribeNegation(const Matcher<T>& matcher) const {
+    StringMatchResultListener listener;
+    matcher.DescribeNegationTo(listener.stream());
+    return listener.str();
+  }
+
   const std::vector<Matcher<T>> matchers_;
 };
 
diff --git a/googlemock/test/gmock-matchers-arithmetic_test.cc b/googlemock/test/gmock-matchers-arithmetic_test.cc
index 6968f55..06b0b47 100644
--- a/googlemock/test/gmock-matchers-arithmetic_test.cc
+++ b/googlemock/test/gmock-matchers-arithmetic_test.cc
@@ -776,45 +776,43 @@
 TEST_P(AnyOfTestP, ExplainsResult) {
   Matcher<int> m;
 
-  // Failed match.  Both matchers need to explain.  The second
-  // matcher doesn't give an explanation, so only the first matcher's
-  // explanation is printed.
+  // Failed match. The second matcher have no explanation (description is used).
   m = AnyOf(GreaterThan(10), Lt(0));
-  EXPECT_EQ("which is 5 less than 10", Explain(m, 5));
+  EXPECT_EQ("which is 5 less than 10, and isn't < 0", Explain(m, 5));
 
-  // Failed match.  Both matchers need to explain.
+  // Failed match. Both matchers have explanations.
   m = AnyOf(GreaterThan(10), GreaterThan(20));
   EXPECT_EQ("which is 5 less than 10, and which is 15 less than 20",
             Explain(m, 5));
 
-  // Failed match.  All matchers need to explain.  The second
-  // matcher doesn't given an explanation.
+  // Failed match. The middle matcher have no explanation.
   m = AnyOf(GreaterThan(10), Gt(20), GreaterThan(30));
-  EXPECT_EQ("which is 5 less than 10, and which is 25 less than 30",
-            Explain(m, 5));
+  EXPECT_EQ(
+      "which is 5 less than 10, and isn't > 20, and which is 25 less than 30",
+      Explain(m, 5));
 
-  // Failed match.  All matchers need to explain.
+  // Failed match. All three matchers have explanations.
   m = AnyOf(GreaterThan(10), GreaterThan(20), GreaterThan(30));
   EXPECT_EQ(
       "which is 5 less than 10, and which is 15 less than 20, "
       "and which is 25 less than 30",
       Explain(m, 5));
 
-  // Successful match.  The first matcher, which succeeded, needs to
-  // explain.
+  // Successful match. The first macher succeeded and has explanation.
   m = AnyOf(GreaterThan(10), GreaterThan(20));
   EXPECT_EQ("which is 5 more than 10", Explain(m, 15));
 
-  // Successful match.  The second matcher, which succeeded, needs to
-  // explain.  Since it doesn't given an explanation, nothing is
-  // printed.
-  m = AnyOf(GreaterThan(10), Lt(30));
-  EXPECT_EQ("", Explain(m, 0));
-
-  // Successful match.  The second matcher, which succeeded, needs to
-  // explain.
+  // Successful match. The second matcher succeeded and has explanation.
   m = AnyOf(GreaterThan(30), GreaterThan(20));
   EXPECT_EQ("which is 5 more than 20", Explain(m, 25));
+
+  // Successful match. The first matcher succeeded and has no explanation.
+  m = AnyOf(Gt(10), Lt(20));
+  EXPECT_EQ("which matches (is > 10)", Explain(m, 15));
+
+  // Successful match. The second matcher succeeded and has no explanation.
+  m = AnyOf(Gt(30), Gt(20));
+  EXPECT_EQ("which matches (is > 20)", Explain(m, 25));
 }
 
 // The following predicate function and predicate functor are for
diff --git a/googlemock/test/gmock-matchers-containers_test.cc b/googlemock/test/gmock-matchers-containers_test.cc
index 52b52d5..751fb60 100644
--- a/googlemock/test/gmock-matchers-containers_test.cc
+++ b/googlemock/test/gmock-matchers-containers_test.cc
@@ -1204,13 +1204,16 @@
   vector<int> container;
   EXPECT_EQ("whose size 0 doesn't match", Explain(m1, container));
   EXPECT_EQ("whose size 0 matches", Explain(m2, container));
-  EXPECT_EQ("whose size 0 matches", Explain(m3, container));
+  EXPECT_EQ("whose size 0 matches, which matches (is equal to 0)",
+            Explain(m3, container));
   EXPECT_EQ("whose size 0 doesn't match", Explain(m4, container));
   container.push_back(0);
   container.push_back(0);
   EXPECT_EQ("whose size 2 matches", Explain(m1, container));
   EXPECT_EQ("whose size 2 doesn't match", Explain(m2, container));
-  EXPECT_EQ("whose size 2 doesn't match", Explain(m3, container));
+  EXPECT_EQ(
+      "whose size 2 doesn't match, isn't equal to 0, and isn't equal to 3",
+      Explain(m3, container));
   EXPECT_EQ("whose size 2 matches", Explain(m4, container));
 }
 
@@ -1475,8 +1478,10 @@
             Explain(m1, container));
   EXPECT_EQ("whose distance between begin() and end() 0 matches",
             Explain(m2, container));
-  EXPECT_EQ("whose distance between begin() and end() 0 matches",
-            Explain(m3, container));
+  EXPECT_EQ(
+      "whose distance between begin() and end() 0 matches, which matches (is "
+      "equal to 0)",
+      Explain(m3, container));
   EXPECT_EQ(
       "whose distance between begin() and end() 0 doesn't match, which is 1 "
       "less than 1",
@@ -1487,8 +1492,10 @@
             Explain(m1, container));
   EXPECT_EQ("whose distance between begin() and end() 2 doesn't match",
             Explain(m2, container));
-  EXPECT_EQ("whose distance between begin() and end() 2 doesn't match",
-            Explain(m3, container));
+  EXPECT_EQ(
+      "whose distance between begin() and end() 2 doesn't match, isn't equal "
+      "to 0, and isn't equal to 3",
+      Explain(m3, container));
   EXPECT_EQ(
       "whose distance between begin() and end() 2 matches, which is 1 more "
       "than 1",
diff --git a/googlemock/test/gmock-matchers-misc_test.cc b/googlemock/test/gmock-matchers-misc_test.cc
index 2bb4cdb..9ac2458 100644
--- a/googlemock/test/gmock-matchers-misc_test.cc
+++ b/googlemock/test/gmock-matchers-misc_test.cc
@@ -1576,10 +1576,10 @@
   const Matcher<int> m1 = AnyOfArray(v1);
   const Matcher<int> m2 = AnyOfArray(v2);
   EXPECT_EQ("", Explain(m0, 0));
-  EXPECT_EQ("", Explain(m1, 1));
-  EXPECT_EQ("", Explain(m1, 2));
-  EXPECT_EQ("", Explain(m2, 3));
-  EXPECT_EQ("", Explain(m2, 4));
+  EXPECT_EQ("which matches (is equal to 1)", Explain(m1, 1));
+  EXPECT_EQ("isn't equal to 1", Explain(m1, 2));
+  EXPECT_EQ("which matches (is equal to 3)", Explain(m2, 3));
+  EXPECT_EQ("isn't equal to 2, and isn't equal to 3", Explain(m2, 4));
   EXPECT_EQ("()", Describe(m0));
   EXPECT_EQ("(is equal to 1)", Describe(m1));
   EXPECT_EQ("(is equal to 2) or (is equal to 3)", Describe(m2));