QUICHE: Type check client histogram macro arguments

Most of the arguments to the QUICHE_CLIENT_HISTOGRAM_* macros were not type checked, meaning that errors would only be found once they were rolled into Chromium.

Add empty implementations to the default implementations of these macros that match the type checks performed by the real macros in Chromium so that errors can be easily found and fixed before landing changes.

No functional changes.

PiperOrigin-RevId: 796994306
diff --git a/quiche/common/platform/api/quiche_client_stats.h b/quiche/common/platform/api/quiche_client_stats.h
index 5b1b08c..c11ccc4 100644
--- a/quiche/common/platform/api/quiche_client_stats.h
+++ b/quiche/common/platform/api/quiche_client_stats.h
@@ -5,8 +5,6 @@
 #ifndef QUICHE_COMMON_PLATFORM_API_QUICHE_CLIENT_STATS_H_
 #define QUICHE_COMMON_PLATFORM_API_QUICHE_CLIENT_STATS_H_
 
-#include <string>
-
 #include "quiche_platform_impl/quiche_client_stats_impl.h"
 
 namespace quiche {
@@ -79,7 +77,8 @@
   QUICHE_CLIENT_HISTOGRAM_COUNTS_IMPL(name, sample, min, max, bucket_count,  \
                                       docstring)
 
-inline void QuicheClientSparseHistogram(const std::string& name, int sample) {
+template <typename String>
+inline void QuicheClientSparseHistogram(const String& name, int sample) {
   QuicheClientSparseHistogramImpl(name, sample);
 }
 
diff --git a/quiche/common/platform/default/quiche_platform_impl/quiche_client_stats_impl.h b/quiche/common/platform/default/quiche_platform_impl/quiche_client_stats_impl.h
index fde75f7..0f9f8e2 100644
--- a/quiche/common/platform/default/quiche_platform_impl/quiche_client_stats_impl.h
+++ b/quiche/common/platform/default/quiche_platform_impl/quiche_client_stats_impl.h
@@ -5,40 +5,88 @@
 #ifndef QUICHE_COMMON_PLATFORM_DEFAULT_QUICHE_PLATFORM_IMPL_QUICHE_CLIENT_STATS_IMPL_H_
 #define QUICHE_COMMON_PLATFORM_DEFAULT_QUICHE_PLATFORM_IMPL_QUICHE_CLIENT_STATS_IMPL_H_
 
-#include <string>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <type_traits>
+
+#include "quiche/common/platform/api/quiche_export.h"
 
 namespace quiche {
 
+// Force `name` to be a string constant by applying C-preprocessor
+// concatenation.
+#define QUICHE_REQUIRE_STRING_CONSTANT(name) "" name
+
+// The implementations in this file are no-ops at runtime, but force type
+// checking of the arguments at compile-time so that the code will still compile
+// when merged to Chromium.
+
 // Use namespace qualifier in case the macro is used outside the quiche
 // namespace.
 
 #define QUICHE_CLIENT_HISTOGRAM_ENUM_IMPL(name, sample, enum_size, docstring) \
-  do {                                                                        \
-    quiche::QuicheClientSparseHistogramImpl(name, static_cast<int>(sample));  \
-  } while (0)
+  quiche::QuicheClientHistogramEnumerationTypeChecker(                        \
+      QUICHE_REQUIRE_STRING_CONSTANT(name), sample, enum_size)
 
 #define QUICHE_CLIENT_HISTOGRAM_BOOL_IMPL(name, sample, docstring) \
-  do {                                                             \
-    (void)sample; /* Workaround for -Wunused-variable. */          \
-  } while (0)
+  quiche::QuicheClientHistogramBoolTypeChecker(                    \
+      QUICHE_REQUIRE_STRING_CONSTANT(name), sample)
 
 #define QUICHE_CLIENT_HISTOGRAM_TIMES_IMPL(name, sample, min, max, \
                                            num_buckets, docstring) \
-  do {                                                             \
-    (void)sample; /* Workaround for -Wunused-variable. */          \
-  } while (0)
+  quiche::QuicheClientHistogramTimesTypeChecker(                   \
+      QUICHE_REQUIRE_STRING_CONSTANT(name), sample, min, max, num_buckets)
 
 #define QUICHE_CLIENT_HISTOGRAM_COUNTS_IMPL(name, sample, min, max, \
                                             num_buckets, docstring) \
-  do {                                                              \
-    quiche::QuicheClientSparseHistogramImpl(name, sample);          \
-  } while (0)
+  quiche::QuicheClientHistogramCountsTypeChecker(                   \
+      QUICHE_REQUIRE_STRING_CONSTANT(name), sample, min, max, num_buckets)
 
-inline void QuicheClientSparseHistogramImpl(const std::string& /*name*/,
-                                            int /*sample*/) {
+// This object's constructor enforces the restriction that the argument must be
+// a string constant.
+struct QUICHE_NO_EXPORT QuicheRequireStringConstant {
+  template <size_t N>
+  consteval QuicheRequireStringConstant(const char (& /*name*/)[N]) {}
+};
+
+inline void QuicheClientSparseHistogramImpl(
+    QuicheRequireStringConstant /*name*/, int /*sample*/) {
   // No-op.
 }
 
+// Enforce type checks on enums so that errors can be caught before rolling to
+// Chromium.
+template <typename SampleType, typename EnumSizeType>
+inline void QuicheClientHistogramEnumerationTypeChecker(
+    QuicheRequireStringConstant /*name*/, SampleType /*sample*/,
+    EnumSizeType /*enum_size*/) {
+  // These are equivalent to the type checks done by Chromium's
+  // UMA_HISTOGRAM_ENUMERATION macro.
+  static_assert(!std::is_enum_v<SampleType> || std::is_enum_v<EnumSizeType>,
+                "Unexpected: |enum_size| is enum, but |sample| is not.");
+  static_assert(
+      !std::is_enum_v<SampleType> || std::is_same_v<SampleType, EnumSizeType>,
+      "|sample| and |boundary| shouldn't be of different enums");
+}
+
+inline void QuicheClientHistogramBoolTypeChecker(
+    QuicheRequireStringConstant /*name*/, bool /*sample*/) {}
+
+template <typename TimeDelta>
+inline void QuicheClientHistogramTimesTypeChecker(
+    QuicheRequireStringConstant /*name*/, TimeDelta sample, TimeDelta /*min*/,
+    TimeDelta /*max*/, int /*num_buckets*/) {
+  static_assert(
+      std::is_convertible_v<decltype(sample.ToMicroseconds()), int64_t>,
+      "The value passed to QUICHE_CLIENT_HISTOGRAM_TIMES must have a "
+      "ToMicroseconds() method that returns a value convertible to int64_t.");
+}
+
+inline void QuicheClientHistogramCountsTypeChecker(
+    QuicheRequireStringConstant /*name*/, int32_t /*sample*/, int32_t /*min*/,
+    int32_t /*max*/, size_t /*num_buckets*/) {}
+
 }  // namespace quiche
 
 #endif  // QUICHE_COMMON_PLATFORM_DEFAULT_QUICHE_PLATFORM_IMPL_QUICHE_CLIENT_STATS_IMPL_H_
diff --git a/quiche/quic/platform/api/quic_client_stats.h b/quiche/quic/platform/api/quic_client_stats.h
index d18d614..da41ce4 100644
--- a/quiche/quic/platform/api/quic_client_stats.h
+++ b/quiche/quic/platform/api/quic_client_stats.h
@@ -5,8 +5,6 @@
 #ifndef QUICHE_QUIC_PLATFORM_API_QUIC_CLIENT_STATS_H_
 #define QUICHE_QUIC_PLATFORM_API_QUIC_CLIENT_STATS_H_
 
-#include <string>
-
 #include "quiche/common/platform/api/quiche_client_stats.h"
 
 namespace quic {
@@ -78,7 +76,8 @@
   QUICHE_CLIENT_HISTOGRAM_COUNTS(name, sample, min, max, bucket_count,     \
                                  docstring)
 
-inline void QuicClientSparseHistogram(const std::string& name, int sample) {
+template <typename String>
+inline void QuicClientSparseHistogram(const String& name, int sample) {
   quiche::QuicheClientSparseHistogram(name, sample);
 }