https://github.com/aviralg updated https://github.com/llvm/llvm-project/pull/185575
>From 8c8b55b1624250ef0dfc74ffb526e0519d7e063a Mon Sep 17 00:00:00 2001 From: Aviral Goel <[email protected]> Date: Mon, 9 Mar 2026 22:22:20 -0700 Subject: [PATCH 1/3] Add ssaf-format --- .../Scalable/Serialization/JSONFormat.h | 4 + .../Serialization/SerializationFormat.h | 7 + .../JSONFormat/JSONFormatImpl.cpp | 7 + .../Analysis/Scalable/ssaf-format/list.test | 9 + clang/test/CMakeLists.txt | 1 + clang/test/lit.cfg.py | 1 + clang/tools/CMakeLists.txt | 1 + clang/tools/ssaf-format/CMakeLists.txt | 14 + clang/tools/ssaf-format/SSAFFormat.cpp | 483 ++++++++++++++++++ .../Registries/MockSerializationFormat.cpp | 7 + .../Registries/MockSerializationFormat.h | 4 + 11 files changed, 538 insertions(+) create mode 100644 clang/test/Analysis/Scalable/ssaf-format/list.test create mode 100644 clang/tools/ssaf-format/CMakeLists.txt create mode 100644 clang/tools/ssaf-format/SSAFFormat.cpp diff --git a/clang/include/clang/Analysis/Scalable/Serialization/JSONFormat.h b/clang/include/clang/Analysis/Scalable/Serialization/JSONFormat.h index 8c7cbd39e7099..aa979b03bbd15 100644 --- a/clang/include/clang/Analysis/Scalable/Serialization/JSONFormat.h +++ b/clang/include/clang/Analysis/Scalable/Serialization/JSONFormat.h @@ -62,6 +62,10 @@ class JSONFormat final : public SerializationFormat { llvm::Error writeLUSummaryEncoding(const LUSummaryEncoding &SummaryEncoding, llvm::StringRef Path) override; + void forEachRegisteredAnalysis( + llvm::function_ref<void(llvm::StringRef Name, llvm::StringRef Desc)> + Callback) const override; + using EntityIdToJSONFn = llvm::function_ref<Object(EntityId)>; using EntityIdFromJSONFn = llvm::function_ref<llvm::Expected<EntityId>(const Object &)>; diff --git a/clang/include/clang/Analysis/Scalable/Serialization/SerializationFormat.h b/clang/include/clang/Analysis/Scalable/Serialization/SerializationFormat.h index 55e1ec7addc6c..cb545ca534ece 100644 --- a/clang/include/clang/Analysis/Scalable/Serialization/SerializationFormat.h +++ b/clang/include/clang/Analysis/Scalable/Serialization/SerializationFormat.h @@ -20,6 +20,7 @@ #include "clang/Analysis/Scalable/Model/BuildNamespace.h" #include "clang/Analysis/Scalable/Model/SummaryName.h" #include "clang/Analysis/Scalable/TUSummary/TUSummary.h" +#include "llvm/ADT/STLFunctionalExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" @@ -54,6 +55,12 @@ class SerializationFormat { writeLUSummaryEncoding(const LUSummaryEncoding &SummaryEncoding, llvm::StringRef Path) = 0; + /// Invokes \p Callback once for each analysis that has registered + /// serialization support for this format. + virtual void forEachRegisteredAnalysis( + llvm::function_ref<void(llvm::StringRef Name, llvm::StringRef Desc)> + Callback) const = 0; + protected: // Helpers providing access to implementation details of basic data structures // for efficient serialization/deserialization. diff --git a/clang/lib/Analysis/Scalable/Serialization/JSONFormat/JSONFormatImpl.cpp b/clang/lib/Analysis/Scalable/Serialization/JSONFormat/JSONFormatImpl.cpp index fa7cd8b7a346a..5cca372ee3b74 100644 --- a/clang/lib/Analysis/Scalable/Serialization/JSONFormat/JSONFormatImpl.cpp +++ b/clang/lib/Analysis/Scalable/Serialization/JSONFormat/JSONFormatImpl.cpp @@ -126,6 +126,13 @@ std::map<SummaryName, JSONFormat::FormatInfo> JSONFormat::initFormatInfos() { return FormatInfos; } +void JSONFormat::forEachRegisteredAnalysis( + llvm::function_ref<void(llvm::StringRef, llvm::StringRef)> Callback) + const { + for (const auto &Entry : llvm::Registry<FormatInfo>::entries()) + Callback(Entry.getName(), Entry.getDesc()); +} + //---------------------------------------------------------------------------- // SummaryName //---------------------------------------------------------------------------- diff --git a/clang/test/Analysis/Scalable/ssaf-format/list.test b/clang/test/Analysis/Scalable/ssaf-format/list.test new file mode 100644 index 0000000000000..b4bedcd99f2bc --- /dev/null +++ b/clang/test/Analysis/Scalable/ssaf-format/list.test @@ -0,0 +1,9 @@ +// Test ssaf-format --list output without any loaded plugins. + +// RUN: ssaf-format --list \ +// RUN: | FileCheck %s + +// CHECK: Registered serialization formats: +// CHECK-EMPTY: +// CHECK-NEXT: 1. JSON JSON serialization format +// CHECK-NEXT: Analyses: (none) diff --git a/clang/test/CMakeLists.txt b/clang/test/CMakeLists.txt index 24136256883f3..050a3fa5db5f7 100644 --- a/clang/test/CMakeLists.txt +++ b/clang/test/CMakeLists.txt @@ -107,6 +107,7 @@ list(APPEND CLANG_TEST_DEPS diagtool hmaptool ssaf-linker + ssaf-format ) if(CLANG_ENABLE_CIR) diff --git a/clang/test/lit.cfg.py b/clang/test/lit.cfg.py index bff9480509231..512afed06a973 100644 --- a/clang/test/lit.cfg.py +++ b/clang/test/lit.cfg.py @@ -143,6 +143,7 @@ unresolved="ignore", ), "ssaf-linker", + "ssaf-format", ] if config.clang_examples: diff --git a/clang/tools/CMakeLists.txt b/clang/tools/CMakeLists.txt index aa4c4c226db57..6523471776cf1 100644 --- a/clang/tools/CMakeLists.txt +++ b/clang/tools/CMakeLists.txt @@ -53,4 +53,5 @@ add_llvm_external_project(clang-tools-extra extra) add_clang_subdirectory(libclang) add_clang_subdirectory(offload-arch) +add_clang_subdirectory(ssaf-format) add_clang_subdirectory(ssaf-linker) diff --git a/clang/tools/ssaf-format/CMakeLists.txt b/clang/tools/ssaf-format/CMakeLists.txt new file mode 100644 index 0000000000000..e517c5af920ec --- /dev/null +++ b/clang/tools/ssaf-format/CMakeLists.txt @@ -0,0 +1,14 @@ +set(LLVM_LINK_COMPONENTS + Option + Support + ) + +add_clang_tool(ssaf-format + SSAFFormat.cpp + ) + +clang_target_link_libraries(ssaf-format + PRIVATE + clangAnalysisScalable + clangBasic + ) diff --git a/clang/tools/ssaf-format/SSAFFormat.cpp b/clang/tools/ssaf-format/SSAFFormat.cpp new file mode 100644 index 0000000000000..711813053bdbb --- /dev/null +++ b/clang/tools/ssaf-format/SSAFFormat.cpp @@ -0,0 +1,483 @@ +//===- SSAFFormat.cpp - SSAF Format Tool ----------------------------------===// +// +// 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 implements the SSAF format tool that validates and converts +// TU and LU summaries between registered serialization formats. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/Scalable/EntityLinker/LUSummaryEncoding.h" +#include "clang/Analysis/Scalable/EntityLinker/TUSummaryEncoding.h" +#include "clang/Analysis/Scalable/Serialization/JSONFormat.h" +#include "clang/Analysis/Scalable/Serialization/SerializationFormatRegistry.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> +#include <string> +#include <system_error> + +using namespace llvm; +using namespace clang::ssaf; + +namespace { + +namespace fs = llvm::sys::fs; +namespace path = llvm::sys::path; + +//===----------------------------------------------------------------------===// +// Summary Type +//===----------------------------------------------------------------------===// + +enum class SummaryType { TU, LU }; + +//===----------------------------------------------------------------------===// +// Command-Line Options +//===----------------------------------------------------------------------===// + +cl::OptionCategory SsafFormatCategory("ssaf-format options"); + +cl::list<std::string> LoadPlugins("load", + cl::desc("Load a plugin shared library"), + cl::value_desc("path"), + cl::cat(SsafFormatCategory)); + +// --type and the input file are required for convert/validateInput operations +// but must be optional at the cl layer so that --list can be used standalone. +cl::opt<SummaryType> Type( + "type", cl::desc("Summary type (required unless --list is given)"), + cl::values(clEnumValN(SummaryType::TU, "tu", "Translation unit summary"), + clEnumValN(SummaryType::LU, "lu", "Link unit summary")), + cl::cat(SsafFormatCategory)); + +cl::opt<std::string> InputPath(cl::Positional, cl::desc("<input file>"), + cl::cat(SsafFormatCategory)); + +cl::opt<std::string> OutputPath("o", cl::desc("Output summary path"), + cl::value_desc("path"), + cl::cat(SsafFormatCategory)); + +cl::opt<bool> UseEncoding("encoding", + cl::desc("Read and write summary encodings rather " + "than decoded summaries"), + cl::cat(SsafFormatCategory)); + +cl::opt<bool> ListFormats("list", + cl::desc("List registered serialization formats and " + "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"; + +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(); + } + + // SerializationFormats are uppercase while file extensions are lowercase. + std::string CapitalizedExtension = Extension.upper(); + + if (!isFormatRegistered(CapitalizedExtension)) { + return nullptr; + } + + auto Format = makeFormat(CapitalizedExtension); + SerializationFormat *Result = Format.get(); + assert(Result); + + ExtensionFormatList.emplace_back(Extension, std::move(Format)); + + return Result; +} + +//===----------------------------------------------------------------------===// +// Format Listing +//===----------------------------------------------------------------------===// + +constexpr size_t FormatIndent = 4; +constexpr size_t AnalysisIndent = 4; + +struct AnalysisData { + std::string Name; + std::string Desc; +}; + +struct FormatData { + std::string Name; + std::string Desc; + llvm::SmallVector<AnalysisData> Analyses; +}; + +struct PrintLayout { + size_t FormatNumWidth; + size_t MaxFormatNameWidth; + size_t FormatNameCol; + size_t AnalysisCol; + size_t AnalysisNumWidth; + size_t MaxAnalysisNameWidth; +}; + +llvm::SmallVector<FormatData> collectFormats() { + llvm::SmallVector<FormatData> Formats; + for (const auto &Entry : SerializationFormatRegistry::entries()) { + FormatData FD; + FD.Name = Entry.getName().str(); + FD.Desc = Entry.getDesc().str(); + auto Format = Entry.instantiate(); + Format->forEachRegisteredAnalysis( + [&](llvm::StringRef Name, llvm::StringRef Desc) { + FD.Analyses.push_back({Name.str(), Desc.str()}); + }); + Formats.push_back(std::move(FD)); + } + return Formats; +} + +void printAnalysis(const AnalysisData &AD, size_t AnalysisIndex, + size_t FormatIndex, const PrintLayout &Layout) { + std::string AnalysisNum = std::to_string(FormatIndex + 1) + "." + + std::to_string(AnalysisIndex + 1) + "."; + llvm::outs().indent(Layout.AnalysisCol) + << llvm::right_justify(AnalysisNum, Layout.AnalysisNumWidth) << " " + << llvm::left_justify(AD.Name, Layout.MaxAnalysisNameWidth) << " " + << AD.Desc << "\n"; +} + +void printAnalyses(const llvm::SmallVector<AnalysisData> &Analyses, + size_t FormatIndex, const PrintLayout &Layout) { + if (Analyses.empty()) { + llvm::outs().indent(Layout.FormatNameCol) << "Analyses: (none)\n"; + return; + } + + llvm::outs().indent(Layout.FormatNameCol) << "Analyses:\n"; + + for (size_t AnalysisIndex = 0; AnalysisIndex < Analyses.size(); + ++AnalysisIndex) { + printAnalysis(Analyses[AnalysisIndex], AnalysisIndex, FormatIndex, Layout); + } +} + +void printFormat(const FormatData &FD, size_t FormatIndex, + const PrintLayout &Layout) { + // Blank line before each format entry for readability. + llvm::outs() << "\n"; + + std::string FormatNum = std::to_string(FormatIndex + 1) + "."; + llvm::outs().indent(FormatIndent) + << llvm::right_justify(FormatNum, Layout.FormatNumWidth) << " " + << llvm::left_justify(FD.Name, Layout.MaxFormatNameWidth) << " " + << FD.Desc << "\n"; + + printAnalyses(FD.Analyses, FormatIndex, Layout); +} + +void printFormats(const llvm::SmallVector<FormatData> &Formats, + const PrintLayout &Layout) { + llvm::outs() << "Registered serialization formats:\n"; + for (size_t FormatIndex = 0; FormatIndex < Formats.size(); ++FormatIndex) { + printFormat(Formats[FormatIndex], FormatIndex, Layout); + } +} + +PrintLayout computePrintLayout(const llvm::SmallVector<FormatData> &Formats) { + size_t MaxFormatNameWidth = 0; + size_t MaxAnalysisCount = 0; + size_t MaxAnalysisNameWidth = 0; + for (const auto &FD : Formats) { + MaxFormatNameWidth = std::max(MaxFormatNameWidth, FD.Name.size()); + MaxAnalysisCount = std::max(MaxAnalysisCount, FD.Analyses.size()); + for (const auto &AD : FD.Analyses) { + MaxAnalysisNameWidth = std::max(MaxAnalysisNameWidth, AD.Name.size()); + } + } + + // Width of the widest format number string, e.g. "10." -> 3. + size_t FormatNumWidth = + std::to_string(Formats.size()).size() + 1; // +1 for '.' + // Width of the widest analysis number string, e.g. "10.10." -> 6. + size_t AnalysisNumWidth = std::to_string(Formats.size()).size() + 1 + + std::to_string(MaxAnalysisCount).size() + 1; + + // Where the format name starts (also where "Analyses:" is indented to). + size_t FormatNameCol = FormatIndent + FormatNumWidth + 1; + // Where the analysis number starts. + size_t AnalysisCol = FormatNameCol + AnalysisIndent; + + return { + FormatNumWidth, MaxFormatNameWidth, FormatNameCol, + AnalysisCol, AnalysisNumWidth, MaxAnalysisNameWidth, + }; +} + +void listFormats() { + llvm::SmallVector<FormatData> Formats = collectFormats(); + if (Formats.empty()) { + llvm::outs() << "No serialization formats registered.\n"; + return; + } + 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; +}; + +FormatInput validateInput() { + assert(!ListFormats); + + FormatInput FI; + + // Validate Type explicitly since we don't want to specify it if --list is + // provided. + if (!Type.getNumOccurrences()) { + fail("'--type' option is required"); + } + + // Validate the input path. + { + if (InputPath.empty()) { + fail("no input file specified"); + } + + llvm::SmallString<256> RealInputPath; + std::error_code EC = + fs::real_path(InputPath, RealInputPath, /*expand_tilde=*/true); + if (EC) { + fail(ErrorMessages::CannotValidateSummary, InputPath, EC.message()); + } + + FI.InputFile = SummaryFile::fromPath(RealInputPath); + } + + // Validate the output path. + if (!OutputPath.empty()) { + llvm::StringRef ParentDir = path::parent_path(OutputPath); + llvm::StringRef DirToCheck = ParentDir.empty() ? "." : ParentDir; + + if (!fs::exists(DirToCheck)) { + fail(ErrorMessages::CannotValidateSummary, OutputPath, + ErrorMessages::OutputDirectoryMissing); + } + + // Reconstruct the real output path from the real parent directory and the + // output filename. The output file does not exist yet so real_path cannot + // be called on the full output path directly. + llvm::SmallString<256> RealParentDir; + if (std::error_code EC = fs::real_path(DirToCheck, RealParentDir)) { + fail(ErrorMessages::CannotValidateSummary, OutputPath, EC.message()); + } + + llvm::SmallString<256> RealOutputPath = RealParentDir; + path::append(RealOutputPath, path::filename(OutputPath)); + + if (RealOutputPath == FI.InputFile.Path) { + fail(ErrorMessages::CannotValidateSummary, OutputPath, + ErrorMessages::InputOutputSamePath); + } + + if (fs::exists(RealOutputPath)) { + fail(ErrorMessages::CannotValidateSummary, OutputPath, + ErrorMessages::OutputFileAlreadyExists); + } + + FI.OutputFile = SummaryFile::fromPath(RealOutputPath); + } + return FI; +} + +//===----------------------------------------------------------------------===// +// Format Conversion +//===----------------------------------------------------------------------===// + +template <typename ReadFn, typename WriteFn> +void run(const FormatInput &FI, ReadFn Read, WriteFn Write) { + auto ExpectedResult = (FI.InputFile.Format->*Read)(FI.InputFile.Path); + if (!ExpectedResult) { + fail(ExpectedResult.takeError()); + } + + if (!FI.OutputFile) { + return; + } + + auto Err = + (FI.OutputFile->Format->*Write)(*ExpectedResult, FI.OutputFile->Path); + if (Err) { + fail(std::move(Err)); + } +} + +void convert(const FormatInput &FI) { + switch (Type) { + case SummaryType::TU: + if (UseEncoding) { + run(FI, &SerializationFormat::readTUSummaryEncoding, + &SerializationFormat::writeTUSummaryEncoding); + } else { + run(FI, &SerializationFormat::readTUSummary, + &SerializationFormat::writeTUSummary); + } + return; + case SummaryType::LU: + if (UseEncoding) { + run(FI, &SerializationFormat::readLUSummaryEncoding, + &SerializationFormat::writeLUSummaryEncoding); + } else { + run(FI, &SerializationFormat::readLUSummary, + &SerializationFormat::writeLUSummary); + } + return; + } + + llvm_unreachable("Unhandled SummaryType variant"); +} + +} // namespace + +//===----------------------------------------------------------------------===// +// Driver +//===----------------------------------------------------------------------===// + +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]); + + cl::HideUnrelatedOptions(SsafFormatCategory); + cl::SetVersionPrinter(printVersion); + cl::ParseCommandLineOptions(argc, argv, "SSAF Format\n"); + + loadPlugins(); + + initializeJSONFormat(); + + if (ListFormats) { + listFormats(); + } else { + FormatInput FI = validateInput(); + convert(FI); + } + + return 0; +} diff --git a/clang/unittests/Analysis/Scalable/Registries/MockSerializationFormat.cpp b/clang/unittests/Analysis/Scalable/Registries/MockSerializationFormat.cpp index 13c8e103768a1..3f074076b793f 100644 --- a/clang/unittests/Analysis/Scalable/Registries/MockSerializationFormat.cpp +++ b/clang/unittests/Analysis/Scalable/Registries/MockSerializationFormat.cpp @@ -44,6 +44,13 @@ MockSerializationFormat::MockSerializationFormat() { } } +void MockSerializationFormat::forEachRegisteredAnalysis( + llvm::function_ref<void(llvm::StringRef, llvm::StringRef)> Callback) + const { + for (const auto &Entry : llvm::Registry<FormatInfo>::entries()) + Callback(Entry.getName(), Entry.getDesc()); +} + llvm::Expected<TUSummary> MockSerializationFormat::readTUSummary(llvm::StringRef Path) { BuildNamespace NS(BuildNamespaceKind::CompilationUnit, "Mock.cpp"); diff --git a/clang/unittests/Analysis/Scalable/Registries/MockSerializationFormat.h b/clang/unittests/Analysis/Scalable/Registries/MockSerializationFormat.h index 06495f4a83929..d15ff27d2b26f 100644 --- a/clang/unittests/Analysis/Scalable/Registries/MockSerializationFormat.h +++ b/clang/unittests/Analysis/Scalable/Registries/MockSerializationFormat.h @@ -44,6 +44,10 @@ class MockSerializationFormat final : public SerializationFormat { llvm::Error writeLUSummaryEncoding(const LUSummaryEncoding &SummaryEncoding, llvm::StringRef Path) override; + void forEachRegisteredAnalysis( + llvm::function_ref<void(llvm::StringRef Name, llvm::StringRef Desc)> + Callback) const override; + struct SpecialFileRepresentation { std::string MockRepresentation; }; >From 8c0ed7fa982386b24fa83ccc53f1940896363f9a Mon Sep 17 00:00:00 2001 From: Aviral Goel <[email protected]> Date: Mon, 9 Mar 2026 22:36:42 -0700 Subject: [PATCH 2/3] Format --- .../Scalable/Serialization/JSONFormat/JSONFormatImpl.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/clang/lib/Analysis/Scalable/Serialization/JSONFormat/JSONFormatImpl.cpp b/clang/lib/Analysis/Scalable/Serialization/JSONFormat/JSONFormatImpl.cpp index 5cca372ee3b74..86f2aa58f766c 100644 --- a/clang/lib/Analysis/Scalable/Serialization/JSONFormat/JSONFormatImpl.cpp +++ b/clang/lib/Analysis/Scalable/Serialization/JSONFormat/JSONFormatImpl.cpp @@ -127,8 +127,7 @@ std::map<SummaryName, JSONFormat::FormatInfo> JSONFormat::initFormatInfos() { } void JSONFormat::forEachRegisteredAnalysis( - llvm::function_ref<void(llvm::StringRef, llvm::StringRef)> Callback) - const { + llvm::function_ref<void(llvm::StringRef, llvm::StringRef)> Callback) const { for (const auto &Entry : llvm::Registry<FormatInfo>::entries()) Callback(Entry.getName(), Entry.getDesc()); } >From 36f4f688621858cf2b34369cea8ac39a1a495946 Mon Sep 17 00:00:00 2001 From: Aviral Goel <[email protected]> Date: Tue, 10 Mar 2026 06:56:30 -0700 Subject: [PATCH 3/3] Format --- .../Analysis/Scalable/Registries/MockSerializationFormat.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/clang/unittests/Analysis/Scalable/Registries/MockSerializationFormat.cpp b/clang/unittests/Analysis/Scalable/Registries/MockSerializationFormat.cpp index 3f074076b793f..2302a7e04fe89 100644 --- a/clang/unittests/Analysis/Scalable/Registries/MockSerializationFormat.cpp +++ b/clang/unittests/Analysis/Scalable/Registries/MockSerializationFormat.cpp @@ -45,8 +45,7 @@ MockSerializationFormat::MockSerializationFormat() { } void MockSerializationFormat::forEachRegisteredAnalysis( - llvm::function_ref<void(llvm::StringRef, llvm::StringRef)> Callback) - const { + llvm::function_ref<void(llvm::StringRef, llvm::StringRef)> Callback) const { for (const auto &Entry : llvm::Registry<FormatInfo>::entries()) Callback(Entry.getName(), Entry.getDesc()); } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
