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

>From 203c2b2d68812a3748245f30014aa2b9e6ae8318 Mon Sep 17 00:00:00 2001
From: Aviral Goel <[email protected]>
Date: Wed, 18 Mar 2026 22:08:00 -0700
Subject: [PATCH] Move common code out

---
 clang/tools/CMakeLists.txt                    |   1 +
 clang/tools/clang-ssaf-format/CMakeLists.txt  |   1 +
 clang/tools/clang-ssaf-format/SSAFFormat.cpp  | 131 ++----------------
 clang/tools/clang-ssaf-linker/CMakeLists.txt  |   1 +
 clang/tools/clang-ssaf-linker/SSAFLinker.cpp  | 126 +++--------------
 .../clang-ssaf-tool-common/CMakeLists.txt     |  17 +++
 .../clang-ssaf-tool-common/SSAFToolUtils.cpp  | 127 +++++++++++++++++
 .../clang-ssaf-tool-common/SSAFToolUtils.h    | 115 +++++++++++++++
 8 files changed, 290 insertions(+), 229 deletions(-)
 create mode 100644 clang/tools/clang-ssaf-tool-common/CMakeLists.txt
 create mode 100644 clang/tools/clang-ssaf-tool-common/SSAFToolUtils.cpp
 create mode 100644 clang/tools/clang-ssaf-tool-common/SSAFToolUtils.h

diff --git a/clang/tools/CMakeLists.txt b/clang/tools/CMakeLists.txt
index 891043ec31f77..b63778991e99f 100644
--- a/clang/tools/CMakeLists.txt
+++ b/clang/tools/CMakeLists.txt
@@ -17,6 +17,7 @@ add_clang_subdirectory(clang-offload-bundler)
 add_clang_subdirectory(clang-scan-deps)
 add_clang_subdirectory(clang-ssaf-format)
 add_clang_subdirectory(clang-ssaf-linker)
+add_clang_subdirectory(clang-ssaf-tool-common)
 add_clang_subdirectory(clang-sycl-linker)
 add_clang_subdirectory(clang-installapi)
 if(HAVE_CLANG_REPL_SUPPORT)
diff --git a/clang/tools/clang-ssaf-format/CMakeLists.txt 
b/clang/tools/clang-ssaf-format/CMakeLists.txt
index f64d12eb3fac0..0eba14190e4ba 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
+  clangSSAFToolCommon
   )
diff --git a/clang/tools/clang-ssaf-format/SSAFFormat.cpp 
b/clang/tools/clang-ssaf-format/SSAFFormat.cpp
index d91ff9402f7ec..0204a7188c723 100644
--- a/clang/tools/clang-ssaf-format/SSAFFormat.cpp
+++ b/clang/tools/clang-ssaf-format/SSAFFormat.cpp
@@ -11,6 +11,7 @@
 //
 
//===----------------------------------------------------------------------===//
 
+#include "SSAFToolUtils.h"
 #include 
"clang/ScalableStaticAnalysisFramework/Core/EntityLinker/LUSummaryEncoding.h"
 #include 
"clang/ScalableStaticAnalysisFramework/Core/EntityLinker/TUSummaryEncoding.h"
 #include 
"clang/ScalableStaticAnalysisFramework/Core/Serialization/JSONFormat.h"
@@ -19,16 +20,14 @@
 #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>
 #include <string>
@@ -36,6 +35,7 @@
 
 using namespace llvm;
 using namespace clang::ssaf;
+using namespace clang::ssaf::tool;
 
 namespace {
 
@@ -84,87 +84,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 +226,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 +285,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 +352,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..ed317cb0fb182 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
+  clangSSAFToolCommon
   )
diff --git a/clang/tools/clang-ssaf-linker/SSAFLinker.cpp 
b/clang/tools/clang-ssaf-linker/SSAFLinker.cpp
index 3c57a2fe2cf98..1b48060cf9795 100644
--- a/clang/tools/clang-ssaf-linker/SSAFLinker.cpp
+++ b/clang/tools/clang-ssaf-linker/SSAFLinker.cpp
@@ -11,10 +11,10 @@
 //
 
//===----------------------------------------------------------------------===//
 
+#include "SSAFToolUtils.h"
 #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 "llvm/ADT/STLExtras.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"
@@ -34,6 +33,7 @@
 
 using namespace llvm;
 using namespace clang::ssaf;
+using namespace clang::ssaf::tool;
 
 namespace fs = llvm::sys::fs;
 namespace path = llvm::sys::path;
@@ -59,53 +59,12 @@ cl::opt<bool> Verbose("verbose", cl::desc("Enable verbose 
output"),
 cl::opt<bool> Time("time", cl::desc("Enable timing"), cl::init(false),
                    cl::cat(SsafLinkerCategory));
 
-//===----------------------------------------------------------------------===//
-// Error Messages
-//===----------------------------------------------------------------------===//
-
-namespace ErrorMessages {
-
-constexpr const char *CannotValidateSummary =
-    "failed to validate summary '{0}': {1}";
-
-constexpr const char *OutputDirectoryMissing =
-    "Parent directory does not exist";
-
-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
-
 
//===----------------------------------------------------------------------===//
 // Diagnostic Utilities
 
//===----------------------------------------------------------------------===//
 
 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,74 +74,29 @@ 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
 
//===----------------------------------------------------------------------===//
 
+namespace LocalErrorMessages {
+
+constexpr const char *OutputDirectoryNotWritable =
+    "Parent directory is not writable";
+
+constexpr const char *LinkingSummary = "Linking summary '{0}'";
+
+} // namespace LocalErrorMessages
+
 LinkerInput validate(llvm::TimerGroup &TG) {
   llvm::Timer TValidate("validate", "Validate Input", TG);
   LinkerInput LI;
@@ -199,7 +113,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 +178,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 +204,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(ToolName, ToolHeading);
   LinkerInput LI;
 
   {
diff --git a/clang/tools/clang-ssaf-tool-common/CMakeLists.txt 
b/clang/tools/clang-ssaf-tool-common/CMakeLists.txt
new file mode 100644
index 0000000000000..67715b7aa7e19
--- /dev/null
+++ b/clang/tools/clang-ssaf-tool-common/CMakeLists.txt
@@ -0,0 +1,17 @@
+set(LLVM_LINK_COMPONENTS
+  Support
+  )
+
+add_clang_library(clangSSAFToolCommon
+  SSAFToolUtils.cpp
+  )
+
+clang_target_link_libraries(clangSSAFToolCommon
+  PUBLIC
+  clangBasic
+  clangScalableStaticAnalysisFrameworkCore
+  )
+
+target_include_directories(clangSSAFToolCommon
+  PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
+  )
diff --git a/clang/tools/clang-ssaf-tool-common/SSAFToolUtils.cpp 
b/clang/tools/clang-ssaf-tool-common/SSAFToolUtils.cpp
new file mode 100644
index 0000000000000..fe86b5d484a97
--- /dev/null
+++ b/clang/tools/clang-ssaf-tool-common/SSAFToolUtils.cpp
@@ -0,0 +1,127 @@
+//===- SSAFToolUtils.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 "SSAFToolUtils.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::tool {
+
+namespace path = llvm::sys::path;
+
+llvm::StringRef ToolName;
+static 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);
+}
+
+// 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::tool
diff --git a/clang/tools/clang-ssaf-tool-common/SSAFToolUtils.h 
b/clang/tools/clang-ssaf-tool-common/SSAFToolUtils.h
new file mode 100644
index 0000000000000..02eedab6eb3b1
--- /dev/null
+++ b/clang/tools/clang-ssaf-tool-common/SSAFToolUtils.h
@@ -0,0 +1,115 @@
+//===- SSAFToolUtils.h - 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
+//
+//===----------------------------------------------------------------------===//
+//
+//  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::tool namespace.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_SSAF_TOOL_COMMON_SSAFTOOLUTILS_H
+#define CLANG_SSAF_TOOL_COMMON_SSAFTOOLUTILS_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 "llvm/Support/raw_ostream.h"
+#include <string>
+
+namespace clang::ssaf::tool {
+
+//===----------------------------------------------------------------------===//
+// Tool Identity
+//===----------------------------------------------------------------------===//
+
+/// Identifies the running tool in diagnostic messages. Must be assigned in
+/// main() before any call to fail().
+extern llvm::StringRef ToolName;
+
+/// Prints "<ToolName> <ToolVersion>\n". Suitable for cl::SetVersionPrinter().
+void printVersion(llvm::raw_ostream &OS);
+
+//===----------------------------------------------------------------------===//
+// 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::tool
+
+#endif // CLANG_SSAF_TOOL_COMMON_SSAFTOOLUTILS_H

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

Reply via email to