Allow RTC_LOG and RTC_CHECK to accept types that implements absl stringify

Bug: None
Change-Id: If99eb0e3e285c13d81cd2bbb56163c2c2311d43a
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/364201
Commit-Queue: Danil Chapovalov <danilchap@webrtc.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#43119}
diff --git a/rtc_base/BUILD.gn b/rtc_base/BUILD.gn
index e1282d7..fc2fc09 100644
--- a/rtc_base/BUILD.gn
+++ b/rtc_base/BUILD.gn
@@ -441,6 +441,7 @@
     "synchronization:mutex",
     "//third_party/abseil-cpp/absl/base:core_headers",
     "//third_party/abseil-cpp/absl/meta:type_traits",
+    "//third_party/abseil-cpp/absl/strings",
     "//third_party/abseil-cpp/absl/strings:string_view",
   ]
 
@@ -489,6 +490,7 @@
     "system:inline",
     "system:rtc_export",
     "//third_party/abseil-cpp/absl/meta:type_traits",
+    "//third_party/abseil-cpp/absl/strings",
     "//third_party/abseil-cpp/absl/strings:string_view",
   ]
   if (build_with_chromium) {
diff --git a/rtc_base/DEPS b/rtc_base/DEPS
index 17d6cf6..b5aacb1 100644
--- a/rtc_base/DEPS
+++ b/rtc_base/DEPS
@@ -6,6 +6,10 @@
 ]
 
 specific_include_rules = {
+  "checks.h": [
+    "+absl/strings/has_absl_stringify.h",
+    "+absl/strings/str_cat.h",
+  ],
   "protobuf_utils.h": [
     "+third_party/protobuf",
   ],
@@ -18,6 +22,10 @@
   "event_tracer\.cc": [
     "+third_party/perfetto",
   ],
+  "logging.h": [
+    "+absl/strings/has_absl_stringify.h",
+    "+absl/strings/str_cat.h",
+  ],
   "trace_event\.h": [
     "+third_party/perfetto",
   ],
diff --git a/rtc_base/checks.h b/rtc_base/checks.h
index 99fee97..130b8b9 100644
--- a/rtc_base/checks.h
+++ b/rtc_base/checks.h
@@ -55,6 +55,8 @@
 #include <string>
 
 #include "absl/meta/type_traits.h"
+#include "absl/strings/has_absl_stringify.h"
+#include "absl/strings/str_cat.h"
 #include "absl/strings/string_view.h"
 #include "api/scoped_refptr.h"
 #include "rtc_base/numerics/safe_compare.h"
@@ -220,6 +222,12 @@
   return {ToLogString(x)};
 }
 
+template <typename T,
+          std::enable_if_t<absl::HasAbslStringify<T>::value>* = nullptr>
+ToStringVal MakeVal(const T& x) {
+  return {absl::StrCat(x)};
+}
+
 // Ephemeral type that represents the result of the logging << operator.
 template <typename... Ts>
 class LogStreamer;
diff --git a/rtc_base/checks_unittest.cc b/rtc_base/checks_unittest.cc
index 95deba9..4a3dfa4 100644
--- a/rtc_base/checks_unittest.cc
+++ b/rtc_base/checks_unittest.cc
@@ -10,8 +10,14 @@
 
 #include "rtc_base/checks.h"
 
+#include "test/gmock.h"
 #include "test/gtest.h"
 
+namespace {
+
+using ::testing::HasSubstr;
+using ::testing::Not;
+
 TEST(ChecksTest, ExpressionNotEvaluatedWhenCheckPassing) {
   int i = 0;
   RTC_CHECK(true) << "i=" << ++i;
@@ -19,6 +25,14 @@
 }
 
 #if GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
+
+struct StructWithStringfy {
+  template <typename Sink>
+  friend void AbslStringify(Sink& sink, const StructWithStringfy& /*self*/) {
+    sink.Append("absl-stringify");
+  }
+};
+
 TEST(ChecksDeathTest, Checks) {
 #if RTC_CHECK_MSG_ENABLED
   EXPECT_DEATH(RTC_FATAL() << "message",
@@ -44,6 +58,9 @@
                "# last system error: \\w+\n"
                "# Check failed: false\n"
                "# Hi there!");
+
+  StructWithStringfy t;
+  EXPECT_DEATH(RTC_CHECK(false) << t, HasSubstr("absl-stringify"));
 #else
   EXPECT_DEATH(RTC_FATAL() << "message",
                "\n\n#\n"
@@ -68,6 +85,12 @@
                "# last system error: \\w+\n"
                "# Check failed.\n"
                "# ");
+
+  // Should compile, but shouldn't try to stringify 't'
+  StructWithStringfy t;
+  EXPECT_DEATH(RTC_CHECK(false) << t, Not(HasSubstr("absl-stringify")));
 #endif  // RTC_CHECK_MSG_ENABLED
 }
 #endif  // GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
+
+}  // namespace
diff --git a/rtc_base/logging.h b/rtc_base/logging.h
index 165a83b..acff13b 100644
--- a/rtc_base/logging.h
+++ b/rtc_base/logging.h
@@ -59,6 +59,8 @@
 
 #include "absl/base/attributes.h"
 #include "absl/meta/type_traits.h"
+#include "absl/strings/has_absl_stringify.h"
+#include "absl/strings/str_cat.h"
 #include "absl/strings/string_view.h"
 #include "api/units/timestamp.h"
 #include "rtc_base/platform_thread_types.h"
@@ -340,20 +342,26 @@
   return {ToLogString(x)};
 }
 
+template <typename T,
+          std::enable_if_t<absl::HasAbslStringify<T>::value>* = nullptr>
+ToStringVal MakeVal(const T& x) {
+  return {absl::StrCat(x)};
+}
+
 // Handle arbitrary types other than the above by falling back to stringstream.
 // TODO(bugs.webrtc.org/9278): Get rid of this overload when callers don't need
 // it anymore. No in-tree caller does, but some external callers still do.
-template <
-    typename T,
-    typename T1 = absl::decay_t<T>,
-    absl::enable_if_t<std::is_class<T1>::value &&
-                      !std::is_same<T1, std::string>::value &&
-                      !std::is_same<T1, LogMetadata>::value &&
-                      !has_to_log_string<T1>::value &&
+template <typename T,
+          typename T1 = absl::decay_t<T>,
+          std::enable_if_t<std::is_class<T1>::value &&               //
+                           !std::is_same<T1, std::string>::value &&  //
+                           !std::is_same<T1, LogMetadata>::value &&  //
+                           !has_to_log_string<T1>::value &&          //
+                           !absl::HasAbslStringify<T1>::value &&
 #ifdef WEBRTC_ANDROID
-                      !std::is_same<T1, LogMetadataTag>::value &&
+                           !std::is_same<T1, LogMetadataTag>::value &&  //
 #endif
-                      !std::is_same<T1, LogMetadataErr>::value>* = nullptr>
+                           !std::is_same<T1, LogMetadataErr>::value>* = nullptr>
 ToStringVal MakeVal(const T& x) {
   std::ostringstream os;  // no-presubmit-check TODO(webrtc:8982)
   os << x;
diff --git a/rtc_base/logging_unittest.cc b/rtc_base/logging_unittest.cc
index b05907e..9e6f297 100644
--- a/rtc_base/logging_unittest.cc
+++ b/rtc_base/logging_unittest.cc
@@ -29,6 +29,8 @@
 
 namespace {
 
+using ::testing::HasSubstr;
+
 #if defined(WEBRTC_WIN)
 constexpr char kFakeFilePath[] = "some\\path\\myfile.cc";
 #else
@@ -367,6 +369,26 @@
   EXPECT_FALSE(was_called);
 }
 
+struct StructWithStringfy {
+  template <typename Sink>
+  friend void AbslStringify(Sink& sink, const StructWithStringfy& /*self*/) {
+    sink.Append("absl-stringify");
+  }
+};
+
+TEST(LogTest, UseAbslStringForCustomTypes) {
+  std::string str;
+  LogSinkImpl stream(&str);
+  LogMessage::AddLogToStream(&stream, LS_INFO);
+  StructWithStringfy t;
+
+  RTC_LOG(LS_INFO) << t;
+
+  EXPECT_THAT(str, HasSubstr("absl-stringify"));
+
+  LogMessage::RemoveLogToStream(&stream);
+}
+
 struct TestStruct {};
 std::string ToLogString(TestStruct foo) {
   return "bar";