[clang] [clang][ssaf] Implement JSONFormat (PR #180021)

Balázs Benics via cfe-commits cfe-commits at lists.llvm.org
Wed Feb 11 08:00:06 PST 2026


================
@@ -0,0 +1,973 @@
+#include "clang/Analysis/Scalable/Serialization/JSONFormat.h"
+#include "clang/Analysis/Scalable/TUSummary/TUSummary.h"
+
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/JSON.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Registry.h"
+
+using namespace clang::ssaf;
+
+//----------------------------------------------------------------------------
+// ErrorBuilder - Fluent API for constructing contextual errors
+//----------------------------------------------------------------------------
+
+namespace {
+
+class ErrorBuilder {
+private:
+  std::error_code Code;
+  std::vector<std::string> ContextStack;
+
+  // Private constructor - only accessible via static factories
+  explicit ErrorBuilder(std::error_code EC) : Code(EC) {}
+
+  // Helper: Format message and add to context stack
+  template <typename... Args>
+  void addFormattedContext(const char *Fmt, Args &&...ArgVals) {
+    std::string Message =
+        llvm::formatv(Fmt, std::forward<Args>(ArgVals)...).str();
+    ContextStack.push_back(std::move(Message));
+  }
+
+public:
+  // Static factory: Create new error from error code and formatted message
+  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 for std::errc
+  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)...);
+  }
+
+  // Static factory: Wrap existing error and optionally add context
+  static ErrorBuilder wrap(llvm::Error E) {
+    if (!E) {
+      llvm::consumeError(std::move(E));
+      // Return builder with generic error code for success case
+      return ErrorBuilder(std::make_error_code(std::errc::invalid_argument));
+    }
+
+    std::error_code EC;
+    std::string ErrorMsg;
+
+    llvm::handleAllErrors(std::move(E), [&](const llvm::ErrorInfoBase &EI) {
+      EC = EI.convertToErrorCode();
+      ErrorMsg = EI.message();
+    });
+
+    ErrorBuilder Builder(EC);
+    if (!ErrorMsg.empty()) {
+      Builder.ContextStack.push_back(std::move(ErrorMsg));
+    }
+    return Builder;
+  }
+
+  // Add context (plain string)
+  ErrorBuilder &context(const char *Msg) {
+    ContextStack.push_back(Msg);
+    return *this;
+  }
+
+  // Add context (formatted string)
+  template <typename... Args>
+  ErrorBuilder &context(const char *Fmt, Args &&...ArgVals) {
+    addFormattedContext(Fmt, std::forward<Args>(ArgVals)...);
+    return *this;
+  }
+
+  // Build the final error
+  llvm::Error build() {
+    if (ContextStack.empty())
+      return llvm::Error::success();
+
+    // Reverse the context stack so that the most recent context appears first
+    // and the wrapped error (if any) appears last
+    std::vector<std::string> ReversedContext(ContextStack.rbegin(),
+                                             ContextStack.rend());
+    std::string FinalMessage = llvm::join(ReversedContext, "\n");
+    return llvm::createStringError(Code, "%s", FinalMessage.c_str());
+  }
+};
+
+} // namespace
+
+//----------------------------------------------------------------------------
+// Error Message Constants
+//----------------------------------------------------------------------------
+
+namespace {
+
+namespace ErrorMessages {
+
+constexpr const char *FailedToReadFile = "failed to read file '{0}': {1}";
+constexpr const char *FailedToWriteFile = "failed to write file '{0}': {1}";
+constexpr const char *FileNotFound = "file does not exist";
----------------
steakhal wrote:

I can't exactly recall, but as if there was upstream some discussion about avoiding many global strings to reduce the load at load time for relocating symbols.
I believe something like that was the motivation for the `ADT/StringTable`.
I don't really know the context there, so this might be a false alarm.

https://github.com/llvm/llvm-project/pull/180021


More information about the cfe-commits mailing list