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

Reply via email to