Make ExpectationToString generate detailed logs in more cases.

ExpectationToString is used to explain why RTC_DCHECK_RUN_ON is
triggered.
Unfortunately, the current implementation only generates verbose strings
when SequenceCheckerImpl is passed as an argument.

Modify ExpectationToString to generate detailed messages even for
derived classes of SequenceCheckerImpl.

Bug: None
Change-Id: I55f76d44ad59dbe6f21cee7d7d8e19188e0f3088
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/276061
Commit-Queue: Daniel.L (Byoungchan) Lee <daniel.l@hpcnt.com>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#38211}
diff --git a/api/sequence_checker_unittest.cc b/api/sequence_checker_unittest.cc
index 5a99148..a929c59 100644
--- a/api/sequence_checker_unittest.cc
+++ b/api/sequence_checker_unittest.cc
@@ -18,8 +18,11 @@
 #include "rtc_base/event.h"
 #include "rtc_base/platform_thread.h"
 #include "rtc_base/task_queue_for_test.h"
+#include "test/gmock.h"
 #include "test/gtest.h"
 
+using testing::HasSubstr;
+
 namespace webrtc {
 namespace {
 
@@ -116,6 +119,36 @@
       [&] { EXPECT_EQ(sequence_checker.IsCurrent(), !RTC_DCHECK_IS_ON); });
 }
 
+TEST(SequenceCheckerTest, ExpectationToString) {
+  TaskQueueForTest queue1;
+
+  SequenceChecker sequence_checker;
+  sequence_checker.Detach();
+
+  rtc::Event blocker;
+  queue1.PostTask([&blocker, &sequence_checker]() {
+    (void)sequence_checker.IsCurrent();
+    blocker.Set();
+  });
+
+  blocker.Wait(rtc::Event::kForever);
+
+#if RTC_DCHECK_IS_ON
+
+  EXPECT_THAT(ExpectationToString(&sequence_checker),
+              HasSubstr("# Expected: TQ:"));
+
+  // Test for the base class
+  webrtc_sequence_checker_internal::SequenceCheckerImpl* sequence_checker_base =
+      &sequence_checker;
+  EXPECT_THAT(ExpectationToString(sequence_checker_base),
+              HasSubstr("# Expected: TQ:"));
+
+#else
+  GTEST_ASSERT_EQ(ExpectationToString(&sequence_checker), "");
+#endif
+}
+
 class TestAnnotations {
  public:
   TestAnnotations() : test_var_(false) {}
diff --git a/rtc_base/synchronization/sequence_checker_internal.cc b/rtc_base/synchronization/sequence_checker_internal.cc
index c03ee94..2612e9e 100644
--- a/rtc_base/synchronization/sequence_checker_internal.cc
+++ b/rtc_base/synchronization/sequence_checker_internal.cc
@@ -104,13 +104,5 @@
 }
 #endif  // RTC_DCHECK_IS_ON
 
-std::string ExpectationToString(const SequenceCheckerImpl* checker) {
-#if RTC_DCHECK_IS_ON
-  return checker->ExpectationToString();
-#else
-  return std::string();
-#endif
-}
-
 }  // namespace webrtc_sequence_checker_internal
 }  // namespace webrtc
diff --git a/rtc_base/synchronization/sequence_checker_internal.h b/rtc_base/synchronization/sequence_checker_internal.h
index be89133..a20fbb0 100644
--- a/rtc_base/synchronization/sequence_checker_internal.h
+++ b/rtc_base/synchronization/sequence_checker_internal.h
@@ -63,11 +63,22 @@
   void Detach() {}
 };
 
-std::string ExpectationToString(const SequenceCheckerImpl* checker);
+template <typename ThreadLikeObject>
+std::enable_if_t<std::is_base_of_v<SequenceCheckerImpl, ThreadLikeObject>,
+                 std::string>
+ExpectationToString(const ThreadLikeObject* checker) {
+#if RTC_DCHECK_IS_ON
+  return checker->ExpectationToString();
+#else
+  return std::string();
+#endif
+}
 
 // Catch-all implementation for types other than explicitly supported above.
 template <typename ThreadLikeObject>
-std::string ExpectationToString(const ThreadLikeObject*) {
+std::enable_if_t<!std::is_base_of_v<SequenceCheckerImpl, ThreadLikeObject>,
+                 std::string>
+ExpectationToString(const ThreadLikeObject*) {
   return std::string();
 }