================
@@ -0,0 +1,207 @@
+//===- ErrorBuilder.h - Fluent API for contextual errors --------*- C++ 
-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file defines the ErrorBuilder class, which provides a fluent API for
+//  constructing contextual error messages with layered context information.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_SCALABLE_SUPPORT_ERRORBUILDER_H
+#define LLVM_CLANG_ANALYSIS_SCALABLE_SUPPORT_ERRORBUILDER_H
+
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FormatVariadic.h"
+#include <optional>
+#include <string>
+#include <system_error>
+#include <vector>
+
+namespace clang::ssaf {
+
+/// Fluent API for constructing contextual errors.
+///
+/// ErrorBuilder allows building error messages with layered context
+/// information. Context is added innermost to outermost, and the final
+/// error message presents the context in reverse order (outermost first).
+///
+/// Example usage:
+///   return ErrorBuilder::create(std::errc::invalid_argument,
+///                               "invalid value {0}", value)
+///       .context("processing field '{0}'", fieldName)
+///       .context("reading configuration")
+///       .build();
+class ErrorBuilder {
+  std::error_code Code;
+  std::vector<std::string> ContextStack;
+
+  explicit ErrorBuilder(std::error_code EC) : Code(EC) {}
+
+  void pushContext(std::string Msg) {
+    if (!Msg.empty()) {
+      ContextStack.push_back(std::move(Msg));
+    }
+  }
+
+  template <typename... Args>
+  static std::string formatErrorMessage(const char *Fmt, Args &&...ArgVals) {
+    return llvm::formatv(Fmt, std::forward<Args>(ArgVals)...).str();
+  }
+
+  template <typename... Args>
+  void addFormattedContext(const char *Fmt, Args &&...ArgVals) {
+    pushContext(formatErrorMessage(Fmt, std::forward<Args>(ArgVals)...));
+  }
+
+public:
+  /// Create an ErrorBuilder with an error code and formatted message.
+  ///
+  /// \param EC The error code for this error.
+  /// \param Fmt Format string for the error message (using llvm::formatv).
+  /// \param ArgVals Arguments for the format string.
+  /// \returns A new ErrorBuilder with the initial error message.
+  ///
+  /// Example:
+  /// \code
+  ///   return ErrorBuilder::create(std::errc::invalid_argument,
+  ///                               "invalid value: {0}", 42)
+  ///       .build();
+  /// \endcode
+  template <typename... Args>
+  static ErrorBuilder create(std::error_code EC, const char *Fmt,
+                             Args &&...ArgVals) {
+    ErrorBuilder Builder(EC);
+    Builder.addFormattedContext(Fmt, std::forward<Args>(ArgVals)...);
+    return Builder;
+  }
+
+  /// Convenience overload that accepts std::errc instead of std::error_code.
+  ///
+  /// \param EC The error condition for this error.
+  /// \param Fmt Format string for the error message.
+  /// \param ArgVals Arguments for the format string.
+  /// \returns A new ErrorBuilder with the initial error message.
+  template <typename... Args>
+  static ErrorBuilder create(std::errc EC, const char *Fmt, Args &&...ArgVals) 
{
+    return create(std::make_error_code(EC), Fmt,
+                  std::forward<Args>(ArgVals)...);
+  }
+
+  /// Wrap an existing error and optionally add context.
+  ///
+  /// Extracts the error code and message(s) from the given error. If multiple
+  /// errors are joined (via llvm::joinErrors), their messages are combined
+  /// using " + " separator.
+  ///
+  /// \param E The error to wrap. Must be a failure (cannot be success).
+  /// \returns A new ErrorBuilder containing the wrapped error information.
+  ///
+  /// \pre E must evaluate to true (i.e., must be a failure). Wrapping
+  ///      Error::success() is a programming error and will trigger an
+  ///      assertion failure in debug builds.
+  ///
+  /// Example:
+  /// \code
+  ///   if (auto Err = foo())
+  ///     return ErrorBuilder::wrap(std::move(Err))
+  ///         .context("while processing file")
+  ///         .build();
+  /// \endcode
+  static ErrorBuilder wrap(llvm::Error E);
+
+  /// Add context information as a plain string.
+  ///
+  /// Empty strings are ignored and not added to the context stack.
+  ///
+  /// \param Msg Context message to add. Must be a null-terminated string.
+  /// \returns Reference to this ErrorBuilder for method chaining.
+  ///
+  /// Example:
+  /// \code
+  ///   return ErrorBuilder::create(...)
+  ///       .context("reading configuration file")
+  ///       .build();
+  /// \endcode
+  ErrorBuilder &context(const char *Msg);
+
+  /// Add context information with formatted string.
+  ///
+  /// Uses llvm::formatv for formatting. Empty messages (after formatting)
+  /// are ignored and not added to the context stack.
+  ///
+  /// \param Fmt Format string (using llvm::formatv syntax).
+  /// \param ArgVals Arguments for the format string.
+  /// \returns Reference to this ErrorBuilder for method chaining.
+  ///
+  /// Example:
+  /// \code
+  ///   return ErrorBuilder::create(...)
+  ///       .context("processing field '{0}'", fieldName)
+  ///       .context("at line {0}, column {1}", line, col)
+  ///       .build();
+  /// \endcode
+  template <typename... Args>
+  ErrorBuilder &context(const char *Fmt, Args &&...ArgVals) {
+    addFormattedContext(Fmt, std::forward<Args>(ArgVals)...);
+    return *this;
+  }
+
+  /// Build and return the final error.
+  ///
+  /// Constructs an llvm::Error with all accumulated context. The context
+  /// is presented in reverse order: most recent context first, original
+  /// error message last. Each context layer is separated by a newline.
+  ///
+  /// \returns An llvm::Error containing the error code and formatted message.
+  ///          Even if no context was added (empty context stack), an error
+  ///          with the stored error code is returned.
+  ///
+  /// \pre The ErrorBuilder must have been created via \c create() or \c 
wrap().
+  ///      Constructing an ErrorBuilder directly is not supported.
+  ///
+  /// Example output:
+  /// \code
+  ///   // ErrorBuilder::create(errc::invalid_argument, "value is 42")
+  ///   //     .context("processing field 'age'")
+  ///   //     .context("reading config")
+  ///   //     .build();
+  ///   //
+  ///   // Produces:
+  ///   // "reading config
+  ///   //  processing field 'age'
+  ///   //  value is 42"
+  /// \endcode
----------------
steakhal wrote:

```suggestion
  /// \code
  ///   ErrorBuilder::create(errc::invalid_argument, "value is 42")
  ///       .context("processing field 'age'")
  ///       .context("reading config")
  ///       .build();
  ///
  ///   // Produces:
  ///   // "reading config
  ///   //  processing field 'age'
  ///   //  value is 42"
  /// \endcode
```

https://github.com/llvm/llvm-project/pull/181765
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to