Add diag::List::add_error() helper

Refactors a common pattern in the tint codebase.

Change-Id: Ia8a70d952fd8c204facd0120f24e43ccc9305622
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/38840
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
diff --git a/src/diagnostic/diagnostic.h b/src/diagnostic/diagnostic.h
index be5d1a8..e85e8ca 100644
--- a/src/diagnostic/diagnostic.h
+++ b/src/diagnostic/diagnostic.h
@@ -98,6 +98,26 @@
     }
   }
 
+  /// adds the error message without a source to the end of this list.
+  /// @param err_msg the error message
+  void add_error(const std::string& err_msg) {
+    diag::Diagnostic error{};
+    error.severity = diag::Severity::Error;
+    error.message = err_msg;
+    add(std::move(error));
+  }
+
+  /// adds the error message with the given Source to the end of this list.
+  /// @param err_msg the error message
+  /// @param source the source of the error diagnostic
+  void add_error(const std::string& err_msg, const Source& source) {
+    diag::Diagnostic error{};
+    error.severity = diag::Severity::Error;
+    error.source = source;
+    error.message = err_msg;
+    add(std::move(error));
+  }
+
   /// @returns true iff the diagnostic list contains errors diagnostics (or of
   /// higher severity).
   bool contains_errors() const { return error_count_ > 0; }
diff --git a/src/reader/spirv/parser.cc b/src/reader/spirv/parser.cc
index 3fc7710..51cd2f0 100644
--- a/src/reader/spirv/parser.cc
+++ b/src/reader/spirv/parser.cc
@@ -14,6 +14,8 @@
 
 #include "src/reader/spirv/parser.h"
 
+#include <utility>
+
 #include "src/reader/spirv/parser_impl.h"
 
 namespace tint {
@@ -30,10 +32,9 @@
   auto err_msg = impl_->error();
   if (!err_msg.empty()) {
     // TODO(bclayton): Migrate spirv::ParserImpl to using diagnostics.
-    diag::Diagnostic error{};
-    error.severity = diag::Severity::Error;
-    error.message = err_msg;
-    set_diagnostics({error});
+    diag::List diagnostics;
+    diagnostics.add_error(err_msg);
+    set_diagnostics(std::move(diagnostics));
   }
   return result;
 }
diff --git a/src/reader/spirv/parser.h b/src/reader/spirv/parser.h
index e189656..711b50d 100644
--- a/src/reader/spirv/parser.h
+++ b/src/reader/spirv/parser.h
@@ -46,6 +46,7 @@
 
  private:
   std::unique_ptr<ParserImpl> impl_;
+  Program program_;
 };
 
 }  // namespace spirv
diff --git a/src/reader/wgsl/parser_impl.cc b/src/reader/wgsl/parser_impl.cc
index 341c252..89cb4e9 100644
--- a/src/reader/wgsl/parser_impl.cc
+++ b/src/reader/wgsl/parser_impl.cc
@@ -230,11 +230,7 @@
 ParserImpl::Failure::Errored ParserImpl::add_error(const Source& source,
                                                    const std::string& err) {
   if (silence_errors_ == 0) {
-    diag::Diagnostic diagnostic;
-    diagnostic.severity = diag::Severity::Error;
-    diagnostic.message = err;
-    diagnostic.source = source;
-    diags_.add(std::move(diagnostic));
+    diags_.add_error(err, source);
   }
   return Failure::kErrored;
 }
diff --git a/src/transform/bound_array_accessors.cc b/src/transform/bound_array_accessors.cc
index 4253fa2..dd293ff 100644
--- a/src/transform/bound_array_accessors.cc
+++ b/src/transform/bound_array_accessors.cc
@@ -102,11 +102,7 @@
       auto* limit = b.Sub(arr_len, b.Expr(1u));
       new_idx = b.Call("min", b.Construct<u32>(ctx->Clone(old_idx)), limit);
     } else {
-      diag::Diagnostic err;
-      err.severity = diag::Severity::Error;
-      err.message = "invalid 0 size";
-      err.source = expr->source();
-      diags->add(std::move(err));
+      diags->add_error("invalid 0 size", expr->source());
       return nullptr;
     }
   } else if (auto* c = old_idx->As<ast::ScalarConstructorExpression>()) {
@@ -118,11 +114,8 @@
     } else if (auto* uint = lit->As<ast::UintLiteral>()) {
       new_idx = b.Expr(std::min(uint->value(), size - 1));
     } else {
-      diag::Diagnostic err;
-      err.severity = diag::Severity::Error;
-      err.message = "unknown scalar constructor type for accessor";
-      err.source = expr->source();
-      diags->add(std::move(err));
+      diags->add_error("unknown scalar constructor type for accessor",
+                       expr->source());
       return nullptr;
     }
   } else {
diff --git a/src/transform/first_index_offset.cc b/src/transform/first_index_offset.cc
index d9790b0..95d652e 100644
--- a/src/transform/first_index_offset.cc
+++ b/src/transform/first_index_offset.cc
@@ -88,11 +88,9 @@
   for (ast::Variable* var : in->AST().GlobalVariables()) {
     if (auto* dec_var = var->As<ast::Variable>()) {
       if (dec_var->symbol() == in->Symbols().Get(kBufferName)) {
-        diag::Diagnostic err;
-        err.message = "First index offset transform has already been applied.";
-        err.severity = diag::Severity::Error;
         Output out;
-        out.diagnostics.add(std::move(err));
+        out.diagnostics.add_error(
+            "First index offset transform has already been applied.");
         return out;
       }
     }
@@ -106,11 +104,8 @@
     ProgramBuilder builder = in->CloneAsBuilder();
     TypeDeterminer td(&builder);
     if (!td.Determine()) {
-      diag::Diagnostic err;
-      err.severity = diag::Severity::Error;
-      err.message = td.error();
       Output out;
-      out.diagnostics.add(std::move(err));
+      out.diagnostics.add_error(td.error());
       return out;
     }
     program = Program(std::move(builder));
diff --git a/src/transform/vertex_pulling.cc b/src/transform/vertex_pulling.cc
index effd571..39585be 100644
--- a/src/transform/vertex_pulling.cc
+++ b/src/transform/vertex_pulling.cc
@@ -78,11 +78,8 @@
 Transform::Output VertexPulling::Run(const Program* in) {
   // Check SetVertexState was called
   if (!cfg.vertex_state_set) {
-    diag::Diagnostic err;
-    err.severity = diag::Severity::Error;
-    err.message = "SetVertexState not called";
     Output out;
-    out.diagnostics.add(std::move(err));
+    out.diagnostics.add_error("SetVertexState not called");
     return out;
   }
 
@@ -90,11 +87,8 @@
   auto* func = in->AST().Functions().Find(
       in->Symbols().Get(cfg.entry_point_name), ast::PipelineStage::kVertex);
   if (func == nullptr) {
-    diag::Diagnostic err;
-    err.severity = diag::Severity::Error;
-    err.message = "Vertex stage entry point not found";
     Output out;
-    out.diagnostics.add(std::move(err));
+    out.diagnostics.add_error("Vertex stage entry point not found");
     return out;
   }
 
diff --git a/src/type_determiner.cc b/src/type_determiner.cc
index 63f4d35..f0f8c61 100644
--- a/src/type_determiner.cc
+++ b/src/type_determiner.cc
@@ -69,10 +69,9 @@
   ProgramBuilder builder = program->CloneAsBuilder();
   TypeDeterminer td(&builder);
   if (!td.Determine()) {
-    diag::Diagnostic err;
-    err.severity = diag::Severity::Error;
-    err.message = td.error();
-    return {err};
+    diag::List diagnostics;
+    diagnostics.add_error(td.error());
+    return diagnostics;
   }
   *program = Program(std::move(builder));
   return {};
diff --git a/src/validator/validator_impl.cc b/src/validator/validator_impl.cc
index 85297e4..6beadbf 100644
--- a/src/validator/validator_impl.cc
+++ b/src/validator/validator_impl.cc
@@ -58,11 +58,7 @@
 }
 
 void ValidatorImpl::add_error(const Source& src, const std::string& msg) {
-  diag::Diagnostic diag;
-  diag.severity = diag::Severity::Error;
-  diag.source = src;
-  diag.message = msg;
-  diags_.add(std::move(diag));
+  diags_.add_error(msg, src);
 }
 
 bool ValidatorImpl::Validate() {