[clang] [clang][ssaf] Consolidate tools and shared utilities under `clang/tools/clang-ssaf/` (PR #187439)

Aviral Goel via cfe-commits cfe-commits at lists.llvm.org
Fri Mar 20 09:38:24 PDT 2026


https://github.com/aviralg updated https://github.com/llvm/llvm-project/pull/187439

>From 4785c4c20dfa19f83b039933a35db9f98e79cb3a Mon Sep 17 00:00:00 2001
From: Aviral Goel <agoel26 at apple.com>
Date: Wed, 18 Mar 2026 22:08:00 -0700
Subject: [PATCH 1/2] Move common code out

---
 .../Tool/Utils.h                              | 110 +++++++++++++++
 .../CMakeLists.txt                            |   2 +-
 .../Tool/CMakeLists.txt                       |  11 ++
 .../Tool/Utils.cpp                            | 129 ++++++++++++++++++
 clang/tools/clang-ssaf-format/CMakeLists.txt  |   1 +
 clang/tools/clang-ssaf-format/SSAFFormat.cpp  | 129 ++----------------
 clang/tools/clang-ssaf-linker/CMakeLists.txt  |   1 +
 clang/tools/clang-ssaf-linker/SSAFLinker.cpp  | 107 ++-------------
 8 files changed, 271 insertions(+), 219 deletions(-)
 create mode 100644 clang/include/clang/ScalableStaticAnalysisFramework/Tool/Utils.h
 create mode 100644 clang/lib/ScalableStaticAnalysisFramework/Tool/CMakeLists.txt
 create mode 100644 clang/lib/ScalableStaticAnalysisFramework/Tool/Utils.cpp

diff --git a/clang/include/clang/ScalableStaticAnalysisFramework/Tool/Utils.h b/clang/include/clang/ScalableStaticAnalysisFramework/Tool/Utils.h
new file mode 100644
index 0000000000000..cf515df54e631
--- /dev/null
+++ b/clang/include/clang/ScalableStaticAnalysisFramework/Tool/Utils.h
@@ -0,0 +1,110 @@
+//===- Utils.h - Shared utilities for SSAF tools ----------------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+//  Shared error-handling, format-registry cache, and summary-file abstraction
+//  used by clang-ssaf-linker and clang-ssaf-format.
+//
+//  All declarations live in the clang::ssaf namespace.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_TOOL_UTILS_H
+#define LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_TOOL_UTILS_H
+
+#include "clang/ScalableStaticAnalysisFramework/Core/Serialization/SerializationFormatRegistry.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FormatVariadic.h"
+#include <string>
+
+namespace clang::ssaf {
+
+//===----------------------------------------------------------------------===//
+// Tool Identity
+//===----------------------------------------------------------------------===//
+
+/// Returns the name of the running tool, as set by initTool().
+llvm::StringRef getToolName();
+
+//===----------------------------------------------------------------------===//
+// Error Messages
+//===----------------------------------------------------------------------===//
+
+namespace ErrorMessages {
+
+constexpr const char *CannotValidateSummary =
+    "failed to validate summary '{0}': {1}";
+
+constexpr const char *ExtensionNotSupplied = "Extension not supplied";
+
+constexpr const char *NoFormatForExtension =
+    "Format not registered for extension '{0}'";
+
+constexpr const char *OutputDirectoryMissing =
+    "Parent directory does not exist";
+
+constexpr const char *FailedToLoadPlugin = "failed to load plugin '{0}': {1}";
+
+} // namespace ErrorMessages
+
+//===----------------------------------------------------------------------===//
+// Diagnostic Utilities
+//===----------------------------------------------------------------------===//
+
+[[noreturn]] void fail(const char *Msg);
+
+template <typename... Ts>
+[[noreturn]] inline void fail(const char *Fmt, Ts &&...Args) {
+  std::string Message = llvm::formatv(Fmt, std::forward<Ts>(Args)...);
+  fail(Message.data());
+}
+
+[[noreturn]] void fail(llvm::Error Err);
+
+//===----------------------------------------------------------------------===//
+// Plugin Loading
+//===----------------------------------------------------------------------===//
+
+void loadPlugins(llvm::ArrayRef<std::string> Paths);
+
+//===----------------------------------------------------------------------===//
+// Initialization
+//===----------------------------------------------------------------------===//
+
+/// Sets ToolName, ToolVersion, and the version printer, hides unrelated
+/// command-line options, and parses arguments. Must be called after InitLLVM.
+void initTool(int argc, const char **argv, llvm::StringRef Version,
+              llvm::cl::OptionCategory &Category, llvm::StringRef ToolHeading);
+
+//===----------------------------------------------------------------------===//
+// Format Registry
+//===----------------------------------------------------------------------===//
+
+/// Returns the SerializationFormat registered for \p Extension, or nullptr if
+/// none is registered. Results are cached for the lifetime of the process.
+SerializationFormat *getFormatForExtension(llvm::StringRef Extension);
+
+//===----------------------------------------------------------------------===//
+// Data Structures
+//===----------------------------------------------------------------------===//
+
+struct SummaryFile {
+  std::string Path;
+  SerializationFormat *Format = nullptr;
+
+  /// Constructs a SummaryFile by resolving the serialization format from the
+  /// file extension. Calls fail() and exits if the extension is missing or
+  /// unregistered.
+  static SummaryFile fromPath(llvm::StringRef Path);
+};
+
+} // namespace clang::ssaf
+
+#endif // LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_TOOL_UTILS_H
diff --git a/clang/lib/ScalableStaticAnalysisFramework/CMakeLists.txt b/clang/lib/ScalableStaticAnalysisFramework/CMakeLists.txt
index 6bcb1a0038127..3da5c8899ddb6 100644
--- a/clang/lib/ScalableStaticAnalysisFramework/CMakeLists.txt
+++ b/clang/lib/ScalableStaticAnalysisFramework/CMakeLists.txt
@@ -1,4 +1,4 @@
 add_subdirectory(Analyses)
 add_subdirectory(Core)
 add_subdirectory(Frontend)
-
+add_subdirectory(Tool)
diff --git a/clang/lib/ScalableStaticAnalysisFramework/Tool/CMakeLists.txt b/clang/lib/ScalableStaticAnalysisFramework/Tool/CMakeLists.txt
new file mode 100644
index 0000000000000..53b900ec8c042
--- /dev/null
+++ b/clang/lib/ScalableStaticAnalysisFramework/Tool/CMakeLists.txt
@@ -0,0 +1,11 @@
+set(LLVM_LINK_COMPONENTS
+  Support
+  )
+
+add_clang_library(clangScalableStaticAnalysisFrameworkTool
+  Utils.cpp
+
+  LINK_LIBS
+  clangBasic
+  clangScalableStaticAnalysisFrameworkCore
+  )
diff --git a/clang/lib/ScalableStaticAnalysisFramework/Tool/Utils.cpp b/clang/lib/ScalableStaticAnalysisFramework/Tool/Utils.cpp
new file mode 100644
index 0000000000000..9eef571a71d82
--- /dev/null
+++ b/clang/lib/ScalableStaticAnalysisFramework/Tool/Utils.cpp
@@ -0,0 +1,129 @@
+//===- Utils.cpp - Shared utilities for SSAF tools -----------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/ScalableStaticAnalysisFramework/Tool/Utils.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/DynamicLibrary.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+#include <memory>
+#include <string>
+
+namespace clang::ssaf {
+
+namespace path = llvm::sys::path;
+
+static llvm::StringRef ToolName;
+static llvm::StringRef ToolVersion;
+
+llvm::StringRef getToolName() { return ToolName; }
+
+void printVersion(llvm::raw_ostream &OS) {
+  OS << ToolName << " " << ToolVersion << "\n";
+}
+
+[[noreturn]] void fail(const char *Msg) {
+  llvm::WithColor::error(llvm::errs(), ToolName) << Msg << "\n";
+  llvm::sys::Process::Exit(1);
+}
+
+[[noreturn]] void fail(llvm::Error Err) {
+  std::string Message = llvm::toString(std::move(Err));
+  fail(Message.data());
+}
+
+void loadPlugins(llvm::ArrayRef<std::string> Paths) {
+  for (const std::string &PluginPath : Paths) {
+    std::string ErrMsg;
+    if (llvm::sys::DynamicLibrary::LoadLibraryPermanently(PluginPath.c_str(),
+                                                          &ErrMsg)) {
+      fail(ErrorMessages::FailedToLoadPlugin, PluginPath, ErrMsg);
+    }
+  }
+}
+
+void initTool(int argc, const char **argv, llvm::StringRef Version,
+              llvm::cl::OptionCategory &Category, llvm::StringRef ToolHeading) {
+  // path::stem strips the .exe extension on Windows so ToolName is consistent.
+  ToolName = path::stem(argv[0]);
+
+  // Set tool version for the version printer.
+  ToolVersion = Version;
+
+  // Hide options unrelated to the tool from --help output.
+  llvm::cl::HideUnrelatedOptions(Category);
+
+  // Register a custom version printer for the --version flag.
+  llvm::cl::SetVersionPrinter(printVersion);
+
+  // Parse command-line arguments and exit with an error if they are invalid.
+  std::string Overview = (ToolHeading + "\n").str();
+  llvm::cl::ParseCommandLineOptions(argc, argv, Overview);
+}
+
+// FIXME: This will be revisited after we add support for registering formats
+// with extensions.
+SerializationFormat *getFormatForExtension(llvm::StringRef Extension) {
+  // This cache is not thread-safe. SSAF tools are single-threaded CLIs, so
+  // concurrent calls to this function are not expected.
+
+  // Realistically, we don't expect to encounter more than four registered
+  // formats.
+  static llvm::SmallVector<
+      std::pair<std::string, std::unique_ptr<SerializationFormat>>, 4>
+      ExtensionFormatList;
+
+  // Most recently used format is most likely to be reused again.
+  auto ReversedList = llvm::reverse(ExtensionFormatList);
+  auto It = llvm::find_if(ReversedList, [&](const auto &Entry) {
+    return Entry.first == Extension;
+  });
+  if (It != ReversedList.end()) {
+    return It->second.get();
+  }
+
+  if (!isFormatRegistered(Extension)) {
+    return nullptr;
+  }
+
+  auto Format = makeFormat(Extension);
+  SerializationFormat *Result = Format.get();
+  assert(Result &&
+         "makeFormat must return non-null for a registered extension");
+
+  ExtensionFormatList.emplace_back(Extension, std::move(Format));
+
+  return Result;
+}
+
+SummaryFile SummaryFile::fromPath(llvm::StringRef Path) {
+  llvm::StringRef Extension = path::extension(Path);
+  if (Extension.empty()) {
+    fail(ErrorMessages::CannotValidateSummary, Path,
+         ErrorMessages::ExtensionNotSupplied);
+  }
+
+  Extension = Extension.drop_front();
+  SerializationFormat *Format = getFormatForExtension(Extension);
+  if (!Format) {
+    std::string BadExtension =
+        llvm::formatv(ErrorMessages::NoFormatForExtension, Extension);
+    fail(ErrorMessages::CannotValidateSummary, Path, BadExtension);
+  }
+
+  return {Path.str(), Format};
+}
+
+} // namespace clang::ssaf
diff --git a/clang/tools/clang-ssaf-format/CMakeLists.txt b/clang/tools/clang-ssaf-format/CMakeLists.txt
index f64d12eb3fac0..864fe5bc27aaa 100644
--- a/clang/tools/clang-ssaf-format/CMakeLists.txt
+++ b/clang/tools/clang-ssaf-format/CMakeLists.txt
@@ -11,4 +11,5 @@ clang_target_link_libraries(clang-ssaf-format
   PRIVATE
   clangBasic
   clangScalableStaticAnalysisFrameworkCore
+  clangScalableStaticAnalysisFrameworkTool
   )
diff --git a/clang/tools/clang-ssaf-format/SSAFFormat.cpp b/clang/tools/clang-ssaf-format/SSAFFormat.cpp
index d91ff9402f7ec..4f337bff89ee1 100644
--- a/clang/tools/clang-ssaf-format/SSAFFormat.cpp
+++ b/clang/tools/clang-ssaf-format/SSAFFormat.cpp
@@ -16,18 +16,16 @@
 #include "clang/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat.h"
 #include "clang/ScalableStaticAnalysisFramework/Core/Serialization/SerializationFormatRegistry.h"
 #include "clang/ScalableStaticAnalysisFramework/SSAFForceLinker.h" // IWYU pragma: keep
+#include "clang/ScalableStaticAnalysisFramework/Tool/Utils.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/Support/CommandLine.h"
-#include "llvm/Support/DynamicLibrary.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/Format.h"
 #include "llvm/Support/FormatVariadic.h"
 #include "llvm/Support/InitLLVM.h"
 #include "llvm/Support/Path.h"
-#include "llvm/Support/Process.h"
-#include "llvm/Support/WithColor.h"
 #include "llvm/Support/raw_ostream.h"
 #include <memory>
 #include <optional>
@@ -84,87 +82,18 @@ cl::opt<bool> ListFormats("list",
                                    "analyses, then exit"),
                           cl::init(false), cl::cat(SsafFormatCategory));
 
-llvm::StringRef ToolName;
-
-void printVersion(llvm::raw_ostream &OS) { OS << ToolName << " 0.1\n"; }
-
 //===----------------------------------------------------------------------===//
 // Error Messages
 //===----------------------------------------------------------------------===//
 
-namespace ErrorMessages {
-
-constexpr const char *FailedToLoadPlugin = "failed to load plugin '{0}': {1}";
-
-constexpr const char *CannotValidateSummary =
-    "failed to validate summary '{0}': {1}";
-
-constexpr const char *ExtensionNotSupplied = "Extension not supplied";
-
-constexpr const char *NoFormatForExtension =
-    "Format not registered for extension '{0}'";
-
-constexpr const char *OutputDirectoryMissing =
-    "Parent directory does not exist";
+namespace LocalErrorMessages {
 
 constexpr const char *OutputFileAlreadyExists = "Output file already exists";
 
 constexpr const char *InputOutputSamePath =
     "Input and Output resolve to the same path";
 
-} // namespace ErrorMessages
-
-//===----------------------------------------------------------------------===//
-// Diagnostic Utilities
-//===----------------------------------------------------------------------===//
-
-[[noreturn]] void fail(const char *Msg) {
-  llvm::WithColor::error(llvm::errs(), ToolName) << Msg << "\n";
-  llvm::sys::Process::Exit(1);
-}
-
-template <typename... Ts>
-[[noreturn]] void fail(const char *Fmt, Ts &&...Args) {
-  std::string Message = llvm::formatv(Fmt, std::forward<Ts>(Args)...);
-  fail(Message.data());
-}
-
-[[noreturn]] void fail(llvm::Error Err) {
-  fail(toString(std::move(Err)).data());
-}
-
-//===----------------------------------------------------------------------===//
-// Format Registry
-//===----------------------------------------------------------------------===//
-
-// FIXME: This will be revisited after we add support for registering formats
-// with extensions.
-SerializationFormat *getFormatForExtension(llvm::StringRef Extension) {
-  static llvm::SmallVector<
-      std::pair<std::string, std::unique_ptr<SerializationFormat>>, 4>
-      ExtensionFormatList;
-
-  // Most recently used format is most likely to be reused again.
-  auto ReversedList = llvm::reverse(ExtensionFormatList);
-  auto It = llvm::find_if(ReversedList, [&](const auto &Entry) {
-    return Entry.first == Extension;
-  });
-  if (It != ReversedList.end()) {
-    return It->second.get();
-  }
-
-  if (!isFormatRegistered(Extension)) {
-    return nullptr;
-  }
-
-  auto Format = makeFormat(Extension);
-  SerializationFormat *Result = Format.get();
-  assert(Result);
-
-  ExtensionFormatList.emplace_back(Extension, std::move(Format));
-
-  return Result;
-}
+} // namespace LocalErrorMessages
 
 //===----------------------------------------------------------------------===//
 // Format Listing
@@ -295,47 +224,10 @@ void listFormats() {
   printFormats(Formats, computePrintLayout(Formats));
 }
 
-//===----------------------------------------------------------------------===//
-// Plugin Loading
-//===----------------------------------------------------------------------===//
-
-void loadPlugins() {
-  for (const auto &PluginPath : LoadPlugins) {
-    std::string ErrMsg;
-    if (llvm::sys::DynamicLibrary::LoadLibraryPermanently(PluginPath.c_str(),
-                                                          &ErrMsg)) {
-      fail(ErrorMessages::FailedToLoadPlugin, PluginPath, ErrMsg);
-    }
-  }
-}
-
 //===----------------------------------------------------------------------===//
 // Input Validation
 //===----------------------------------------------------------------------===//
 
-struct SummaryFile {
-  std::string Path;
-  SerializationFormat *Format = nullptr;
-
-  static SummaryFile fromPath(llvm::StringRef Path) {
-    llvm::StringRef Extension = path::extension(Path);
-    if (Extension.empty()) {
-      fail(ErrorMessages::CannotValidateSummary, Path,
-           ErrorMessages::ExtensionNotSupplied);
-    }
-
-    Extension = Extension.drop_front();
-    SerializationFormat *Format = getFormatForExtension(Extension);
-    if (!Format) {
-      std::string Msg =
-          llvm::formatv(ErrorMessages::NoFormatForExtension, Extension);
-      fail(ErrorMessages::CannotValidateSummary, Path, Msg);
-    }
-
-    return {Path.str(), Format};
-  }
-};
-
 struct FormatInput {
   SummaryFile InputFile;
   std::optional<SummaryFile> OutputFile;
@@ -391,12 +283,12 @@ FormatInput validateInput() {
 
     if (RealOutputPath == FI.InputFile.Path) {
       fail(ErrorMessages::CannotValidateSummary, OutputPath,
-           ErrorMessages::InputOutputSamePath);
+           LocalErrorMessages::InputOutputSamePath);
     }
 
     if (fs::exists(RealOutputPath)) {
       fail(ErrorMessages::CannotValidateSummary, OutputPath,
-           ErrorMessages::OutputFileAlreadyExists);
+           LocalErrorMessages::OutputFileAlreadyExists);
     }
 
     FI.OutputFile = SummaryFile::fromPath(RealOutputPath);
@@ -458,15 +350,12 @@ void convert(const FormatInput &FI) {
 //===----------------------------------------------------------------------===//
 
 int main(int argc, const char **argv) {
-  InitLLVM X(argc, argv);
-  // path::stem strips the .exe extension on Windows so ToolName is consistent.
-  ToolName = path::stem(argv[0]);
+  llvm::StringRef ToolHeading = "SSAF Format";
 
-  cl::HideUnrelatedOptions(SsafFormatCategory);
-  cl::SetVersionPrinter(printVersion);
-  cl::ParseCommandLineOptions(argc, argv, "SSAF Format\n");
+  InitLLVM X(argc, argv);
+  initTool(argc, argv, "0.1", SsafFormatCategory, ToolHeading);
 
-  loadPlugins();
+  loadPlugins(LoadPlugins);
 
   if (ListFormats) {
     listFormats();
diff --git a/clang/tools/clang-ssaf-linker/CMakeLists.txt b/clang/tools/clang-ssaf-linker/CMakeLists.txt
index 0f6041fb109c9..95db5ad2d3d08 100644
--- a/clang/tools/clang-ssaf-linker/CMakeLists.txt
+++ b/clang/tools/clang-ssaf-linker/CMakeLists.txt
@@ -11,4 +11,5 @@ clang_target_link_libraries(clang-ssaf-linker
   PRIVATE
   clangBasic
   clangScalableStaticAnalysisFrameworkCore
+  clangScalableStaticAnalysisFrameworkTool
   )
diff --git a/clang/tools/clang-ssaf-linker/SSAFLinker.cpp b/clang/tools/clang-ssaf-linker/SSAFLinker.cpp
index 3c57a2fe2cf98..1f595854c508d 100644
--- a/clang/tools/clang-ssaf-linker/SSAFLinker.cpp
+++ b/clang/tools/clang-ssaf-linker/SSAFLinker.cpp
@@ -14,9 +14,9 @@
 #include "clang/ScalableStaticAnalysisFramework/Core/EntityLinker/EntityLinker.h"
 #include "clang/ScalableStaticAnalysisFramework/Core/EntityLinker/TUSummaryEncoding.h"
 #include "clang/ScalableStaticAnalysisFramework/Core/Model/BuildNamespace.h"
-#include "clang/ScalableStaticAnalysisFramework/Core/Serialization/SerializationFormatRegistry.h"
 #include "clang/ScalableStaticAnalysisFramework/Core/Support/ErrorBuilder.h"
 #include "clang/ScalableStaticAnalysisFramework/SSAFForceLinker.h" // IWYU pragma: keep
+#include "clang/ScalableStaticAnalysisFramework/Tool/Utils.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/Support/CommandLine.h"
@@ -24,7 +24,6 @@
 #include "llvm/Support/FormatVariadic.h"
 #include "llvm/Support/InitLLVM.h"
 #include "llvm/Support/Path.h"
-#include "llvm/Support/Process.h"
 #include "llvm/Support/Timer.h"
 #include "llvm/Support/WithColor.h"
 #include "llvm/Support/raw_ostream.h"
@@ -63,25 +62,14 @@ cl::opt<bool> Time("time", cl::desc("Enable timing"), cl::init(false),
 // Error Messages
 //===----------------------------------------------------------------------===//
 
-namespace ErrorMessages {
-
-constexpr const char *CannotValidateSummary =
-    "failed to validate summary '{0}': {1}";
-
-constexpr const char *OutputDirectoryMissing =
-    "Parent directory does not exist";
+namespace LocalErrorMessages {
 
 constexpr const char *OutputDirectoryNotWritable =
     "Parent directory is not writable";
 
-constexpr const char *ExtensionNotSupplied = "Extension not supplied";
-
-constexpr const char *NoFormatForExtension =
-    "Format not registered for extension '{0}'";
-
 constexpr const char *LinkingSummary = "Linking summary '{0}'";
 
-} // namespace ErrorMessages
+} // namespace LocalErrorMessages
 
 //===----------------------------------------------------------------------===//
 // Diagnostic Utilities
@@ -89,23 +77,6 @@ constexpr const char *LinkingSummary = "Linking summary '{0}'";
 
 constexpr unsigned IndentationWidth = 2;
 
-llvm::StringRef ToolName;
-
-template <typename... Ts> [[noreturn]] void fail(const char *Msg) {
-  llvm::WithColor::error(llvm::errs(), ToolName) << Msg << "\n";
-  llvm::sys::Process::Exit(1);
-}
-
-template <typename... Ts>
-[[noreturn]] void fail(const char *Fmt, Ts &&...Args) {
-  std::string Message = llvm::formatv(Fmt, std::forward<Ts>(Args)...);
-  fail(Message.data());
-}
-
-template <typename... Ts> [[noreturn]] void fail(llvm::Error Err) {
-  fail(toString(std::move(Err)).data());
-}
-
 template <typename... Ts>
 void info(unsigned IndentationLevel, const char *Fmt, Ts &&...Args) {
   if (Verbose) {
@@ -115,70 +86,16 @@ void info(unsigned IndentationLevel, const char *Fmt, Ts &&...Args) {
   }
 }
 
-//===----------------------------------------------------------------------===//
-// Format Registry
-//===----------------------------------------------------------------------===//
-
-SerializationFormat *getFormatForExtension(llvm::StringRef Extension) {
-  static llvm::SmallVector<
-      std::pair<std::string, std::unique_ptr<SerializationFormat>>, 4>
-      ExtensionFormatList;
-
-  // Most recently used format is most likely to be reused again.
-  auto ReversedList = llvm::reverse(ExtensionFormatList);
-  auto It = llvm::find_if(ReversedList, [&](const auto &Entry) {
-    return Entry.first == Extension;
-  });
-  if (It != ReversedList.end()) {
-    return It->second.get();
-  }
-
-  if (!isFormatRegistered(Extension)) {
-    return nullptr;
-  }
-
-  auto Format = makeFormat(Extension);
-  SerializationFormat *Result = Format.get();
-  assert(Result);
-
-  ExtensionFormatList.emplace_back(Extension, std::move(Format));
-
-  return Result;
-}
-
 //===----------------------------------------------------------------------===//
 // Data Structures
 //===----------------------------------------------------------------------===//
 
-struct SummaryFile {
-  std::string Path;
-  SerializationFormat *Format = nullptr;
-
-  static SummaryFile fromPath(llvm::StringRef Path) {
-    llvm::StringRef Extension = path::extension(Path);
-    if (Extension.empty()) {
-      fail(ErrorMessages::CannotValidateSummary, Path,
-           ErrorMessages::ExtensionNotSupplied);
-    }
-    Extension = Extension.drop_front();
-    SerializationFormat *Format = getFormatForExtension(Extension);
-    if (!Format) {
-      std::string BadExtension =
-          llvm::formatv(ErrorMessages::NoFormatForExtension, Extension);
-      fail(ErrorMessages::CannotValidateSummary, Path, BadExtension);
-    }
-    return {Path.str(), Format};
-  }
-};
-
 struct LinkerInput {
   std::vector<SummaryFile> InputFiles;
   SummaryFile OutputFile;
   std::string LinkUnitName;
 };
 
-static void printVersion(llvm::raw_ostream &OS) { OS << ToolName << " 0.1\n"; }
-
 //===----------------------------------------------------------------------===//
 // Pipeline
 //===----------------------------------------------------------------------===//
@@ -199,7 +116,7 @@ LinkerInput validate(llvm::TimerGroup &TG) {
 
     if (fs::access(DirToCheck, fs::AccessMode::Write)) {
       fail(ErrorMessages::CannotValidateSummary, OutputPath,
-           ErrorMessages::OutputDirectoryNotWritable);
+           LocalErrorMessages::OutputDirectoryNotWritable);
     }
 
     LI.OutputFile = SummaryFile::fromPath(OutputPath);
@@ -264,7 +181,7 @@ void link(const LinkerInput &LI, llvm::TimerGroup &TG) {
 
       if (auto Err = EL.link(std::move(Summary))) {
         fail(ErrorBuilder::wrap(std::move(Err))
-                 .context(ErrorMessages::LinkingSummary, InputFile.Path)
+                 .context(LocalErrorMessages::LinkingSummary, InputFile.Path)
                  .build());
       }
     }
@@ -290,18 +207,12 @@ void link(const LinkerInput &LI, llvm::TimerGroup &TG) {
 //===----------------------------------------------------------------------===//
 
 int main(int argc, const char **argv) {
-  InitLLVM X(argc, argv);
-  // path::stem strips the .exe extension on Windows so ToolName is consistent.
-  ToolName = llvm::sys::path::stem(argv[0]);
+  llvm::StringRef ToolHeading = "SSAF Linker";
 
-  // Hide options unrelated to clang-ssaf-linker from --help output.
-  cl::HideUnrelatedOptions(SsafLinkerCategory);
-  // Register a custom version printer for the --version flag.
-  cl::SetVersionPrinter(printVersion);
-  // Parse command-line arguments and exit with an error if they are invalid.
-  cl::ParseCommandLineOptions(argc, argv, "SSAF Linker\n");
+  InitLLVM X(argc, argv);
+  initTool(argc, argv, "0.1", SsafLinkerCategory, ToolHeading);
 
-  llvm::TimerGroup LinkerTimers(ToolName, "SSAF Linker");
+  llvm::TimerGroup LinkerTimers(getToolName(), ToolHeading);
   LinkerInput LI;
 
   {

>From 54feeae6ba52dc99e9d33227edfea1bf717b9137 Mon Sep 17 00:00:00 2001
From: Aviral Goel <agoel26 at apple.com>
Date: Fri, 20 Mar 2026 09:38:01 -0700
Subject: [PATCH 2/2] Namespace

---
 .../Tool/Utils.h                              |  8 --
 .../Tool/Utils.cpp                            | 96 ++++++++++---------
 2 files changed, 51 insertions(+), 53 deletions(-)

diff --git a/clang/include/clang/ScalableStaticAnalysisFramework/Tool/Utils.h b/clang/include/clang/ScalableStaticAnalysisFramework/Tool/Utils.h
index cf515df54e631..790920d2bf711 100644
--- a/clang/include/clang/ScalableStaticAnalysisFramework/Tool/Utils.h
+++ b/clang/include/clang/ScalableStaticAnalysisFramework/Tool/Utils.h
@@ -83,14 +83,6 @@ void loadPlugins(llvm::ArrayRef<std::string> Paths);
 void initTool(int argc, const char **argv, llvm::StringRef Version,
               llvm::cl::OptionCategory &Category, llvm::StringRef ToolHeading);
 
-//===----------------------------------------------------------------------===//
-// Format Registry
-//===----------------------------------------------------------------------===//
-
-/// Returns the SerializationFormat registered for \p Extension, or nullptr if
-/// none is registered. Results are cached for the lifetime of the process.
-SerializationFormat *getFormatForExtension(llvm::StringRef Extension);
-
 //===----------------------------------------------------------------------===//
 // Data Structures
 //===----------------------------------------------------------------------===//
diff --git a/clang/lib/ScalableStaticAnalysisFramework/Tool/Utils.cpp b/clang/lib/ScalableStaticAnalysisFramework/Tool/Utils.cpp
index 9eef571a71d82..2d7fa09250e7b 100644
--- a/clang/lib/ScalableStaticAnalysisFramework/Tool/Utils.cpp
+++ b/clang/lib/ScalableStaticAnalysisFramework/Tool/Utils.cpp
@@ -21,58 +21,22 @@
 #include <memory>
 #include <string>
 
-namespace clang::ssaf {
+using namespace clang;
+using namespace ssaf;
 
 namespace path = llvm::sys::path;
 
-static llvm::StringRef ToolName;
-static llvm::StringRef ToolVersion;
+namespace {
 
-llvm::StringRef getToolName() { return ToolName; }
+llvm::StringRef ToolName;
+llvm::StringRef ToolVersion;
 
 void printVersion(llvm::raw_ostream &OS) {
   OS << ToolName << " " << ToolVersion << "\n";
 }
 
-[[noreturn]] void fail(const char *Msg) {
-  llvm::WithColor::error(llvm::errs(), ToolName) << Msg << "\n";
-  llvm::sys::Process::Exit(1);
-}
-
-[[noreturn]] void fail(llvm::Error Err) {
-  std::string Message = llvm::toString(std::move(Err));
-  fail(Message.data());
-}
-
-void loadPlugins(llvm::ArrayRef<std::string> Paths) {
-  for (const std::string &PluginPath : Paths) {
-    std::string ErrMsg;
-    if (llvm::sys::DynamicLibrary::LoadLibraryPermanently(PluginPath.c_str(),
-                                                          &ErrMsg)) {
-      fail(ErrorMessages::FailedToLoadPlugin, PluginPath, ErrMsg);
-    }
-  }
-}
-
-void initTool(int argc, const char **argv, llvm::StringRef Version,
-              llvm::cl::OptionCategory &Category, llvm::StringRef ToolHeading) {
-  // path::stem strips the .exe extension on Windows so ToolName is consistent.
-  ToolName = path::stem(argv[0]);
-
-  // Set tool version for the version printer.
-  ToolVersion = Version;
-
-  // Hide options unrelated to the tool from --help output.
-  llvm::cl::HideUnrelatedOptions(Category);
-
-  // Register a custom version printer for the --version flag.
-  llvm::cl::SetVersionPrinter(printVersion);
-
-  // Parse command-line arguments and exit with an error if they are invalid.
-  std::string Overview = (ToolHeading + "\n").str();
-  llvm::cl::ParseCommandLineOptions(argc, argv, Overview);
-}
-
+// Returns the SerializationFormat registered for \p Extension, or nullptr if
+// none is registered. Results are cached for the lifetime of the process.
 // FIXME: This will be revisited after we add support for registering formats
 // with extensions.
 SerializationFormat *getFormatForExtension(llvm::StringRef Extension) {
@@ -108,6 +72,50 @@ SerializationFormat *getFormatForExtension(llvm::StringRef Extension) {
   return Result;
 }
 
+} // namespace
+
+llvm::StringRef ssaf::getToolName() { return ToolName; }
+
+[[noreturn]] void ssaf::fail(const char *Msg) {
+  llvm::WithColor::error(llvm::errs(), ToolName) << Msg << "\n";
+  llvm::sys::Process::Exit(1);
+}
+
+[[noreturn]] void ssaf::fail(llvm::Error Err) {
+  std::string Message = llvm::toString(std::move(Err));
+  ssaf::fail(Message.data());
+}
+
+void ssaf::loadPlugins(llvm::ArrayRef<std::string> Paths) {
+  for (const std::string &PluginPath : Paths) {
+    std::string ErrMsg;
+    if (llvm::sys::DynamicLibrary::LoadLibraryPermanently(PluginPath.c_str(),
+                                                          &ErrMsg)) {
+      fail(ErrorMessages::FailedToLoadPlugin, PluginPath, ErrMsg);
+    }
+  }
+}
+
+void ssaf::initTool(int argc, const char **argv, llvm::StringRef Version,
+                    llvm::cl::OptionCategory &Category,
+                    llvm::StringRef ToolHeading) {
+  // path::stem strips the .exe extension on Windows so ToolName is consistent.
+  ToolName = path::stem(argv[0]);
+
+  // Set tool version for the version printer.
+  ToolVersion = Version;
+
+  // Hide options unrelated to the tool from --help output.
+  llvm::cl::HideUnrelatedOptions(Category);
+
+  // Register a custom version printer for the --version flag.
+  llvm::cl::SetVersionPrinter(printVersion);
+
+  // Parse command-line arguments and exit with an error if they are invalid.
+  std::string Overview = (ToolHeading + "\n").str();
+  llvm::cl::ParseCommandLineOptions(argc, argv, Overview);
+}
+
 SummaryFile SummaryFile::fromPath(llvm::StringRef Path) {
   llvm::StringRef Extension = path::extension(Path);
   if (Extension.empty()) {
@@ -125,5 +133,3 @@ SummaryFile SummaryFile::fromPath(llvm::StringRef Path) {
 
   return {Path.str(), Format};
 }
-
-} // namespace clang::ssaf



More information about the cfe-commits mailing list