https://github.com/aviralg updated https://github.com/llvm/llvm-project/pull/181765
>From a513fdb439c2245b22440d0658db936f79e1ca81 Mon Sep 17 00:00:00 2001 From: Aviral Goel <[email protected]> Date: Mon, 16 Feb 2026 17:29:25 -0800 Subject: [PATCH 1/3] Add Entity Linker algorithm and associated data structures --- .../Scalable/EntityLinker/EntityLinker.h | 65 ++++++ .../EntityLinker/EntitySummaryEncoding.h | 41 ++++ .../Scalable/EntityLinker/LUSummary.h | 56 +++++ .../Scalable/EntityLinker/LUSummaryEncoding.h | 57 ++++++ .../Scalable/EntityLinker/TUSummaryEncoding.h | 59 ++++++ .../clang/Analysis/Scalable/Model/EntityId.h | 7 +- .../Analysis/Scalable/Model/EntityIdTable.h | 5 +- .../Analysis/Scalable/Model/EntityLinkage.h | 4 +- .../Analysis/Scalable/Model/EntityName.h | 1 + .../Analysis/Scalable/Support/ErrorBuilder.h | 89 ++++++++ clang/lib/Analysis/Scalable/CMakeLists.txt | 2 + .../Scalable/EntityLinker/EntityLinker.cpp | 192 ++++++++++++++++++ .../Scalable/Serialization/JSONFormat.cpp | 97 +-------- .../Scalable/Support/ErrorBuilder.cpp | 59 ++++++ 14 files changed, 631 insertions(+), 103 deletions(-) create mode 100644 clang/include/clang/Analysis/Scalable/EntityLinker/EntityLinker.h create mode 100644 clang/include/clang/Analysis/Scalable/EntityLinker/EntitySummaryEncoding.h create mode 100644 clang/include/clang/Analysis/Scalable/EntityLinker/LUSummary.h create mode 100644 clang/include/clang/Analysis/Scalable/EntityLinker/LUSummaryEncoding.h create mode 100644 clang/include/clang/Analysis/Scalable/EntityLinker/TUSummaryEncoding.h create mode 100644 clang/include/clang/Analysis/Scalable/Support/ErrorBuilder.h create mode 100644 clang/lib/Analysis/Scalable/EntityLinker/EntityLinker.cpp create mode 100644 clang/lib/Analysis/Scalable/Support/ErrorBuilder.cpp diff --git a/clang/include/clang/Analysis/Scalable/EntityLinker/EntityLinker.h b/clang/include/clang/Analysis/Scalable/EntityLinker/EntityLinker.h new file mode 100644 index 0000000000000..b628af9d25843 --- /dev/null +++ b/clang/include/clang/Analysis/Scalable/EntityLinker/EntityLinker.h @@ -0,0 +1,65 @@ +//===- EntityLinker.h - Class for linking entities --------------*- 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 EntityLinker class that combines multiple TU summaries +// into a unified LU summary by deduplicating entities and patching summaries. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_SCALABLE_ENTITYLINKER_ENTITYLINKER_H +#define LLVM_CLANG_ANALYSIS_SCALABLE_ENTITYLINKER_ENTITYLINKER_H + +#include "clang/Analysis/Scalable/EntityLinker/LUSummaryEncoding.h" +#include "clang/Analysis/Scalable/Model/BuildNamespace.h" +#include "clang/Analysis/Scalable/Model/EntityId.h" +#include "clang/Analysis/Scalable/Model/EntityLinkage.h" +#include "clang/Analysis/Scalable/Model/EntityName.h" +#include "clang/Analysis/Scalable/Model/SummaryName.h" +#include "llvm/Support/Error.h" +#include <map> +#include <memory> +#include <vector> + +namespace clang::ssaf { + +class EntitySummaryEncoding; +class TUSummaryEncoding; + +class EntityLinker { + LUSummaryEncoding Output; + +public: + EntityLinker(NestedBuildNamespace LUNamespace) + : Output(std::move(LUNamespace)) {} + + llvm::Error link(std::unique_ptr<TUSummaryEncoding> Summary); + + const LUSummaryEncoding &getOutput() const { return Output; } + +private: + llvm::Expected<EntityId> resolve(const EntityName &OldName, + const EntityId OldId, + const EntityLinkage &EL); + + llvm::Error + merge(std::map<SummaryName, + std::map<EntityId, std::unique_ptr<EntitySummaryEncoding>>> + &InputData, + std::map<SummaryName, + std::map<EntityId, std::unique_ptr<EntitySummaryEncoding>>> + &OutputData, + const EntityId OldId, const EntityId NewId, const EntityLinkage &EL, + std::vector<EntitySummaryEncoding *> &PatchTargets); + + void patch(std::vector<EntitySummaryEncoding *> &PatchTargets, + const std::map<EntityId, EntityId> &EntityResolutionTable); +}; + +} // end namespace clang::ssaf + +#endif // LLVM_CLANG_ANALYSIS_SCALABLE_ENTITYLINKER_ENTITYLINKER_H diff --git a/clang/include/clang/Analysis/Scalable/EntityLinker/EntitySummaryEncoding.h b/clang/include/clang/Analysis/Scalable/EntityLinker/EntitySummaryEncoding.h new file mode 100644 index 0000000000000..a38dd0c895452 --- /dev/null +++ b/clang/include/clang/Analysis/Scalable/EntityLinker/EntitySummaryEncoding.h @@ -0,0 +1,41 @@ +//===- EntitySummaryEncoding.h ----------------------------------*- 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 EntitySummaryEncoding class, which represents +// EntitySummary data in an encoded, format-specific form. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_SCALABLE_ENTITYLINKER_ENTITYSUMMARYENCODING_H +#define LLVM_CLANG_ANALYSIS_SCALABLE_ENTITYLINKER_ENTITYSUMMARYENCODING_H + +#include "clang/Analysis/Scalable/Model/EntityId.h" +#include <map> + +namespace clang::ssaf { + +/// Represents EntitySummary data in its serialized, format-specific encoding. +/// +/// This abstract base class allows the entity linker to manipulate serialized +/// entity summary data without knowing the exact schema of the EntitySummary +/// subclass. The primary operation is patching EntityId references when +/// entities are merged during linking. +class EntitySummaryEncoding { +public: + virtual ~EntitySummaryEncoding() = default; + + /// Updates EntityId references in the encoded data. + /// + /// \param EntityResolutionTable Mapping from old EntityIds to new EntityIds. + virtual void + patch(const std::map<EntityId, EntityId> &EntityResolutionTable) = 0; +}; + +} // namespace clang::ssaf + +#endif // LLVM_CLANG_ANALYSIS_SCALABLE_ENTITYLINKER_ENTITYSUMMARYENCODING_H diff --git a/clang/include/clang/Analysis/Scalable/EntityLinker/LUSummary.h b/clang/include/clang/Analysis/Scalable/EntityLinker/LUSummary.h new file mode 100644 index 0000000000000..54d18d78d53bf --- /dev/null +++ b/clang/include/clang/Analysis/Scalable/EntityLinker/LUSummary.h @@ -0,0 +1,56 @@ +//===- LUSummary.h ----------------------------------------------*- 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 LUSummary class, which represents a link unit summary +// containing merged and deduplicated entity summaries from multiple TUs. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_SCALABLE_ENTITYLINKER_LUSUMMARY_H +#define LLVM_CLANG_ANALYSIS_SCALABLE_ENTITYLINKER_LUSUMMARY_H + +#include "clang/Analysis/Scalable/Model/BuildNamespace.h" +#include "clang/Analysis/Scalable/Model/EntityId.h" +#include "clang/Analysis/Scalable/Model/EntityIdTable.h" +#include "clang/Analysis/Scalable/Model/EntityLinkage.h" +#include "clang/Analysis/Scalable/Model/SummaryName.h" +#include <map> +#include <memory> + +namespace clang::ssaf { + +class EntitySummary; +class SerializationFormat; +class SummaryViewBuilder; + +/// Represents a link unit (LU) summary containing merged entity summaries. +/// +/// LUSummary is the result of linking multiple translation unit summaries +/// together. It contains deduplicated entities with their linkage information +/// and the merged entity summaries. +class LUSummary { + NestedBuildNamespace LUNamespace; + + EntityIdTable IdTable; + + std::map<EntityId, EntityLinkage> LinkageTable; + + std::map<SummaryName, std::map<EntityId, std::unique_ptr<EntitySummary>>> + Data; + +public: + LUSummary(NestedBuildNamespace LUNamespace) + : LUNamespace(std::move(LUNamespace)) {} + + friend class SerializationFormat; + friend class SummaryViewBuilder; +}; + +} // namespace clang::ssaf + +#endif // LLVM_CLANG_ANALYSIS_SCALABLE_ENTITYLINKER_LUSUMMARY_H diff --git a/clang/include/clang/Analysis/Scalable/EntityLinker/LUSummaryEncoding.h b/clang/include/clang/Analysis/Scalable/EntityLinker/LUSummaryEncoding.h new file mode 100644 index 0000000000000..39185990a9ea6 --- /dev/null +++ b/clang/include/clang/Analysis/Scalable/EntityLinker/LUSummaryEncoding.h @@ -0,0 +1,57 @@ +//===- LUSummaryEncoding.h --------------------------------------*- 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 LUSummaryEncoding class, which represents a link unit +// summary in its serialized, format-specific encoding. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_SCALABLE_ENTITYLINKER_LUSUMMARYENCODING_H +#define LLVM_CLANG_ANALYSIS_SCALABLE_ENTITYLINKER_LUSUMMARYENCODING_H + +#include "clang/Analysis/Scalable/EntityLinker/EntitySummaryEncoding.h" +#include "clang/Analysis/Scalable/Model/BuildNamespace.h" +#include "clang/Analysis/Scalable/Model/EntityId.h" +#include "clang/Analysis/Scalable/Model/EntityIdTable.h" +#include "clang/Analysis/Scalable/Model/EntityLinkage.h" +#include "clang/Analysis/Scalable/Model/SummaryName.h" +#include <map> +#include <memory> + +namespace clang::ssaf { + +class EntityLinker; +class SerializationFormat; + +/// Represents a link unit summary in its serialized encoding. +/// +/// LUSummaryEncoding holds the combined entity summary data from multiple +/// translation units in a format-specific encoding. It is produced by the +/// entity linker and contains deduplicated and patched entity summaries. +class LUSummaryEncoding { + NestedBuildNamespace LUNamespace; + + EntityIdTable IdTable; + + std::map<EntityId, EntityLinkage> LinkageTable; + + std::map<SummaryName, + std::map<EntityId, std::unique_ptr<EntitySummaryEncoding>>> + Data; + +public: + LUSummaryEncoding(NestedBuildNamespace LUNamespace) + : LUNamespace(std::move(LUNamespace)) {} + + friend class EntityLinker; + friend class SerializationFormat; +}; + +} // namespace clang::ssaf + +#endif // LLVM_CLANG_ANALYSIS_SCALABLE_ENTITYLINKER_LUSUMMARYENCODING_H diff --git a/clang/include/clang/Analysis/Scalable/EntityLinker/TUSummaryEncoding.h b/clang/include/clang/Analysis/Scalable/EntityLinker/TUSummaryEncoding.h new file mode 100644 index 0000000000000..1b42eb70d09d0 --- /dev/null +++ b/clang/include/clang/Analysis/Scalable/EntityLinker/TUSummaryEncoding.h @@ -0,0 +1,59 @@ +//===- TUSummaryEncoding.h --------------------------------------*- 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 TUSummaryEncoding class, which represents a +// translation unit summary in its serialized, format-specific encoding. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_SCALABLE_ENTITYLINKER_TUSUMMARYENCODING_H +#define LLVM_CLANG_ANALYSIS_SCALABLE_ENTITYLINKER_TUSUMMARYENCODING_H + +#include "clang/Analysis/Scalable/EntityLinker/EntitySummaryEncoding.h" +#include "clang/Analysis/Scalable/Model/BuildNamespace.h" +#include "clang/Analysis/Scalable/Model/EntityId.h" +#include "clang/Analysis/Scalable/Model/EntityIdTable.h" +#include "clang/Analysis/Scalable/Model/EntityLinkage.h" +#include "clang/Analysis/Scalable/Model/SummaryName.h" +#include <map> +#include <memory> + +namespace clang::ssaf { + +class EntityLinker; +class SerializationFormat; + +/// Represents a translation unit summary in its serialized encoding. +/// +/// TUSummaryEncoding holds entity summary data in a format-specific encoding +/// that can be manipulated by the entity linker without deserializing the +/// full EntitySummary objects. This enables efficient entity ID patching +/// during the linking process. +class TUSummaryEncoding { + /// Identifies the translation unit. + BuildNamespace TUNamespace; + + EntityIdTable IdTable; + + std::map<EntityId, EntityLinkage> LinkageTable; + + std::map<SummaryName, + std::map<EntityId, std::unique_ptr<EntitySummaryEncoding>>> + Data; + +public: + TUSummaryEncoding(BuildNamespace TUNamespace) + : TUNamespace(std::move(TUNamespace)) {} + + friend class EntityLinker; + friend class SerializationFormat; +}; + +} // namespace clang::ssaf + +#endif // LLVM_CLANG_ANALYSIS_SCALABLE_ENTITYLINKER_TUSUMMARYENCODING_H diff --git a/clang/include/clang/Analysis/Scalable/Model/EntityId.h b/clang/include/clang/Analysis/Scalable/Model/EntityId.h index e348486386cb6..231525b445ca0 100644 --- a/clang/include/clang/Analysis/Scalable/Model/EntityId.h +++ b/clang/include/clang/Analysis/Scalable/Model/EntityId.h @@ -28,9 +28,6 @@ class EntityIdTable; /// /// \see EntityIdTable class EntityId { - friend class EntityIdTable; - friend class SerializationFormat; - size_t Index; explicit EntityId(size_t Index) : Index(Index) {} @@ -41,6 +38,10 @@ class EntityId { bool operator==(const EntityId &Other) const { return Index == Other.Index; } bool operator<(const EntityId &Other) const { return Index < Other.Index; } bool operator!=(const EntityId &Other) const { return !(*this == Other); } + + friend class EntityIdTable; + friend class EntityLinker; + friend class SerializationFormat; }; } // namespace clang::ssaf diff --git a/clang/include/clang/Analysis/Scalable/Model/EntityIdTable.h b/clang/include/clang/Analysis/Scalable/Model/EntityIdTable.h index a1099c4e4d0f8..b12d3e0c0faec 100644 --- a/clang/include/clang/Analysis/Scalable/Model/EntityIdTable.h +++ b/clang/include/clang/Analysis/Scalable/Model/EntityIdTable.h @@ -21,8 +21,6 @@ namespace clang::ssaf { /// The table maps each unique EntityName to exactly one EntityId. /// Entities are never removed. class EntityIdTable { - friend class SerializationFormat; - std::map<EntityName, EntityId> Entities; public: @@ -45,6 +43,9 @@ class EntityIdTable { /// Returns the number of unique entities in the table. size_t count() const { return Entities.size(); } + + friend class EntityLinker; + friend class SerializationFormat; }; } // namespace clang::ssaf diff --git a/clang/include/clang/Analysis/Scalable/Model/EntityLinkage.h b/clang/include/clang/Analysis/Scalable/Model/EntityLinkage.h index ba5f7d3073a30..af775769dc1e4 100644 --- a/clang/include/clang/Analysis/Scalable/Model/EntityLinkage.h +++ b/clang/include/clang/Analysis/Scalable/Model/EntityLinkage.h @@ -17,8 +17,6 @@ namespace clang::ssaf { /// or external linkage, which determines its visibility and accessibility /// across translation units. class EntityLinkage { - friend class SerializationFormat; - public: enum class LinkageType { None, ///< local variables, function parameters @@ -32,6 +30,8 @@ class EntityLinkage { private: LinkageType Linkage; + + friend class SerializationFormat; }; } // namespace clang::ssaf diff --git a/clang/include/clang/Analysis/Scalable/Model/EntityName.h b/clang/include/clang/Analysis/Scalable/Model/EntityName.h index 23890ab7bea43..6bf51844f2f5b 100644 --- a/clang/include/clang/Analysis/Scalable/Model/EntityName.h +++ b/clang/include/clang/Analysis/Scalable/Model/EntityName.h @@ -47,6 +47,7 @@ class EntityName { /// \param Namespace The namespace steps to append to this entity's namespace. EntityName makeQualified(NestedBuildNamespace Namespace) const; + friend class EntityLinker; friend class LinkUnitResolution; friend class SerializationFormat; }; diff --git a/clang/include/clang/Analysis/Scalable/Support/ErrorBuilder.h b/clang/include/clang/Analysis/Scalable/Support/ErrorBuilder.h new file mode 100644 index 0000000000000..4ccda48e2391a --- /dev/null +++ b/clang/include/clang/Analysis/Scalable/Support/ErrorBuilder.h @@ -0,0 +1,89 @@ +//===- 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 <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 from 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 { +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); + + // Add context (plain string). + ErrorBuilder &context(const char *Msg); + + // 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(); +}; + +} // namespace clang::ssaf + +#endif // LLVM_CLANG_ANALYSIS_SCALABLE_SUPPORT_ERRORBUILDER_H diff --git a/clang/lib/Analysis/Scalable/CMakeLists.txt b/clang/lib/Analysis/Scalable/CMakeLists.txt index 522fc9dcf078d..8ef1625cc704b 100644 --- a/clang/lib/Analysis/Scalable/CMakeLists.txt +++ b/clang/lib/Analysis/Scalable/CMakeLists.txt @@ -4,11 +4,13 @@ set(LLVM_LINK_COMPONENTS add_clang_library(clangAnalysisScalable ASTEntityMapping.cpp + EntityLinker/EntityLinker.cpp Model/BuildNamespace.cpp Model/EntityIdTable.cpp Model/EntityName.cpp Serialization/JSONFormat.cpp Serialization/SerializationFormatRegistry.cpp + Support/ErrorBuilder.cpp TUSummary/ExtractorRegistry.cpp LINK_LIBS diff --git a/clang/lib/Analysis/Scalable/EntityLinker/EntityLinker.cpp b/clang/lib/Analysis/Scalable/EntityLinker/EntityLinker.cpp new file mode 100644 index 0000000000000..2c7344b19de55 --- /dev/null +++ b/clang/lib/Analysis/Scalable/EntityLinker/EntityLinker.cpp @@ -0,0 +1,192 @@ +//===- EntityLinker.cpp ----------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/Scalable/EntityLinker/EntityLinker.h" +#include "clang/Analysis/Scalable/EntityLinker/TUSummaryEncoding.h" +#include "clang/Analysis/Scalable/Serialization/SerializationFormat.h" +#include "clang/Analysis/Scalable/Support/ErrorBuilder.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FormatVariadic.h" + +using namespace clang::ssaf; + +//---------------------------------------------------------------------------- +// Error Message Constants +//---------------------------------------------------------------------------- + +namespace { + +namespace ErrorMessages { + +constexpr const char *EntityIdAlreadyExistsInLinkageTable = + "EntityId({0}) already exists in LU linkage table"; + +constexpr const char *FailedToMergeSummaryData = + "failed to merge summary data for TU EntityId({0}) resolved to LU " + "EntityId({1}) with linkage '{2}'"; + +constexpr const char *MissingLinkageInformation = + "missing linkage information for TU EntityId({0})"; + +constexpr const char *DuplicateEntityIdInLinking = + "duplicate TU EntityId({0}) encountered during linking"; + +constexpr const char *ResolvingEntity = + "resolving entity '{0}' (TU EntityId({1}))"; +constexpr const char *MergingSummaryData = "merging summary data"; +constexpr const char *LinkingTUSummary = "linking TU summary"; + +} // namespace ErrorMessages + +} // namespace + +static NestedBuildNamespace +resolveNamespace(const NestedBuildNamespace &LUNamespace, + const NestedBuildNamespace &EntityNamespace, + const EntityLinkage::LinkageType Linkage) { + switch (Linkage) { + case EntityLinkage::LinkageType::None: + case EntityLinkage::LinkageType::Internal: + return EntityNamespace.makeQualified(LUNamespace); + case EntityLinkage::LinkageType::External: + return NestedBuildNamespace(LUNamespace); + } + + llvm_unreachable("Unhandled EntityLinkage::LinkageType variant"); +} + +llvm::Expected<EntityId> EntityLinker::resolve(const EntityName &OldName, + const EntityId OldId, + const EntityLinkage &EL) { + NestedBuildNamespace NewNamespace = + resolveNamespace(Output.LUNamespace, OldName.Namespace, EL.getLinkage()); + + EntityName NewName(OldName.USR, OldName.Suffix, NewNamespace); + + // NewId construction will always return a fresh id for `None` and `Internal` + // linkage entities since their namespaces will be different even if their + // names clash. For `External` linkage entities with clashing names this + // function will return the id assigned at the first insertion. + EntityId NewId = Output.IdTable.getId(NewName); + + auto [It, Inserted] = Output.LinkageTable.try_emplace(NewId, EL); + if (!Inserted) { + return ErrorBuilder::create( + llvm::inconvertibleErrorCode(), + ErrorMessages::EntityIdAlreadyExistsInLinkageTable, NewId.Index) + .build(); + } + + return NewId; +} + +llvm::Error EntityLinker::merge( + std::map<SummaryName, + std::map<EntityId, std::unique_ptr<EntitySummaryEncoding>>> + &InputData, + std::map<SummaryName, + std::map<EntityId, std::unique_ptr<EntitySummaryEncoding>>> + &OutputData, + const EntityId OldId, const EntityId NewId, const EntityLinkage &EL, + std::vector<EntitySummaryEncoding *> &PatchTargets) { + for (auto &[Name, DataMap] : InputData) { + auto Iter = DataMap.find(OldId); + if (Iter == DataMap.end()) + continue; + + auto &OutputMap = OutputData[Name]; + auto Result = OutputMap.insert({NewId, std::move(Iter->second)}); + + // If insertion is successful, we will have to replace OldId with NewId in + // this EntitySummaryEncoding. + if (Result.second) { + PatchTargets.push_back(Result.first->second.get()); + } else { + switch (EL.getLinkage()) { + // Insertion should never fail for `None` and `Internal` linkage + // entities because these entities have different namespaces even if + // their names clash. + case EntityLinkage::LinkageType::None: + return ErrorBuilder::create(llvm::inconvertibleErrorCode(), + ErrorMessages::FailedToMergeSummaryData, + OldId.Index, NewId.Index, "None") + .build(); + case EntityLinkage::LinkageType::Internal: + return ErrorBuilder::create(llvm::inconvertibleErrorCode(), + ErrorMessages::FailedToMergeSummaryData, + OldId.Index, NewId.Index, "Internal") + .build(); + case EntityLinkage::LinkageType::External: + // Insertion is expected to fail for duplicate occurrences of `External` + // linkage entities. We will report these cases to help users debug + // potential ODR violations. + // TODO - issue diagnostic log for dropping data using instrumentation + // framework. + break; + } + } + } + + return llvm::Error::success(); +} + +void EntityLinker::patch( + std::vector<EntitySummaryEncoding *> &PatchTargets, + const std::map<EntityId, EntityId> &EntityResolutionTable) { + for (auto *PatchTarget : PatchTargets) { + PatchTarget->patch(EntityResolutionTable); + } +} + +llvm::Error EntityLinker::link(std::unique_ptr<TUSummaryEncoding> Summary) { + std::map<EntityId, EntityId> EntityResolutionTable; + std::vector<EntitySummaryEncoding *> PatchTargets; + + for (const auto &[OldName, OldId] : Summary->IdTable.Entities) { + + auto Iter = Summary->LinkageTable.find(OldId); + if (Iter == Summary->LinkageTable.end()) { + return ErrorBuilder::create(llvm::inconvertibleErrorCode(), + ErrorMessages::MissingLinkageInformation, + OldId.Index) + .context(ErrorMessages::LinkingTUSummary) + .build(); + } + + EntityLinkage &Linkage = Iter->second; + + llvm::Expected<EntityId> NewIdOrErr = resolve(OldName, OldId, Linkage); + if (!NewIdOrErr) + return ErrorBuilder::wrap(NewIdOrErr.takeError()) + .context(ErrorMessages::LinkingTUSummary) + .build(); + + EntityId NewId = *NewIdOrErr; + + auto Res = EntityResolutionTable.insert({OldId, NewId}); + if (!Res.second) { + return ErrorBuilder::create(llvm::inconvertibleErrorCode(), + ErrorMessages::DuplicateEntityIdInLinking, + OldId.Index) + .context(ErrorMessages::LinkingTUSummary) + .build(); + } + + if (llvm::Error Err = merge(Summary->Data, Output.Data, OldId, NewId, + Linkage, PatchTargets)) + return ErrorBuilder::wrap(std::move(Err)) + .context(ErrorMessages::MergingSummaryData) + .context(ErrorMessages::LinkingTUSummary) + .build(); + } + + patch(PatchTargets, EntityResolutionTable); + + return llvm::Error::success(); +} diff --git a/clang/lib/Analysis/Scalable/Serialization/JSONFormat.cpp b/clang/lib/Analysis/Scalable/Serialization/JSONFormat.cpp index 6f7de45e863d1..0007ddf6a275f 100644 --- a/clang/lib/Analysis/Scalable/Serialization/JSONFormat.cpp +++ b/clang/lib/Analysis/Scalable/Serialization/JSONFormat.cpp @@ -1,4 +1,5 @@ #include "clang/Analysis/Scalable/Serialization/JSONFormat.h" +#include "clang/Analysis/Scalable/Support/ErrorBuilder.h" #include "clang/Analysis/Scalable/TUSummary/TUSummary.h" #include "llvm/ADT/StringExtras.h" @@ -15,102 +16,6 @@ using Array = llvm::json::Array; using Object = llvm::json::Object; using Value = llvm::json::Value; -//---------------------------------------------------------------------------- -// 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; - bool FirstError = true; - ErrorBuilder Builder(std::make_error_code(std::errc::invalid_argument)); - - llvm::handleAllErrors(std::move(E), [&](const llvm::ErrorInfoBase &EI) { - // Capture error code from the first error only. - if (FirstError) { - EC = EI.convertToErrorCode(); - Builder.Code = EC; - FirstError = false; - } - - // Collect messages from all errors. - std::string ErrorMsg = EI.message(); - 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. - return llvm::createStringError( - llvm::join(llvm::reverse(ContextStack), "\n"), Code); - } -}; - -} // namespace - //---------------------------------------------------------------------------- // File Format Constant //---------------------------------------------------------------------------- diff --git a/clang/lib/Analysis/Scalable/Support/ErrorBuilder.cpp b/clang/lib/Analysis/Scalable/Support/ErrorBuilder.cpp new file mode 100644 index 0000000000000..ad0a013bcf2f2 --- /dev/null +++ b/clang/lib/Analysis/Scalable/Support/ErrorBuilder.cpp @@ -0,0 +1,59 @@ +//===- ErrorBuilder.cpp ----------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/Scalable/Support/ErrorBuilder.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringExtras.h" + +namespace clang::ssaf { + +ErrorBuilder 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; + bool FirstError = true; + ErrorBuilder Builder(std::make_error_code(std::errc::invalid_argument)); + + llvm::handleAllErrors(std::move(E), [&](const llvm::ErrorInfoBase &EI) { + // Capture error code from the first error only. + if (FirstError) { + EC = EI.convertToErrorCode(); + Builder.Code = EC; + FirstError = false; + } + + // Collect messages from all errors. + std::string ErrorMsg = EI.message(); + if (!ErrorMsg.empty()) { + Builder.ContextStack.push_back(std::move(ErrorMsg)); + } + }); + + return Builder; +} + +ErrorBuilder &ErrorBuilder::context(const char *Msg) { + ContextStack.push_back(Msg); + return *this; +} + +llvm::Error ErrorBuilder::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. + return llvm::createStringError(llvm::join(llvm::reverse(ContextStack), "\n"), + Code); +} + +} // namespace clang::ssaf >From 848d72a7612a881d518f0b49a391398aeb78cf68 Mon Sep 17 00:00:00 2001 From: Aviral Goel <[email protected]> Date: Mon, 16 Feb 2026 17:44:17 -0800 Subject: [PATCH 2/3] Quality Fixes --- .../Scalable/EntityLinker/EntityLinker.h | 5 ++-- .../Analysis/Scalable/Model/EntityLinkage.h | 5 ++++ clang/lib/Analysis/Scalable/CMakeLists.txt | 1 + .../Scalable/EntityLinker/EntityLinker.cpp | 29 +++++++------------ .../Analysis/Scalable/Model/EntityLinkage.cpp | 27 +++++++++++++++++ 5 files changed, 47 insertions(+), 20 deletions(-) create mode 100644 clang/lib/Analysis/Scalable/Model/EntityLinkage.cpp diff --git a/clang/include/clang/Analysis/Scalable/EntityLinker/EntityLinker.h b/clang/include/clang/Analysis/Scalable/EntityLinker/EntityLinker.h index b628af9d25843..4788f27ce24a0 100644 --- a/clang/include/clang/Analysis/Scalable/EntityLinker/EntityLinker.h +++ b/clang/include/clang/Analysis/Scalable/EntityLinker/EntityLinker.h @@ -44,7 +44,7 @@ class EntityLinker { private: llvm::Expected<EntityId> resolve(const EntityName &OldName, const EntityId OldId, - const EntityLinkage &EL); + const EntityLinkage &Linkage); llvm::Error merge(std::map<SummaryName, @@ -53,7 +53,8 @@ class EntityLinker { std::map<SummaryName, std::map<EntityId, std::unique_ptr<EntitySummaryEncoding>>> &OutputData, - const EntityId OldId, const EntityId NewId, const EntityLinkage &EL, + const EntityId OldId, const EntityId NewId, + const EntityLinkage &Linkage, std::vector<EntitySummaryEncoding *> &PatchTargets); void patch(std::vector<EntitySummaryEncoding *> &PatchTargets, diff --git a/clang/include/clang/Analysis/Scalable/Model/EntityLinkage.h b/clang/include/clang/Analysis/Scalable/Model/EntityLinkage.h index af775769dc1e4..a0014f0039f61 100644 --- a/clang/include/clang/Analysis/Scalable/Model/EntityLinkage.h +++ b/clang/include/clang/Analysis/Scalable/Model/EntityLinkage.h @@ -9,6 +9,8 @@ #ifndef LLVM_CLANG_ANALYSIS_SCALABLE_MODEL_ENTITYLINKAGE_H #define LLVM_CLANG_ANALYSIS_SCALABLE_MODEL_ENTITYLINKAGE_H +#include "llvm/ADT/StringRef.h" + namespace clang::ssaf { /// Represents the linkage properties of an entity in the program model. @@ -34,6 +36,9 @@ class EntityLinkage { friend class SerializationFormat; }; +/// Returns a string representation of the linkage type. +llvm::StringRef toString(EntityLinkage::LinkageType Linkage); + } // namespace clang::ssaf #endif // LLVM_CLANG_ANALYSIS_SCALABLE_MODEL_ENTITYLINKAGE_H diff --git a/clang/lib/Analysis/Scalable/CMakeLists.txt b/clang/lib/Analysis/Scalable/CMakeLists.txt index 8ef1625cc704b..7e4404d96bbd4 100644 --- a/clang/lib/Analysis/Scalable/CMakeLists.txt +++ b/clang/lib/Analysis/Scalable/CMakeLists.txt @@ -7,6 +7,7 @@ add_clang_library(clangAnalysisScalable EntityLinker/EntityLinker.cpp Model/BuildNamespace.cpp Model/EntityIdTable.cpp + Model/EntityLinkage.cpp Model/EntityName.cpp Serialization/JSONFormat.cpp Serialization/SerializationFormatRegistry.cpp diff --git a/clang/lib/Analysis/Scalable/EntityLinker/EntityLinker.cpp b/clang/lib/Analysis/Scalable/EntityLinker/EntityLinker.cpp index 2c7344b19de55..9b15181721566 100644 --- a/clang/lib/Analysis/Scalable/EntityLinker/EntityLinker.cpp +++ b/clang/lib/Analysis/Scalable/EntityLinker/EntityLinker.cpp @@ -8,11 +8,9 @@ #include "clang/Analysis/Scalable/EntityLinker/EntityLinker.h" #include "clang/Analysis/Scalable/EntityLinker/TUSummaryEncoding.h" -#include "clang/Analysis/Scalable/Serialization/SerializationFormat.h" #include "clang/Analysis/Scalable/Support/ErrorBuilder.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/FormatVariadic.h" using namespace clang::ssaf; @@ -37,8 +35,6 @@ constexpr const char *MissingLinkageInformation = constexpr const char *DuplicateEntityIdInLinking = "duplicate TU EntityId({0}) encountered during linking"; -constexpr const char *ResolvingEntity = - "resolving entity '{0}' (TU EntityId({1}))"; constexpr const char *MergingSummaryData = "merging summary data"; constexpr const char *LinkingTUSummary = "linking TU summary"; @@ -63,9 +59,9 @@ resolveNamespace(const NestedBuildNamespace &LUNamespace, llvm::Expected<EntityId> EntityLinker::resolve(const EntityName &OldName, const EntityId OldId, - const EntityLinkage &EL) { - NestedBuildNamespace NewNamespace = - resolveNamespace(Output.LUNamespace, OldName.Namespace, EL.getLinkage()); + const EntityLinkage &Linkage) { + NestedBuildNamespace NewNamespace = resolveNamespace( + Output.LUNamespace, OldName.Namespace, Linkage.getLinkage()); EntityName NewName(OldName.USR, OldName.Suffix, NewNamespace); @@ -75,7 +71,7 @@ llvm::Expected<EntityId> EntityLinker::resolve(const EntityName &OldName, // function will return the id assigned at the first insertion. EntityId NewId = Output.IdTable.getId(NewName); - auto [It, Inserted] = Output.LinkageTable.try_emplace(NewId, EL); + auto [It, Inserted] = Output.LinkageTable.try_emplace(NewId, Linkage); if (!Inserted) { return ErrorBuilder::create( llvm::inconvertibleErrorCode(), @@ -93,7 +89,7 @@ llvm::Error EntityLinker::merge( std::map<SummaryName, std::map<EntityId, std::unique_ptr<EntitySummaryEncoding>>> &OutputData, - const EntityId OldId, const EntityId NewId, const EntityLinkage &EL, + const EntityId OldId, const EntityId NewId, const EntityLinkage &Linkage, std::vector<EntitySummaryEncoding *> &PatchTargets) { for (auto &[Name, DataMap] : InputData) { auto Iter = DataMap.find(OldId); @@ -101,26 +97,23 @@ llvm::Error EntityLinker::merge( continue; auto &OutputMap = OutputData[Name]; - auto Result = OutputMap.insert({NewId, std::move(Iter->second)}); + auto InsertResult = OutputMap.insert({NewId, std::move(Iter->second)}); // If insertion is successful, we will have to replace OldId with NewId in // this EntitySummaryEncoding. - if (Result.second) { - PatchTargets.push_back(Result.first->second.get()); + if (InsertResult.second) { + PatchTargets.push_back(InsertResult.first->second.get()); } else { - switch (EL.getLinkage()) { + switch (Linkage.getLinkage()) { // Insertion should never fail for `None` and `Internal` linkage // entities because these entities have different namespaces even if // their names clash. case EntityLinkage::LinkageType::None: - return ErrorBuilder::create(llvm::inconvertibleErrorCode(), - ErrorMessages::FailedToMergeSummaryData, - OldId.Index, NewId.Index, "None") - .build(); case EntityLinkage::LinkageType::Internal: return ErrorBuilder::create(llvm::inconvertibleErrorCode(), ErrorMessages::FailedToMergeSummaryData, - OldId.Index, NewId.Index, "Internal") + OldId.Index, NewId.Index, + toString(Linkage.getLinkage())) .build(); case EntityLinkage::LinkageType::External: // Insertion is expected to fail for duplicate occurrences of `External` diff --git a/clang/lib/Analysis/Scalable/Model/EntityLinkage.cpp b/clang/lib/Analysis/Scalable/Model/EntityLinkage.cpp new file mode 100644 index 0000000000000..b1f50964969c3 --- /dev/null +++ b/clang/lib/Analysis/Scalable/Model/EntityLinkage.cpp @@ -0,0 +1,27 @@ +//===- EntityLinkage.cpp ----------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/Scalable/Model/EntityLinkage.h" +#include "llvm/Support/ErrorHandling.h" + +namespace clang::ssaf { + +llvm::StringRef toString(EntityLinkage::LinkageType Linkage) { + switch (Linkage) { + case EntityLinkage::LinkageType::None: + return "None"; + case EntityLinkage::LinkageType::Internal: + return "Internal"; + case EntityLinkage::LinkageType::External: + return "External"; + } + + llvm_unreachable("Unhandled EntityLinkage::LinkageType variant"); +} + +} // namespace clang::ssaf >From f8ac91011576e959f3a45e1dfb1e88084dc49a4b Mon Sep 17 00:00:00 2001 From: Aviral Goel <[email protected]> Date: Tue, 17 Feb 2026 11:38:44 -0800 Subject: [PATCH 3/3] More quality fixes --- .../Scalable/EntityLinker/EntityLinker.h | 21 ++++++++++++--- .../Scalable/EntityLinker/LUSummary.h | 6 ++--- .../Scalable/EntityLinker/LUSummaryEncoding.h | 10 ++++--- .../Scalable/EntityLinker/TUSummaryEncoding.h | 11 +++++--- .../clang/Analysis/Scalable/Model/EntityId.h | 8 +++--- .../Analysis/Scalable/Model/EntityIdTable.h | 6 ++--- .../Analysis/Scalable/Model/EntityLinkage.h | 4 +-- .../Analysis/Scalable/Model/EntityName.h | 8 +++--- .../Scalable/EntityLinker/EntityLinker.cpp | 26 ++++++++++++------- 9 files changed, 64 insertions(+), 36 deletions(-) diff --git a/clang/include/clang/Analysis/Scalable/EntityLinker/EntityLinker.h b/clang/include/clang/Analysis/Scalable/EntityLinker/EntityLinker.h index 4788f27ce24a0..c362a2f87d0f7 100644 --- a/clang/include/clang/Analysis/Scalable/EntityLinker/EntityLinker.h +++ b/clang/include/clang/Analysis/Scalable/EntityLinker/EntityLinker.h @@ -17,8 +17,6 @@ #include "clang/Analysis/Scalable/EntityLinker/LUSummaryEncoding.h" #include "clang/Analysis/Scalable/Model/BuildNamespace.h" #include "clang/Analysis/Scalable/Model/EntityId.h" -#include "clang/Analysis/Scalable/Model/EntityLinkage.h" -#include "clang/Analysis/Scalable/Model/EntityName.h" #include "clang/Analysis/Scalable/Model/SummaryName.h" #include "llvm/Support/Error.h" #include <map> @@ -27,6 +25,8 @@ namespace clang::ssaf { +class EntityLinkage; +class EntityName; class EntitySummaryEncoding; class TUSummaryEncoding; @@ -34,16 +34,31 @@ class EntityLinker { LUSummaryEncoding Output; public: + /// Constructs an EntityLinker for a link unit. + /// + /// \param LUNamespace The namespace identifying this link unit. EntityLinker(NestedBuildNamespace LUNamespace) : Output(std::move(LUNamespace)) {} + /// Links a translation unit summary into the link unit summary. + /// + /// Processes entity names, resolves namespace conflicts based on linkage, + /// deduplicates entities, and patches entity ID references in the summary + /// data. The provided TU summary is consumed by this operation. + /// + /// \param Summary The TU summary to link. Ownership is transferred. + /// \returns Error if linking fails (e.g., duplicate internal entities, + /// missing linkage information), success otherwise. llvm::Error link(std::unique_ptr<TUSummaryEncoding> Summary); + /// Returns the accumulated link unit summary. + /// + /// \returns A const reference to the linked output containing all + /// deduplicated and patched entity summaries. const LUSummaryEncoding &getOutput() const { return Output; } private: llvm::Expected<EntityId> resolve(const EntityName &OldName, - const EntityId OldId, const EntityLinkage &Linkage); llvm::Error diff --git a/clang/include/clang/Analysis/Scalable/EntityLinker/LUSummary.h b/clang/include/clang/Analysis/Scalable/EntityLinker/LUSummary.h index 54d18d78d53bf..735e569cbd4af 100644 --- a/clang/include/clang/Analysis/Scalable/EntityLinker/LUSummary.h +++ b/clang/include/clang/Analysis/Scalable/EntityLinker/LUSummary.h @@ -34,6 +34,9 @@ class SummaryViewBuilder; /// together. It contains deduplicated entities with their linkage information /// and the merged entity summaries. class LUSummary { + friend class SerializationFormat; + friend class SummaryViewBuilder; + NestedBuildNamespace LUNamespace; EntityIdTable IdTable; @@ -46,9 +49,6 @@ class LUSummary { public: LUSummary(NestedBuildNamespace LUNamespace) : LUNamespace(std::move(LUNamespace)) {} - - friend class SerializationFormat; - friend class SummaryViewBuilder; }; } // namespace clang::ssaf diff --git a/clang/include/clang/Analysis/Scalable/EntityLinker/LUSummaryEncoding.h b/clang/include/clang/Analysis/Scalable/EntityLinker/LUSummaryEncoding.h index 39185990a9ea6..196e2109471cc 100644 --- a/clang/include/clang/Analysis/Scalable/EntityLinker/LUSummaryEncoding.h +++ b/clang/include/clang/Analysis/Scalable/EntityLinker/LUSummaryEncoding.h @@ -34,12 +34,19 @@ class SerializationFormat; /// translation units in a format-specific encoding. It is produced by the /// entity linker and contains deduplicated and patched entity summaries. class LUSummaryEncoding { + friend class EntityLinker; + friend class SerializationFormat; + + /// The namespace identifying this link unit. NestedBuildNamespace LUNamespace; + /// Maps entity names to their unique identifiers within this link unit. EntityIdTable IdTable; + /// Maps entity IDs to their linkage properties (None, Internal, External). std::map<EntityId, EntityLinkage> LinkageTable; + /// Encoded summary data organized by summary type and entity ID. std::map<SummaryName, std::map<EntityId, std::unique_ptr<EntitySummaryEncoding>>> Data; @@ -47,9 +54,6 @@ class LUSummaryEncoding { public: LUSummaryEncoding(NestedBuildNamespace LUNamespace) : LUNamespace(std::move(LUNamespace)) {} - - friend class EntityLinker; - friend class SerializationFormat; }; } // namespace clang::ssaf diff --git a/clang/include/clang/Analysis/Scalable/EntityLinker/TUSummaryEncoding.h b/clang/include/clang/Analysis/Scalable/EntityLinker/TUSummaryEncoding.h index 1b42eb70d09d0..b73a58b9d2984 100644 --- a/clang/include/clang/Analysis/Scalable/EntityLinker/TUSummaryEncoding.h +++ b/clang/include/clang/Analysis/Scalable/EntityLinker/TUSummaryEncoding.h @@ -35,13 +35,19 @@ class SerializationFormat; /// full EntitySummary objects. This enables efficient entity ID patching /// during the linking process. class TUSummaryEncoding { - /// Identifies the translation unit. + friend class EntityLinker; + friend class SerializationFormat; + + /// The namespace identifying this translation unit. BuildNamespace TUNamespace; + /// Maps entity names to their unique identifiers within this TU. EntityIdTable IdTable; + /// Maps entity IDs to their linkage properties (None, Internal, External). std::map<EntityId, EntityLinkage> LinkageTable; + /// Encoded summary data organized by summary type and entity ID. std::map<SummaryName, std::map<EntityId, std::unique_ptr<EntitySummaryEncoding>>> Data; @@ -49,9 +55,6 @@ class TUSummaryEncoding { public: TUSummaryEncoding(BuildNamespace TUNamespace) : TUNamespace(std::move(TUNamespace)) {} - - friend class EntityLinker; - friend class SerializationFormat; }; } // namespace clang::ssaf diff --git a/clang/include/clang/Analysis/Scalable/Model/EntityId.h b/clang/include/clang/Analysis/Scalable/Model/EntityId.h index 231525b445ca0..e6f57adf24690 100644 --- a/clang/include/clang/Analysis/Scalable/Model/EntityId.h +++ b/clang/include/clang/Analysis/Scalable/Model/EntityId.h @@ -28,6 +28,10 @@ class EntityIdTable; /// /// \see EntityIdTable class EntityId { + friend class EntityIdTable; + friend class EntityLinker; + friend class SerializationFormat; + size_t Index; explicit EntityId(size_t Index) : Index(Index) {} @@ -38,10 +42,6 @@ class EntityId { bool operator==(const EntityId &Other) const { return Index == Other.Index; } bool operator<(const EntityId &Other) const { return Index < Other.Index; } bool operator!=(const EntityId &Other) const { return !(*this == Other); } - - friend class EntityIdTable; - friend class EntityLinker; - friend class SerializationFormat; }; } // namespace clang::ssaf diff --git a/clang/include/clang/Analysis/Scalable/Model/EntityIdTable.h b/clang/include/clang/Analysis/Scalable/Model/EntityIdTable.h index b12d3e0c0faec..e563cacb63ca4 100644 --- a/clang/include/clang/Analysis/Scalable/Model/EntityIdTable.h +++ b/clang/include/clang/Analysis/Scalable/Model/EntityIdTable.h @@ -21,6 +21,9 @@ namespace clang::ssaf { /// The table maps each unique EntityName to exactly one EntityId. /// Entities are never removed. class EntityIdTable { + friend class EntityLinker; + friend class SerializationFormat; + std::map<EntityName, EntityId> Entities; public: @@ -43,9 +46,6 @@ class EntityIdTable { /// Returns the number of unique entities in the table. size_t count() const { return Entities.size(); } - - friend class EntityLinker; - friend class SerializationFormat; }; } // namespace clang::ssaf diff --git a/clang/include/clang/Analysis/Scalable/Model/EntityLinkage.h b/clang/include/clang/Analysis/Scalable/Model/EntityLinkage.h index a0014f0039f61..4e715fc12af4c 100644 --- a/clang/include/clang/Analysis/Scalable/Model/EntityLinkage.h +++ b/clang/include/clang/Analysis/Scalable/Model/EntityLinkage.h @@ -19,6 +19,8 @@ namespace clang::ssaf { /// or external linkage, which determines its visibility and accessibility /// across translation units. class EntityLinkage { + friend class SerializationFormat; + public: enum class LinkageType { None, ///< local variables, function parameters @@ -32,8 +34,6 @@ class EntityLinkage { private: LinkageType Linkage; - - friend class SerializationFormat; }; /// Returns a string representation of the linkage type. diff --git a/clang/include/clang/Analysis/Scalable/Model/EntityName.h b/clang/include/clang/Analysis/Scalable/Model/EntityName.h index 6bf51844f2f5b..42021cfd6b610 100644 --- a/clang/include/clang/Analysis/Scalable/Model/EntityName.h +++ b/clang/include/clang/Analysis/Scalable/Model/EntityName.h @@ -25,6 +25,10 @@ namespace clang::ssaf { /// Client code should not make assumptions about the implementation details, /// such as USRs. class EntityName { + friend class EntityLinker; + friend class LinkUnitResolution; + friend class SerializationFormat; + std::string USR; llvm::SmallString<16> Suffix; NestedBuildNamespace Namespace; @@ -46,10 +50,6 @@ class EntityName { /// /// \param Namespace The namespace steps to append to this entity's namespace. EntityName makeQualified(NestedBuildNamespace Namespace) const; - - friend class EntityLinker; - friend class LinkUnitResolution; - friend class SerializationFormat; }; } // namespace clang::ssaf diff --git a/clang/lib/Analysis/Scalable/EntityLinker/EntityLinker.cpp b/clang/lib/Analysis/Scalable/EntityLinker/EntityLinker.cpp index 9b15181721566..b23c19f0936b2 100644 --- a/clang/lib/Analysis/Scalable/EntityLinker/EntityLinker.cpp +++ b/clang/lib/Analysis/Scalable/EntityLinker/EntityLinker.cpp @@ -8,9 +8,12 @@ #include "clang/Analysis/Scalable/EntityLinker/EntityLinker.h" #include "clang/Analysis/Scalable/EntityLinker/TUSummaryEncoding.h" +#include "clang/Analysis/Scalable/Model/EntityLinkage.h" +#include "clang/Analysis/Scalable/Model/EntityName.h" #include "clang/Analysis/Scalable/Support/ErrorBuilder.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" +#include <cassert> using namespace clang::ssaf; @@ -58,7 +61,6 @@ resolveNamespace(const NestedBuildNamespace &LUNamespace, } llvm::Expected<EntityId> EntityLinker::resolve(const EntityName &OldName, - const EntityId OldId, const EntityLinkage &Linkage) { NestedBuildNamespace NewNamespace = resolveNamespace( Output.LUNamespace, OldName.Namespace, Linkage.getLinkage()); @@ -71,7 +73,8 @@ llvm::Expected<EntityId> EntityLinker::resolve(const EntityName &OldName, // function will return the id assigned at the first insertion. EntityId NewId = Output.IdTable.getId(NewName); - auto [It, Inserted] = Output.LinkageTable.try_emplace(NewId, Linkage); + [[maybe_unused]] auto [It, Inserted] = + Output.LinkageTable.try_emplace(NewId, Linkage); if (!Inserted) { return ErrorBuilder::create( llvm::inconvertibleErrorCode(), @@ -93,8 +96,9 @@ llvm::Error EntityLinker::merge( std::vector<EntitySummaryEncoding *> &PatchTargets) { for (auto &[Name, DataMap] : InputData) { auto Iter = DataMap.find(OldId); - if (Iter == DataMap.end()) + if (Iter == DataMap.end()) { continue; + } auto &OutputMap = OutputData[Name]; auto InsertResult = OutputMap.insert({NewId, std::move(Iter->second)}); @@ -133,6 +137,7 @@ void EntityLinker::patch( std::vector<EntitySummaryEncoding *> &PatchTargets, const std::map<EntityId, EntityId> &EntityResolutionTable) { for (auto *PatchTarget : PatchTargets) { + assert(PatchTarget && "Patch target cannot be null"); PatchTarget->patch(EntityResolutionTable); } } @@ -142,7 +147,6 @@ llvm::Error EntityLinker::link(std::unique_ptr<TUSummaryEncoding> Summary) { std::vector<EntitySummaryEncoding *> PatchTargets; for (const auto &[OldName, OldId] : Summary->IdTable.Entities) { - auto Iter = Summary->LinkageTable.find(OldId); if (Iter == Summary->LinkageTable.end()) { return ErrorBuilder::create(llvm::inconvertibleErrorCode(), @@ -152,18 +156,19 @@ llvm::Error EntityLinker::link(std::unique_ptr<TUSummaryEncoding> Summary) { .build(); } - EntityLinkage &Linkage = Iter->second; + const EntityLinkage &Linkage = Iter->second; - llvm::Expected<EntityId> NewIdOrErr = resolve(OldName, OldId, Linkage); - if (!NewIdOrErr) + auto NewIdOrErr = resolve(OldName, Linkage); + if (!NewIdOrErr) { return ErrorBuilder::wrap(NewIdOrErr.takeError()) .context(ErrorMessages::LinkingTUSummary) .build(); + } EntityId NewId = *NewIdOrErr; - auto Res = EntityResolutionTable.insert({OldId, NewId}); - if (!Res.second) { + auto InsertResult = EntityResolutionTable.insert({OldId, NewId}); + if (!InsertResult.second) { return ErrorBuilder::create(llvm::inconvertibleErrorCode(), ErrorMessages::DuplicateEntityIdInLinking, OldId.Index) @@ -172,11 +177,12 @@ llvm::Error EntityLinker::link(std::unique_ptr<TUSummaryEncoding> Summary) { } if (llvm::Error Err = merge(Summary->Data, Output.Data, OldId, NewId, - Linkage, PatchTargets)) + Linkage, PatchTargets)) { return ErrorBuilder::wrap(std::move(Err)) .context(ErrorMessages::MergingSummaryData) .context(ErrorMessages::LinkingTUSummary) .build(); + } } patch(PatchTargets, EntityResolutionTable); _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
