fuzzers: Don't pointlessly format diagnostics

Fuzzers like to generate silly long source, and formatting large spans of these can take considerable time.
Only format the diagnostic if it is going to be displayed.

Significantly speeds up some fuzzing tests, fixing some timeouts.

Also add a minor optimization to the formatter repeat() implementation.

Fixed: chromium:1230313
Change-Id: Ib1f6ac0b31010f86cb7f4e1432dc703ecbe52cb0
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/58841
Auto-Submit: Ben Clayton <bclayton@google.com>
Commit-Queue: Ryan Harrison <rharrison@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Ryan Harrison <rharrison@chromium.org>
diff --git a/fuzzers/tint_ast_fuzzer/fuzzer.cc b/fuzzers/tint_ast_fuzzer/fuzzer.cc
index 421ee4e..a6c3129 100644
--- a/fuzzers/tint_ast_fuzzer/fuzzer.cc
+++ b/fuzzers/tint_ast_fuzzer/fuzzer.cc
@@ -106,9 +106,10 @@
     fuzzer.EnableInspector();
     fuzzer.Run(data, size);
     if (fuzzer.HasErrors()) {
-      std::cout << "Fuzzing " << target.name
-                << " produced an error:" << std::endl
-                << fuzzer.GetErrors() << std::endl;
+      std::cout << "Fuzzing " << target.name << " produced an error"
+                << std::endl;
+      auto printer = tint::diag::Printer::create(stderr, true);
+      tint::diag::Formatter{}.format(fuzzer.Diagnostics(), printer.get());
     }
   }
 
diff --git a/fuzzers/tint_common_fuzzer.cc b/fuzzers/tint_common_fuzzer.cc
index 9e36291..153cf8f 100644
--- a/fuzzers/tint_common_fuzzer.cc
+++ b/fuzzers/tint_common_fuzzer.cc
@@ -217,7 +217,7 @@
   }
 
   if (!program.IsValid()) {
-    errors_ = diag::Formatter().format(program.Diagnostics());
+    diagnostics_ = program.Diagnostics();
     return 0;
   }
 
@@ -234,68 +234,77 @@
 
     auto entry_points = inspector.GetEntryPoints();
     if (inspector.has_error()) {
-      errors_ = inspector.error();
+      diagnostics_.add_error(tint::diag::System::Inspector, inspector.error());
       return 0;
     }
 
     for (auto& ep : entry_points) {
       auto remapped_name = inspector.GetRemappedNameForEntryPoint(ep.name);
       if (inspector.has_error()) {
-        errors_ = inspector.error();
+        diagnostics_.add_error(tint::diag::System::Inspector,
+                               inspector.error());
         return 0;
       }
 
       auto constant_ids = inspector.GetConstantIDs();
       if (inspector.has_error()) {
-        errors_ = inspector.error();
+        diagnostics_.add_error(tint::diag::System::Inspector,
+                               inspector.error());
         return 0;
       }
 
       auto uniform_bindings =
           inspector.GetUniformBufferResourceBindings(ep.name);
       if (inspector.has_error()) {
-        errors_ = inspector.error();
+        diagnostics_.add_error(tint::diag::System::Inspector,
+                               inspector.error());
         return 0;
       }
 
       auto storage_bindings =
           inspector.GetStorageBufferResourceBindings(ep.name);
       if (inspector.has_error()) {
-        errors_ = inspector.error();
+        diagnostics_.add_error(tint::diag::System::Inspector,
+                               inspector.error());
         return 0;
       }
 
       auto readonly_bindings =
           inspector.GetReadOnlyStorageBufferResourceBindings(ep.name);
       if (inspector.has_error()) {
-        errors_ = inspector.error();
+        diagnostics_.add_error(tint::diag::System::Inspector,
+                               inspector.error());
         return 0;
       }
 
       auto sampler_bindings = inspector.GetSamplerResourceBindings(ep.name);
       if (inspector.has_error()) {
-        errors_ = inspector.error();
+        diagnostics_.add_error(tint::diag::System::Inspector,
+                               inspector.error());
         return 0;
       }
 
       auto comparison_sampler_bindings =
           inspector.GetComparisonSamplerResourceBindings(ep.name);
       if (inspector.has_error()) {
-        errors_ = inspector.error();
+        diagnostics_.add_error(tint::diag::System::Inspector,
+                               inspector.error());
         return 0;
       }
 
       auto sampled_texture_bindings =
           inspector.GetSampledTextureResourceBindings(ep.name);
       if (inspector.has_error()) {
-        errors_ = inspector.error();
+        diagnostics_.add_error(tint::diag::System::Inspector,
+                               inspector.error());
         return 0;
       }
 
       auto multisampled_texture_bindings =
           inspector.GetMultisampledTextureResourceBindings(ep.name);
       if (inspector.has_error()) {
-        errors_ = inspector.error();
+        diagnostics_.add_error(tint::diag::System::Inspector,
+                               inspector.error());
         return 0;
       }
     }
diff --git a/fuzzers/tint_common_fuzzer.h b/fuzzers/tint_common_fuzzer.h
index 3bdaf23..32475cc 100644
--- a/fuzzers/tint_common_fuzzer.h
+++ b/fuzzers/tint_common_fuzzer.h
@@ -110,8 +110,6 @@
 
   int Run(const uint8_t* data, size_t size);
 
-  const std::string& GetErrors() const { return errors_; }
-
   const std::vector<uint32_t>& GetGeneratedSpirv() const {
     return generated_spirv_;
   }
@@ -122,7 +120,9 @@
 
   const std::string& GetGeneratedMsl() const { return generated_msl_; }
 
-  bool HasErrors() const { return !errors_.empty(); }
+  const tint::diag::List& Diagnostics() const { return diagnostics_; }
+
+  bool HasErrors() const { return diagnostics_.contains_errors(); }
 
  private:
   InputFormat input_;
@@ -130,7 +130,7 @@
   transform::Manager* transform_manager_;
   transform::DataMap transform_inputs_;
   bool inspector_enabled_;
-  std::string errors_;
+  tint::diag::List diagnostics_;
 
   std::vector<uint32_t> generated_spirv_;
   std::string generated_wgsl_;
diff --git a/src/diagnostic/formatter.cc b/src/diagnostic/formatter.cc
index 4b20879..e162c89 100644
--- a/src/diagnostic/formatter.cc
+++ b/src/diagnostic/formatter.cc
@@ -15,6 +15,7 @@
 #include "src/diagnostic/formatter.h"
 
 #include <algorithm>
+#include <iterator>
 #include <vector>
 
 #include "src/diagnostic/diagnostic.h"
@@ -96,9 +97,7 @@
   /// @param c the character to print `n` times
   /// @param n the number of times to print character `c`
   void repeat(char c, size_t n) {
-    while (n-- > 0) {
-      stream << c;
-    }
+    std::fill_n(std::ostream_iterator<char>(stream), n, c);
   }
 
  private: