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

>From 08408536ac3e3d70878a13beda9ddb3df686b483 Mon Sep 17 00:00:00 2001
From: Aviral Goel <[email protected]>
Date: Mon, 23 Feb 2026 15:52:32 -0800
Subject: [PATCH 1/4] Add JSONFormat serialization and deserialization support
 for linkage table

---
 .../Scalable/Serialization/JSONFormat.h       |  17 +
 .../Scalable/Serialization/JSONFormat.cpp     | 231 ++++++-
 .../JSONFormatTest/TUSummaryTest.cpp          | 596 +++++++++++++++++-
 3 files changed, 842 insertions(+), 2 deletions(-)

diff --git a/clang/include/clang/Analysis/Scalable/Serialization/JSONFormat.h 
b/clang/include/clang/Analysis/Scalable/Serialization/JSONFormat.h
index 052aa2641dbce..25fdd07b7f469 100644
--- a/clang/include/clang/Analysis/Scalable/Serialization/JSONFormat.h
+++ b/clang/include/clang/Analysis/Scalable/Serialization/JSONFormat.h
@@ -13,12 +13,15 @@
 #ifndef CLANG_ANALYSIS_SCALABLE_SERIALIZATION_JSONFORMAT_H
 #define CLANG_ANALYSIS_SCALABLE_SERIALIZATION_JSONFORMAT_H
 
+#include "clang/Analysis/Scalable/Model/EntityLinkage.h"
 #include "clang/Analysis/Scalable/Serialization/SerializationFormat.h"
 #include "clang/Support/Compiler.h"
 #include "llvm/ADT/STLFunctionalExtras.h"
 #include "llvm/Support/JSON.h"
 #include "llvm/Support/Registry.h"
 
+#include <set>
+
 namespace clang::ssaf {
 
 class EntityIdTable;
@@ -69,6 +72,20 @@ class JSONFormat final : public SerializationFormat {
   llvm::Expected<BuildNamespaceKind>
   buildNamespaceKindFromJSON(llvm::StringRef BuildNamespaceKindStr) const;
 
+  llvm::Expected<EntityLinkage>
+  entityLinkageFromJSON(const Object &EntityLinkageObject) const;
+  Object entityLinkageToJSON(const EntityLinkage &EL) const;
+
+  llvm::Expected<std::pair<EntityId, EntityLinkage>>
+  linkageTableEntryFromJSON(const Object &LinkageTableEntryObject) const;
+  Object linkageTableEntryToJSON(EntityId EI, const EntityLinkage &EL) const;
+
+  llvm::Expected<std::map<EntityId, EntityLinkage>>
+  linkageTableFromJSON(const Array &LinkageTableArray,
+                       std::set<EntityId> EntityIds) const;
+  Array linkageTableToJSON(
+      const std::map<EntityId, EntityLinkage> &LinkageTable) const;
+
   llvm::Expected<BuildNamespace>
   buildNamespaceFromJSON(const Object &BuildNamespaceObject) const;
   Object buildNamespaceToJSON(const BuildNamespace &BN) const;
diff --git a/clang/lib/Analysis/Scalable/Serialization/JSONFormat.cpp 
b/clang/lib/Analysis/Scalable/Serialization/JSONFormat.cpp
index d6c6e5223ea0f..55243c08133c0 100644
--- a/clang/lib/Analysis/Scalable/Serialization/JSONFormat.cpp
+++ b/clang/lib/Analysis/Scalable/Serialization/JSONFormat.cpp
@@ -1,8 +1,11 @@
 #include "clang/Analysis/Scalable/Serialization/JSONFormat.h"
+#include "clang/Analysis/Scalable/Model/EntityLinkage.h"
 #include "clang/Analysis/Scalable/Support/ErrorBuilder.h"
 #include "clang/Analysis/Scalable/TUSummary/TUSummary.h"
 
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/FormatVariadic.h"
 #include "llvm/Support/JSON.h"
@@ -72,6 +75,15 @@ constexpr const char *FailedToSerializeEntitySummary =
 constexpr const char *InvalidBuildNamespaceKind =
     "invalid 'kind' BuildNamespaceKind value '{0}'";
 
+constexpr const char *InvalidEntityLinkageType =
+    "invalid 'linkage' EntityLinkage value '{0}'";
+
+constexpr const char *LinkageTableExtraId =
+    "linkage_table contains EntityId '{0}' not present in id_table";
+
+constexpr const char *LinkageTableMissingId =
+    "linkage_table is missing EntityId '{0}' present in id_table";
+
 } // namespace ErrorMessages
 
 } // namespace
@@ -234,7 +246,195 @@ llvm::StringRef 
buildNamespaceKindToJSON(BuildNamespaceKind BNK) {
 } // namespace
 
 //----------------------------------------------------------------------------
-// BuildNamespace
+// EntityLinkageType
+//----------------------------------------------------------------------------
+
+namespace {
+
+std::optional<EntityLinkage::LinkageType>
+parseEntityLinkageType(llvm::StringRef S) {
+  if (S == "none")
+    return EntityLinkage::LinkageType::None;
+  if (S == "internal")
+    return EntityLinkage::LinkageType::Internal;
+  if (S == "external")
+    return EntityLinkage::LinkageType::External;
+  return std::nullopt;
+}
+
+llvm::StringRef entityLinkageTypeToJSON(EntityLinkage::LinkageType LT) {
+  switch (LT) {
+  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
+
+//----------------------------------------------------------------------------
+// EntityLinkage
+//----------------------------------------------------------------------------
+
+llvm::Expected<EntityLinkage>
+JSONFormat::entityLinkageFromJSON(const Object &EntityLinkageObject) const {
+  auto OptLinkageStr = EntityLinkageObject.getString("type");
+  if (!OptLinkageStr) {
+    return ErrorBuilder::create(std::errc::invalid_argument,
+                                ErrorMessages::FailedToReadObjectAtField,
+                                "EntityLinkageType", "type", "string")
+        .build();
+  }
+
+  auto OptLinkageType = parseEntityLinkageType(*OptLinkageStr);
+  if (!OptLinkageType) {
+    return ErrorBuilder::create(std::errc::invalid_argument,
+                                ErrorMessages::InvalidEntityLinkageType,
+                                *OptLinkageStr)
+        .build();
+  }
+
+  return EntityLinkage(*OptLinkageType);
+}
+
+Object JSONFormat::entityLinkageToJSON(const EntityLinkage &EL) const {
+  Object Result;
+  Result["type"] = entityLinkageTypeToJSON(getLinkage(EL));
+  return Result;
+}
+
+//----------------------------------------------------------------------------
+// LinkageTableEntry
+//----------------------------------------------------------------------------
+
+llvm::Expected<std::pair<EntityId, EntityLinkage>>
+JSONFormat::linkageTableEntryFromJSON(
+    const Object &LinkageTableEntryObject) const {
+  const Value *EntityIdIntValue = LinkageTableEntryObject.get("id");
+  if (!EntityIdIntValue) {
+    return ErrorBuilder::create(std::errc::invalid_argument,
+                                ErrorMessages::FailedToReadObjectAtField,
+                                "EntityId", "id",
+                                "number (unsigned 64-bit integer)")
+        .build();
+  }
+
+  const std::optional<uint64_t> OptEntityIdInt =
+      EntityIdIntValue->getAsUINT64();
+  if (!OptEntityIdInt) {
+    return ErrorBuilder::create(std::errc::invalid_argument,
+                                ErrorMessages::FailedToReadObjectAtField,
+                                "EntityId", "id",
+                                "number (unsigned 64-bit integer)")
+        .build();
+  }
+
+  EntityId EI = entityIdFromJSON(*OptEntityIdInt);
+
+  const Object *OptEntityLinkageObject =
+      LinkageTableEntryObject.getObject("linkage");
+  if (!OptEntityLinkageObject) {
+    return ErrorBuilder::create(std::errc::invalid_argument,
+                                ErrorMessages::FailedToReadObjectAtField,
+                                "EntityLinkage", "linkage", "object")
+        .build();
+  }
+
+  auto ExpectedEntityLinkage = entityLinkageFromJSON(*OptEntityLinkageObject);
+  if (!ExpectedEntityLinkage) {
+    return ErrorBuilder::wrap(ExpectedEntityLinkage.takeError())
+        .context(ErrorMessages::ReadingFromField, "EntityLinkage", "linkage")
+        .build();
+  }
+
+  return std::make_pair(std::move(EI), std::move(*ExpectedEntityLinkage));
+}
+
+Object JSONFormat::linkageTableEntryToJSON(EntityId EI,
+                                           const EntityLinkage &EL) const {
+  Object Entry;
+  Entry["id"] = entityIdToJSON(EI);
+  Entry["linkage"] = entityLinkageToJSON(EL);
+  return Entry;
+}
+
+//----------------------------------------------------------------------------
+// LinkageTable
+//----------------------------------------------------------------------------
+
+llvm::Expected<std::map<EntityId, EntityLinkage>>
+JSONFormat::linkageTableFromJSON(const Array &LinkageTableArray,
+                                 std::set<EntityId> EntityIds) const {
+  std::map<EntityId, EntityLinkage> LinkageTable;
+
+  for (const auto &[Index, LinkageTableEntryValue] :
+       llvm::enumerate(LinkageTableArray)) {
+
+    const Object *OptLinkageTableEntryObject =
+        LinkageTableEntryValue.getAsObject();
+    if (!OptLinkageTableEntryObject) {
+      return ErrorBuilder::create(std::errc::invalid_argument,
+                                  ErrorMessages::FailedToReadObjectAtIndex,
+                                  "LinkageTable entry", Index, "object")
+          .build();
+    }
+
+    auto ExpectedLinkageTableEntry =
+        linkageTableEntryFromJSON(*OptLinkageTableEntryObject);
+    if (!ExpectedLinkageTableEntry)
+      return ErrorBuilder::wrap(ExpectedLinkageTableEntry.takeError())
+          .context(ErrorMessages::ReadingFromIndex, "LinkageTable entry", 
Index)
+          .build();
+
+    const EntityId EI = ExpectedLinkageTableEntry->first;
+
+    auto [It, Inserted] =
+        LinkageTable.insert(std::move(*ExpectedLinkageTableEntry));
+    if (!Inserted) {
+      return ErrorBuilder::create(std::errc::invalid_argument,
+                                  ErrorMessages::FailedInsertionOnDuplication,
+                                  "LinkageTable entry", Index, "EntityId",
+                                  getIndex(It->first))
+          .build();
+    }
+
+    if (EntityIds.erase(EI) == 0) {
+      return ErrorBuilder::create(std::errc::invalid_argument,
+                                  ErrorMessages::LinkageTableExtraId,
+                                  getIndex(EI))
+          .context(ErrorMessages::ReadingFromIndex, "LinkageTable entry", 
Index)
+          .build();
+    }
+  }
+
+  if (!EntityIds.empty()) {
+    return ErrorBuilder::create(std::errc::invalid_argument,
+                                ErrorMessages::LinkageTableMissingId,
+                                getIndex(*EntityIds.begin()))
+        .build();
+  }
+
+  return LinkageTable;
+}
+
+Array JSONFormat::linkageTableToJSON(
+    const std::map<EntityId, EntityLinkage> &LinkageTable) const {
+  Array Result;
+  Result.reserve(LinkageTable.size());
+
+  for (const auto &[EI, EL] : LinkageTable) {
+    Result.push_back(linkageTableEntryToJSON(EI, EL));
+  }
+
+  return Result;
+}
+
+//----------------------------------------------------------------------------
+// NestedBuildNamespace
 //----------------------------------------------------------------------------
 
 llvm::Expected<BuildNamespace>
@@ -840,6 +1040,33 @@ llvm::Expected<TUSummary> 
JSONFormat::readTUSummary(llvm::StringRef Path) {
     getIdTable(Summary) = std::move(*ExpectedIdTable);
   }
 
+  {
+    const Array *LinkageTableArray = RootObject.getArray("linkage_table");
+    if (!LinkageTableArray) {
+      return ErrorBuilder::create(std::errc::invalid_argument,
+                                  ErrorMessages::FailedToReadObjectAtField,
+                                  "LinkageTable", "linkage_table", "array")
+          .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
+          .build();
+    }
+
+    auto EntityIdRange =
+        llvm::make_second_range(getEntities(getIdTable(Summary)));
+    std::set<EntityId> EntityIds(EntityIdRange.begin(), EntityIdRange.end());
+
+    auto ExpectedLinkageTable =
+        linkageTableFromJSON(*LinkageTableArray, std::move(EntityIds));
+    if (!ExpectedLinkageTable) {
+      return ErrorBuilder::wrap(ExpectedLinkageTable.takeError())
+          .context(ErrorMessages::ReadingFromField, "LinkageTable",
+                   "linkage_table")
+          .context(ErrorMessages::ReadingFromFile, "TUSummary", Path)
+          .build();
+    }
+
+    getLinkageTable(Summary) = std::move(*ExpectedLinkageTable);
+  }
+
   {
     const Array *SummaryDataArray = RootObject.getArray("data");
     if (!SummaryDataArray) {
@@ -874,6 +1101,8 @@ llvm::Error JSONFormat::writeTUSummary(const TUSummary &S,
 
   RootObject["id_table"] = entityIdTableToJSON(getIdTable(S));
 
+  RootObject["linkage_table"] = linkageTableToJSON(getLinkageTable(S));
+
   auto ExpectedDataObject = summaryDataMapToJSON(getData(S));
   if (!ExpectedDataObject) {
     return ErrorBuilder::wrap(ExpectedDataObject.takeError())
diff --git 
a/clang/unittests/Analysis/Scalable/Serialization/JSONFormatTest/TUSummaryTest.cpp
 
b/clang/unittests/Analysis/Scalable/Serialization/JSONFormatTest/TUSummaryTest.cpp
index 2cdbec9675662..1fb9a966217c8 100644
--- 
a/clang/unittests/Analysis/Scalable/Serialization/JSONFormatTest/TUSummaryTest.cpp
+++ 
b/clang/unittests/Analysis/Scalable/Serialization/JSONFormatTest/TUSummaryTest.cpp
@@ -312,6 +312,7 @@ TEST_F(JSONFormatTUSummaryTest, NoReadPermission) {
       "name": "test.cpp"
     },
     "id_table": [],
+    "linkage_table": [],
     "data": []
   })",
                                     FileName);
@@ -349,6 +350,286 @@ TEST_F(JSONFormatTUSummaryTest, NotObject) {
                                       HasSubstr("expected JSON object"))));
 }
 
+// ============================================================================
+// JSONFormat::entityLinkageFromJSON() Error Tests
+// ============================================================================
+
+TEST_F(JSONFormatTUSummaryTest, LinkageTableEntryLinkageMissingType) {
+  auto Result = readTUSummaryFromString(R"({
+    "tu_namespace": {
+      "kind": "compilation_unit",
+      "name": "test.cpp"
+    },
+    "id_table": [],
+    "linkage_table": [
+      {
+        "id": 0,
+        "linkage": {}
+      }
+    ],
+    "data": []
+  })");
+
+  EXPECT_THAT_EXPECTED(
+      Result,
+      FailedWithMessage(
+          AllOf(HasSubstr("reading TUSummary from file"),
+                HasSubstr("reading LinkageTable from field 'linkage_table'"),
+                HasSubstr("reading LinkageTable entry from index '0'"),
+                HasSubstr("reading EntityLinkage from field 'linkage'"),
+                HasSubstr("failed to read EntityLinkageType from field 
'type'"),
+                HasSubstr("expected JSON string"))));
+}
+
+TEST_F(JSONFormatTUSummaryTest, LinkageTableEntryLinkageInvalidType) {
+  auto Result = readTUSummaryFromString(R"({
+    "tu_namespace": {
+      "kind": "compilation_unit",
+      "name": "test.cpp"
+    },
+    "id_table": [],
+    "linkage_table": [
+      {
+        "id": 0,
+        "linkage": { "type": "invalid_type" }
+      }
+    ],
+    "data": []
+  })");
+
+  EXPECT_THAT_EXPECTED(
+      Result,
+      FailedWithMessage(AllOf(
+          HasSubstr("reading TUSummary from file"),
+          HasSubstr("reading LinkageTable from field 'linkage_table'"),
+          HasSubstr("reading LinkageTable entry from index '0'"),
+          HasSubstr("reading EntityLinkage from field 'linkage'"),
+          HasSubstr("invalid 'linkage' EntityLinkage value 'invalid_type'"))));
+}
+
+// ============================================================================
+// JSONFormat::linkageTableEntryFromJSON() Error Tests
+// ============================================================================
+
+TEST_F(JSONFormatTUSummaryTest, LinkageTableEntryMissingId) {
+  auto Result = readTUSummaryFromString(R"({
+    "tu_namespace": {
+      "kind": "compilation_unit",
+      "name": "test.cpp"
+    },
+    "id_table": [],
+    "linkage_table": [
+      {
+        "linkage": { "type": "external" }
+      }
+    ],
+    "data": []
+  })");
+
+  EXPECT_THAT_EXPECTED(
+      Result,
+      FailedWithMessage(
+          AllOf(HasSubstr("reading TUSummary from file"),
+                HasSubstr("reading LinkageTable from field 'linkage_table'"),
+                HasSubstr("reading LinkageTable entry from index '0'"),
+                HasSubstr("failed to read EntityId from field 'id'"),
+                HasSubstr("expected JSON number (unsigned 64-bit integer)"))));
+}
+
+TEST_F(JSONFormatTUSummaryTest, LinkageTableEntryIdNotUInt64) {
+  auto Result = readTUSummaryFromString(R"({
+    "tu_namespace": {
+      "kind": "compilation_unit",
+      "name": "test.cpp"
+    },
+    "id_table": [],
+    "linkage_table": [
+      {
+        "id": "not_a_number",
+        "linkage": { "type": "external" }
+      }
+    ],
+    "data": []
+  })");
+
+  EXPECT_THAT_EXPECTED(
+      Result,
+      FailedWithMessage(
+          AllOf(HasSubstr("reading TUSummary from file"),
+                HasSubstr("reading LinkageTable from field 'linkage_table'"),
+                HasSubstr("reading LinkageTable entry from index '0'"),
+                HasSubstr("failed to read EntityId from field 'id'"),
+                HasSubstr("expected JSON number (unsigned 64-bit integer)"))));
+}
+
+TEST_F(JSONFormatTUSummaryTest, LinkageTableEntryMissingLinkage) {
+  auto Result = readTUSummaryFromString(R"({
+    "tu_namespace": {
+      "kind": "compilation_unit",
+      "name": "test.cpp"
+    },
+    "id_table": [],
+    "linkage_table": [
+      {
+        "id": 0
+      }
+    ],
+    "data": []
+  })");
+
+  EXPECT_THAT_EXPECTED(
+      Result,
+      FailedWithMessage(
+          AllOf(HasSubstr("reading TUSummary from file"),
+                HasSubstr("reading LinkageTable from field 'linkage_table'"),
+                HasSubstr("reading LinkageTable entry from index '0'"),
+                HasSubstr("failed to read EntityLinkage from field 'linkage'"),
+                HasSubstr("expected JSON object"))));
+}
+
+// ============================================================================
+// JSONFormat::linkageTableFromJSON() Error Tests
+// ============================================================================
+
+TEST_F(JSONFormatTUSummaryTest, LinkageTableNotArray) {
+  auto Result = readTUSummaryFromString(R"({
+    "tu_namespace": {
+      "kind": "compilation_unit",
+      "name": "test.cpp"
+    },
+    "id_table": [],
+    "linkage_table": {},
+    "data": []
+  })");
+
+  EXPECT_THAT_EXPECTED(
+      Result,
+      FailedWithMessage(AllOf(
+          HasSubstr("reading TUSummary from file"),
+          HasSubstr("failed to read LinkageTable from field 'linkage_table'"),
+          HasSubstr("expected JSON array"))));
+}
+
+TEST_F(JSONFormatTUSummaryTest, LinkageTableElementNotObject) {
+  auto Result = readTUSummaryFromString(R"({
+    "tu_namespace": {
+      "kind": "compilation_unit",
+      "name": "test.cpp"
+    },
+    "id_table": [],
+    "linkage_table": ["invalid"],
+    "data": []
+  })");
+
+  EXPECT_THAT_EXPECTED(
+      Result, FailedWithMessage(AllOf(
+                  HasSubstr("reading TUSummary from file"),
+                  HasSubstr("reading LinkageTable from field 'linkage_table'"),
+                  HasSubstr("failed to read LinkageTable entry from index 
'0'"),
+                  HasSubstr("expected JSON object"))));
+}
+
+TEST_F(JSONFormatTUSummaryTest, LinkageTableExtraId) {
+  auto Result = readTUSummaryFromString(R"({
+    "tu_namespace": {
+      "kind": "compilation_unit",
+      "name": "test.cpp"
+    },
+    "id_table": [],
+    "linkage_table": [
+      {
+        "id": 0,
+        "linkage": { "type": "external" }
+      }
+    ],
+    "data": []
+  })");
+
+  EXPECT_THAT_EXPECTED(
+      Result,
+      FailedWithMessage(AllOf(
+          HasSubstr("reading TUSummary from file"),
+          HasSubstr("reading LinkageTable from field 'linkage_table'"),
+          HasSubstr("reading LinkageTable entry from index '0'"),
+          HasSubstr(
+              "linkage_table contains EntityId '0' not present in 
id_table"))));
+}
+
+TEST_F(JSONFormatTUSummaryTest, LinkageTableMissingId) {
+  auto Result = readTUSummaryFromString(R"({
+    "tu_namespace": {
+      "kind": "compilation_unit",
+      "name": "test.cpp"
+    },
+    "id_table": [
+      {
+        "id": 0,
+        "name": {
+          "usr": "c:@F@foo",
+          "suffix": "",
+          "namespace": [
+            {
+              "kind": "compilation_unit",
+              "name": "test.cpp"
+            }
+          ]
+        }
+      }
+    ],
+    "linkage_table": [],
+    "data": []
+  })");
+
+  EXPECT_THAT_EXPECTED(
+      Result,
+      FailedWithMessage(AllOf(
+          HasSubstr("reading TUSummary from file"),
+          HasSubstr(
+              "linkage_table is missing EntityId '0' present in id_table"))));
+}
+
+TEST_F(JSONFormatTUSummaryTest, LinkageTableDuplicateId) {
+  auto Result = readTUSummaryFromString(R"({
+    "tu_namespace": {
+      "kind": "compilation_unit",
+      "name": "test.cpp"
+    },
+    "id_table": [
+      {
+        "id": 0,
+        "name": {
+          "usr": "c:@F@foo",
+          "suffix": "",
+          "namespace": [
+            {
+              "kind": "compilation_unit",
+              "name": "test.cpp"
+            }
+          ]
+        }
+      }
+    ],
+    "linkage_table": [
+      {
+        "id": 0,
+        "linkage": { "type": "external" }
+      },
+      {
+        "id": 0,
+        "linkage": { "type": "internal" }
+      }
+    ],
+    "data": []
+  })");
+
+  EXPECT_THAT_EXPECTED(
+      Result, FailedWithMessage(AllOf(
+                  HasSubstr("reading TUSummary from file"),
+                  HasSubstr("reading LinkageTable from field 'linkage_table'"),
+                  HasSubstr("failed to insert LinkageTable entry at index 
'1'"),
+                  HasSubstr("encountered duplicate EntityId '0'"))));
+}
+
 // ============================================================================
 // JSONFormat::buildNamespaceKindFromJSON() Error Tests
 // ============================================================================
@@ -360,6 +641,7 @@ TEST_F(JSONFormatTUSummaryTest, InvalidKind) {
       "name": "test.cpp"
     },
     "id_table": [],
+    "linkage_table": [],
     "data": []
   })");
 
@@ -383,6 +665,7 @@ TEST_F(JSONFormatTUSummaryTest, MissingKind) {
       "name": "test.cpp"
     },
     "id_table": [],
+    "linkage_table": [],
     "data": []
   })");
 
@@ -401,6 +684,7 @@ TEST_F(JSONFormatTUSummaryTest, MissingName) {
       "kind": "compilation_unit"
     },
     "id_table": [],
+    "linkage_table": [],
     "data": []
   })");
 
@@ -433,6 +717,12 @@ TEST_F(JSONFormatTUSummaryTest, NamespaceElementNotObject) 
{
         }
       }
     ],
+    "linkage_table": [
+      {
+        "id": 0,
+        "linkage": { "type": "none" }
+      }
+    ],
     "data": []
   })");
 
@@ -468,6 +758,12 @@ TEST_F(JSONFormatTUSummaryTest, 
NamespaceElementMissingKind) {
         }
       }
     ],
+    "linkage_table": [
+      {
+        "id": 0,
+        "linkage": { "type": "internal" }
+      }
+    ],
     "data": []
   })");
 
@@ -505,6 +801,12 @@ TEST_F(JSONFormatTUSummaryTest, 
NamespaceElementInvalidKind) {
         }
       }
     ],
+    "linkage_table": [
+      {
+        "id": 0,
+        "linkage": { "type": "external" }
+      }
+    ],
     "data": []
   })");
 
@@ -542,6 +844,12 @@ TEST_F(JSONFormatTUSummaryTest, 
NamespaceElementMissingName) {
         }
       }
     ],
+    "linkage_table": [
+      {
+        "id": 0,
+        "linkage": { "type": "none" }
+      }
+    ],
     "data": []
   })");
 
@@ -577,6 +885,12 @@ TEST_F(JSONFormatTUSummaryTest, EntityNameMissingUSR) {
         }
       }
     ],
+    "linkage_table": [
+      {
+        "id": 0,
+        "linkage": { "type": "internal" }
+      }
+    ],
     "data": []
   })");
 
@@ -605,6 +919,12 @@ TEST_F(JSONFormatTUSummaryTest, EntityNameMissingSuffix) {
         }
       }
     ],
+    "linkage_table": [
+      {
+        "id": 0,
+        "linkage": { "type": "external" }
+      }
+    ],
     "data": []
   })");
 
@@ -633,6 +953,12 @@ TEST_F(JSONFormatTUSummaryTest, 
EntityNameMissingNamespace) {
         }
       }
     ],
+    "linkage_table": [
+      {
+        "id": 0,
+        "linkage": { "type": "none" }
+      }
+    ],
     "data": []
   })");
 
@@ -667,6 +993,7 @@ TEST_F(JSONFormatTUSummaryTest, IDTableEntryMissingID) {
         }
       }
     ],
+    "linkage_table": [],
     "data": []
   })");
 
@@ -691,6 +1018,12 @@ TEST_F(JSONFormatTUSummaryTest, IDTableEntryMissingName) {
         "id": 0
       }
     ],
+    "linkage_table": [
+      {
+        "id": 0,
+        "linkage": { "type": "none" }
+      }
+    ],
     "data": []
   })");
 
@@ -719,6 +1052,7 @@ TEST_F(JSONFormatTUSummaryTest, IDTableEntryIDNotUInt64) {
         }
       }
     ],
+    "linkage_table": [],
     "data": []
   })");
 
@@ -743,6 +1077,7 @@ TEST_F(JSONFormatTUSummaryTest, IDTableNotArray) {
       "name": "test.cpp"
     },
     "id_table": {},
+    "linkage_table": [],
     "data": []
   })");
 
@@ -760,6 +1095,7 @@ TEST_F(JSONFormatTUSummaryTest, IDTableElementNotObject) {
       "name": "test.cpp"
     },
     "id_table": [123],
+    "linkage_table": [],
     "data": []
   })");
 
@@ -806,6 +1142,16 @@ TEST_F(JSONFormatTUSummaryTest, DuplicateEntity) {
         }
       }
     ],
+    "linkage_table": [
+      {
+        "id": 0,
+        "linkage": { "type": "none" }
+      },
+      {
+        "id": 1,
+        "linkage": { "type": "none" }
+      }
+    ],
     "data": []
   })");
 
@@ -829,6 +1175,7 @@ TEST_F(JSONFormatTUSummaryTest, EntitySummaryNoFormatInfo) 
{
       "name": "test.cpp"
     },
     "id_table": [],
+    "linkage_table": [],
     "data": [
       {
         "summary_name": "unknown_summary_type",
@@ -868,6 +1215,7 @@ TEST_F(JSONFormatTUSummaryTest,
       "name": "test.cpp"
     },
     "id_table": [],
+    "linkage_table": [],
     "data": [
       {
         "summary_name": "PairsEntitySummaryForJSONFormatTest",
@@ -901,6 +1249,7 @@ TEST_F(JSONFormatTUSummaryTest,
       "name": "test.cpp"
     },
     "id_table": [],
+    "linkage_table": [],
     "data": [
       {
         "summary_name": "PairsEntitySummaryForJSONFormatTest",
@@ -936,6 +1285,7 @@ TEST_F(JSONFormatTUSummaryTest,
       "name": "test.cpp"
     },
     "id_table": [],
+    "linkage_table": [],
     "data": [
       {
         "summary_name": "PairsEntitySummaryForJSONFormatTest",
@@ -971,6 +1321,7 @@ TEST_F(JSONFormatTUSummaryTest,
       "name": "test.cpp"
     },
     "id_table": [],
+    "linkage_table": [],
     "data": [
       {
         "summary_name": "PairsEntitySummaryForJSONFormatTest",
@@ -1010,6 +1361,7 @@ TEST_F(JSONFormatTUSummaryTest,
       "name": "test.cpp"
     },
     "id_table": [],
+    "linkage_table": [],
     "data": [
       {
         "summary_name": "PairsEntitySummaryForJSONFormatTest",
@@ -1050,6 +1402,7 @@ TEST_F(JSONFormatTUSummaryTest,
       "name": "test.cpp"
     },
     "id_table": [],
+    "linkage_table": [],
     "data": [
       {
         "summary_name": "PairsEntitySummaryForJSONFormatTest",
@@ -1089,6 +1442,7 @@ TEST_F(JSONFormatTUSummaryTest,
       "name": "test.cpp"
     },
     "id_table": [],
+    "linkage_table": [],
     "data": [
       {
         "summary_name": "PairsEntitySummaryForJSONFormatTest",
@@ -1132,6 +1486,7 @@ TEST_F(JSONFormatTUSummaryTest, 
EntityDataMissingEntityID) {
       "name": "test.cpp"
     },
     "id_table": [],
+    "linkage_table": [],
     "data": [
       {
         "summary_name": "PairsEntitySummaryForJSONFormatTest",
@@ -1163,6 +1518,7 @@ TEST_F(JSONFormatTUSummaryTest, 
EntityDataMissingEntitySummary) {
       "name": "test.cpp"
     },
     "id_table": [],
+    "linkage_table": [],
     "data": [
       {
         "summary_name": "PairsEntitySummaryForJSONFormatTest",
@@ -1194,6 +1550,7 @@ TEST_F(JSONFormatTUSummaryTest, EntityIDNotUInt64) {
       "name": "test.cpp"
     },
     "id_table": [],
+    "linkage_table": [],
     "data": [
       {
         "summary_name": "PairsEntitySummaryForJSONFormatTest",
@@ -1230,6 +1587,7 @@ TEST_F(JSONFormatTUSummaryTest, 
EntityDataElementNotObject) {
       "name": "test.cpp"
     },
     "id_table": [],
+    "linkage_table": [],
     "data": [
       {
         "summary_name": "PairsEntitySummaryForJSONFormatTest",
@@ -1265,6 +1623,14 @@ TEST_F(JSONFormatTUSummaryTest, 
DuplicateEntityIdInDataMap) {
         }
       }
     ],
+    "linkage_table": [
+      {
+        "id": 0,
+        "linkage": {
+          "type": "none"
+        }
+      }
+    ],
     "data": [
       {
         "summary_name": "PairsEntitySummaryForJSONFormatTest",
@@ -1308,6 +1674,7 @@ TEST_F(JSONFormatTUSummaryTest, 
DataEntryMissingSummaryName) {
       "name": "test.cpp"
     },
     "id_table": [],
+    "linkage_table": [],
     "data": [
       {
         "summary_data": []
@@ -1332,6 +1699,7 @@ TEST_F(JSONFormatTUSummaryTest, DataEntryMissingData) {
       "name": "test.cpp"
     },
     "id_table": [],
+    "linkage_table": [],
     "data": [
       {
         "summary_name": "PairsEntitySummaryForJSONFormatTest"
@@ -1361,6 +1729,7 @@ TEST_F(JSONFormatTUSummaryTest, DataNotArray) {
       "name": "test.cpp"
     },
     "id_table": [],
+    "linkage_table": [],
     "data": {}
   })");
 
@@ -1379,6 +1748,7 @@ TEST_F(JSONFormatTUSummaryTest, DataElementNotObject) {
       "name": "test.cpp"
     },
     "id_table": [],
+    "linkage_table": [],
     "data": ["invalid"]
   })");
 
@@ -1397,6 +1767,7 @@ TEST_F(JSONFormatTUSummaryTest, DuplicateSummaryName) {
       "name": "test.cpp"
     },
     "id_table": [],
+    "linkage_table": [],
     "data": [
       {
         "summary_name": "PairsEntitySummaryForJSONFormatTest",
@@ -1425,6 +1796,7 @@ TEST_F(JSONFormatTUSummaryTest, DuplicateSummaryName) {
 TEST_F(JSONFormatTUSummaryTest, MissingTUNamespace) {
   auto Result = readTUSummaryFromString(R"({
     "id_table": [],
+    "linkage_table": [],
     "data": []
   })");
 
@@ -1452,13 +1824,32 @@ TEST_F(JSONFormatTUSummaryTest, MissingIDTable) {
                   HasSubstr("expected JSON array"))));
 }
 
+TEST_F(JSONFormatTUSummaryTest, MissingLinkageTable) {
+  auto Result = readTUSummaryFromString(R"({
+    "tu_namespace": {
+      "kind": "compilation_unit",
+      "name": "test.cpp"
+    },
+    "id_table": [],
+    "data": []
+  })");
+
+  EXPECT_THAT_EXPECTED(
+      Result,
+      FailedWithMessage(AllOf(
+          HasSubstr("reading TUSummary from file"),
+          HasSubstr("failed to read LinkageTable from field 'linkage_table'"),
+          HasSubstr("expected JSON array"))));
+}
+
 TEST_F(JSONFormatTUSummaryTest, MissingData) {
   auto Result = readTUSummaryFromString(R"({
     "tu_namespace": {
       "kind": "compilation_unit",
       "name": "test.cpp"
     },
-    "id_table": []
+    "id_table": [],
+    "linkage_table": []
   })");
 
   EXPECT_THAT_EXPECTED(
@@ -1563,6 +1954,7 @@ TEST_F(JSONFormatTUSummaryTest, Empty) {
       "name": "test.cpp"
     },
     "id_table": [],
+    "linkage_table": [],
     "data": []
   })");
 }
@@ -1574,6 +1966,7 @@ TEST_F(JSONFormatTUSummaryTest, LinkUnit) {
       "name": "libtest.so"
     },
     "id_table": [],
+    "linkage_table": [],
     "data": []
   })");
 }
@@ -1616,6 +2009,16 @@ TEST_F(JSONFormatTUSummaryTest, WithIDTable) {
         }
       }
     ],
+    "linkage_table": [
+      {
+        "id": 0,
+        "linkage": { "type": "none" }
+      },
+      {
+        "id": 1,
+        "linkage": { "type": "internal" }
+      }
+    ],
     "data": []
   })");
 }
@@ -1627,6 +2030,7 @@ TEST_F(JSONFormatTUSummaryTest, WithEmptyDataEntry) {
       "name": "test.cpp"
     },
     "id_table": [],
+    "linkage_table": [],
     "data": [
       {
         "summary_name": "PairsEntitySummaryForJSONFormatTest",
@@ -1657,6 +2061,12 @@ TEST_F(JSONFormatTUSummaryTest, RoundTripWithIDTable) {
         }
       }
     ],
+    "linkage_table": [
+      {
+        "id": 0,
+        "linkage": { "type": "none" }
+      }
+    ],
     "data": []
   })");
 }
@@ -1708,6 +2118,20 @@ TEST_F(JSONFormatTUSummaryTest, 
RoundTripPairsEntitySummaryForJSONFormatTest) {
         }
       }
     ],
+    "linkage_table": [
+      {
+        "id": 0,
+        "linkage": { "type": "none" }
+      },
+      {
+        "id": 1,
+        "linkage": { "type": "internal" }
+      },
+      {
+        "id": 2,
+        "linkage": { "type": "external" }
+      }
+    ],
     "data": [
       {
         "summary_name": "PairsEntitySummaryForJSONFormatTest",
@@ -1733,4 +2157,174 @@ TEST_F(JSONFormatTUSummaryTest, 
RoundTripPairsEntitySummaryForJSONFormatTest) {
   })");
 }
 
+TEST_F(JSONFormatTUSummaryTest, EmptyLinkageTable) {
+  readWriteCompareTUSummary(R"({
+    "tu_namespace": {
+      "kind": "compilation_unit",
+      "name": "test.cpp"
+    },
+    "id_table": [],
+    "linkage_table": [],
+    "data": []
+  })");
+}
+
+TEST_F(JSONFormatTUSummaryTest, LinkageTableWithNoneLinkage) {
+  readWriteCompareTUSummary(R"({
+    "tu_namespace": {
+      "kind": "compilation_unit",
+      "name": "test.cpp"
+    },
+    "id_table": [
+      {
+        "id": 0,
+        "name": {
+          "usr": "c:@F@foo",
+          "suffix": "",
+          "namespace": [
+            {
+              "kind": "compilation_unit",
+              "name": "test.cpp"
+            }
+          ]
+        }
+      }
+    ],
+    "linkage_table": [
+      {
+        "id": 0,
+        "linkage": { "type": "none" }
+      }
+    ],
+    "data": []
+  })");
+}
+
+TEST_F(JSONFormatTUSummaryTest, LinkageTableWithInternalLinkage) {
+  readWriteCompareTUSummary(R"({
+    "tu_namespace": {
+      "kind": "compilation_unit",
+      "name": "test.cpp"
+    },
+    "id_table": [
+      {
+        "id": 0,
+        "name": {
+          "usr": "c:@F@bar",
+          "suffix": "",
+          "namespace": [
+            {
+              "kind": "compilation_unit",
+              "name": "test.cpp"
+            }
+          ]
+        }
+      }
+    ],
+    "linkage_table": [
+      {
+        "id": 0,
+        "linkage": { "type": "internal" }
+      }
+    ],
+    "data": []
+  })");
+}
+
+TEST_F(JSONFormatTUSummaryTest, LinkageTableWithExternalLinkage) {
+  readWriteCompareTUSummary(R"({
+    "tu_namespace": {
+      "kind": "compilation_unit",
+      "name": "test.cpp"
+    },
+    "id_table": [
+      {
+        "id": 0,
+        "name": {
+          "usr": "c:@F@baz",
+          "suffix": "",
+          "namespace": [
+            {
+              "kind": "compilation_unit",
+              "name": "test.cpp"
+            }
+          ]
+        }
+      }
+    ],
+    "linkage_table": [
+      {
+        "id": 0,
+        "linkage": { "type": "external" }
+      }
+    ],
+    "data": []
+  })");
+}
+
+TEST_F(JSONFormatTUSummaryTest, LinkageTableWithMultipleEntries) {
+  readWriteCompareTUSummary(R"({
+    "tu_namespace": {
+      "kind": "compilation_unit",
+      "name": "test.cpp"
+    },
+    "id_table": [
+      {
+        "id": 0,
+        "name": {
+          "usr": "c:@F@foo",
+          "suffix": "",
+          "namespace": [
+            {
+              "kind": "compilation_unit",
+              "name": "test.cpp"
+            }
+          ]
+        }
+      },
+      {
+        "id": 1,
+        "name": {
+          "usr": "c:@F@bar",
+          "suffix": "",
+          "namespace": [
+            {
+              "kind": "compilation_unit",
+              "name": "test.cpp"
+            }
+          ]
+        }
+      },
+      {
+        "id": 2,
+        "name": {
+          "usr": "c:@F@baz",
+          "suffix": "",
+          "namespace": [
+            {
+              "kind": "compilation_unit",
+              "name": "test.cpp"
+            }
+          ]
+        }
+      }
+    ],
+    "linkage_table": [
+      {
+        "id": 0,
+        "linkage": { "type": "none" }
+      },
+      {
+        "id": 1,
+        "linkage": { "type": "internal" }
+      },
+      {
+        "id": 2,
+        "linkage": { "type": "external" }
+      }
+    ],
+    "data": []
+  })");
+}
+
 } // anonymous namespace

>From 20c01095d4399519b721c954268a56b905ac0012 Mon Sep 17 00:00:00 2001
From: Aviral Goel <[email protected]>
Date: Mon, 23 Feb 2026 16:21:07 -0800
Subject: [PATCH 2/4] Error message fix

---
 .../Scalable/Serialization/JSONFormat.cpp     | 27 ++++++++++-------
 .../JSONFormatTest/TUSummaryTest.cpp          | 29 +++++++++----------
 2 files changed, 30 insertions(+), 26 deletions(-)

diff --git a/clang/lib/Analysis/Scalable/Serialization/JSONFormat.cpp 
b/clang/lib/Analysis/Scalable/Serialization/JSONFormat.cpp
index 55243c08133c0..efb8ea54fcca1 100644
--- a/clang/lib/Analysis/Scalable/Serialization/JSONFormat.cpp
+++ b/clang/lib/Analysis/Scalable/Serialization/JSONFormat.cpp
@@ -76,13 +76,15 @@ constexpr const char *InvalidBuildNamespaceKind =
     "invalid 'kind' BuildNamespaceKind value '{0}'";
 
 constexpr const char *InvalidEntityLinkageType =
-    "invalid 'linkage' EntityLinkage value '{0}'";
+    "invalid 'type' EntityLinkageType value '{0}'";
 
-constexpr const char *LinkageTableExtraId =
-    "linkage_table contains EntityId '{0}' not present in id_table";
+constexpr const char *FailedToDeserializeLinkageTableExtraId =
+    "failed to deserialize LinkageTable: extra EntityId '{0}' not present in "
+    "IdTable";
 
-constexpr const char *LinkageTableMissingId =
-    "linkage_table is missing EntityId '{0}' present in id_table";
+constexpr const char *FailedToDeserializeLinkageTableMissingId =
+    "failed to deserialize LinkageTable: missing EntityId '{0}' present in "
+    "IdTable";
 
 } // namespace ErrorMessages
 
@@ -399,22 +401,25 @@ JSONFormat::linkageTableFromJSON(const Array 
&LinkageTableArray,
                                   ErrorMessages::FailedInsertionOnDuplication,
                                   "LinkageTable entry", Index, "EntityId",
                                   getIndex(It->first))
+          .context(ErrorMessages::ReadingFromIndex, "LinkageTable entry", 
Index)
           .build();
     }
 
     if (EntityIds.erase(EI) == 0) {
-      return ErrorBuilder::create(std::errc::invalid_argument,
-                                  ErrorMessages::LinkageTableExtraId,
-                                  getIndex(EI))
+      return ErrorBuilder::create(
+                 std::errc::invalid_argument,
+                 ErrorMessages::FailedToDeserializeLinkageTableExtraId,
+                 getIndex(EI))
           .context(ErrorMessages::ReadingFromIndex, "LinkageTable entry", 
Index)
           .build();
     }
   }
 
   if (!EntityIds.empty()) {
-    return ErrorBuilder::create(std::errc::invalid_argument,
-                                ErrorMessages::LinkageTableMissingId,
-                                getIndex(*EntityIds.begin()))
+    return ErrorBuilder::create(
+               std::errc::invalid_argument,
+               ErrorMessages::FailedToDeserializeLinkageTableMissingId,
+               getIndex(*EntityIds.begin()))
         .build();
   }
 
diff --git 
a/clang/unittests/Analysis/Scalable/Serialization/JSONFormatTest/TUSummaryTest.cpp
 
b/clang/unittests/Analysis/Scalable/Serialization/JSONFormatTest/TUSummaryTest.cpp
index 1fb9a966217c8..ee20a48a321cb 100644
--- 
a/clang/unittests/Analysis/Scalable/Serialization/JSONFormatTest/TUSummaryTest.cpp
+++ 
b/clang/unittests/Analysis/Scalable/Serialization/JSONFormatTest/TUSummaryTest.cpp
@@ -404,7 +404,7 @@ TEST_F(JSONFormatTUSummaryTest, 
LinkageTableEntryLinkageInvalidType) {
           HasSubstr("reading LinkageTable from field 'linkage_table'"),
           HasSubstr("reading LinkageTable entry from index '0'"),
           HasSubstr("reading EntityLinkage from field 'linkage'"),
-          HasSubstr("invalid 'linkage' EntityLinkage value 'invalid_type'"))));
+          HasSubstr("invalid 'type' EntityLinkageType value 
'invalid_type'"))));
 }
 
 // ============================================================================
@@ -546,13 +546,12 @@ TEST_F(JSONFormatTUSummaryTest, LinkageTableExtraId) {
   })");
 
   EXPECT_THAT_EXPECTED(
-      Result,
-      FailedWithMessage(AllOf(
-          HasSubstr("reading TUSummary from file"),
-          HasSubstr("reading LinkageTable from field 'linkage_table'"),
-          HasSubstr("reading LinkageTable entry from index '0'"),
-          HasSubstr(
-              "linkage_table contains EntityId '0' not present in 
id_table"))));
+      Result, FailedWithMessage(AllOf(
+                  HasSubstr("reading TUSummary from file"),
+                  HasSubstr("reading LinkageTable from field 'linkage_table'"),
+                  HasSubstr("reading LinkageTable entry from index '0'"),
+                  HasSubstr("failed to deserialize LinkageTable"),
+                  HasSubstr("extra EntityId '0' not present in IdTable"))));
 }
 
 TEST_F(JSONFormatTUSummaryTest, LinkageTableMissingId) {
@@ -581,11 +580,11 @@ TEST_F(JSONFormatTUSummaryTest, LinkageTableMissingId) {
   })");
 
   EXPECT_THAT_EXPECTED(
-      Result,
-      FailedWithMessage(AllOf(
-          HasSubstr("reading TUSummary from file"),
-          HasSubstr(
-              "linkage_table is missing EntityId '0' present in id_table"))));
+      Result, FailedWithMessage(AllOf(
+                  HasSubstr("reading TUSummary from file"),
+                  HasSubstr("reading LinkageTable from field 'linkage_table'"),
+                  HasSubstr("failed to deserialize LinkageTable"),
+                  HasSubstr("missing EntityId '0' present in IdTable"))));
 }
 
 TEST_F(JSONFormatTUSummaryTest, LinkageTableDuplicateId) {
@@ -1145,11 +1144,11 @@ TEST_F(JSONFormatTUSummaryTest, DuplicateEntity) {
     "linkage_table": [
       {
         "id": 0,
-        "linkage": { "type": "none" }
+        "linkage": { "type": "internal" }
       },
       {
         "id": 1,
-        "linkage": { "type": "none" }
+        "linkage": { "type": "external" }
       }
     ],
     "data": []

>From 7be5cf0829c250c6284196f74c2a9ba65eaa6daf Mon Sep 17 00:00:00 2001
From: Aviral Goel <[email protected]>
Date: Mon, 23 Feb 2026 16:25:03 -0800
Subject: [PATCH 3/4] Reorder

---
 .../Scalable/Serialization/JSONFormat.cpp     | 382 +++++++++---------
 1 file changed, 191 insertions(+), 191 deletions(-)

diff --git a/clang/lib/Analysis/Scalable/Serialization/JSONFormat.cpp 
b/clang/lib/Analysis/Scalable/Serialization/JSONFormat.cpp
index efb8ea54fcca1..1c79f41df11a3 100644
--- a/clang/lib/Analysis/Scalable/Serialization/JSONFormat.cpp
+++ b/clang/lib/Analysis/Scalable/Serialization/JSONFormat.cpp
@@ -247,197 +247,6 @@ llvm::StringRef 
buildNamespaceKindToJSON(BuildNamespaceKind BNK) {
 
 } // namespace
 
-//----------------------------------------------------------------------------
-// EntityLinkageType
-//----------------------------------------------------------------------------
-
-namespace {
-
-std::optional<EntityLinkage::LinkageType>
-parseEntityLinkageType(llvm::StringRef S) {
-  if (S == "none")
-    return EntityLinkage::LinkageType::None;
-  if (S == "internal")
-    return EntityLinkage::LinkageType::Internal;
-  if (S == "external")
-    return EntityLinkage::LinkageType::External;
-  return std::nullopt;
-}
-
-llvm::StringRef entityLinkageTypeToJSON(EntityLinkage::LinkageType LT) {
-  switch (LT) {
-  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
-
-//----------------------------------------------------------------------------
-// EntityLinkage
-//----------------------------------------------------------------------------
-
-llvm::Expected<EntityLinkage>
-JSONFormat::entityLinkageFromJSON(const Object &EntityLinkageObject) const {
-  auto OptLinkageStr = EntityLinkageObject.getString("type");
-  if (!OptLinkageStr) {
-    return ErrorBuilder::create(std::errc::invalid_argument,
-                                ErrorMessages::FailedToReadObjectAtField,
-                                "EntityLinkageType", "type", "string")
-        .build();
-  }
-
-  auto OptLinkageType = parseEntityLinkageType(*OptLinkageStr);
-  if (!OptLinkageType) {
-    return ErrorBuilder::create(std::errc::invalid_argument,
-                                ErrorMessages::InvalidEntityLinkageType,
-                                *OptLinkageStr)
-        .build();
-  }
-
-  return EntityLinkage(*OptLinkageType);
-}
-
-Object JSONFormat::entityLinkageToJSON(const EntityLinkage &EL) const {
-  Object Result;
-  Result["type"] = entityLinkageTypeToJSON(getLinkage(EL));
-  return Result;
-}
-
-//----------------------------------------------------------------------------
-// LinkageTableEntry
-//----------------------------------------------------------------------------
-
-llvm::Expected<std::pair<EntityId, EntityLinkage>>
-JSONFormat::linkageTableEntryFromJSON(
-    const Object &LinkageTableEntryObject) const {
-  const Value *EntityIdIntValue = LinkageTableEntryObject.get("id");
-  if (!EntityIdIntValue) {
-    return ErrorBuilder::create(std::errc::invalid_argument,
-                                ErrorMessages::FailedToReadObjectAtField,
-                                "EntityId", "id",
-                                "number (unsigned 64-bit integer)")
-        .build();
-  }
-
-  const std::optional<uint64_t> OptEntityIdInt =
-      EntityIdIntValue->getAsUINT64();
-  if (!OptEntityIdInt) {
-    return ErrorBuilder::create(std::errc::invalid_argument,
-                                ErrorMessages::FailedToReadObjectAtField,
-                                "EntityId", "id",
-                                "number (unsigned 64-bit integer)")
-        .build();
-  }
-
-  EntityId EI = entityIdFromJSON(*OptEntityIdInt);
-
-  const Object *OptEntityLinkageObject =
-      LinkageTableEntryObject.getObject("linkage");
-  if (!OptEntityLinkageObject) {
-    return ErrorBuilder::create(std::errc::invalid_argument,
-                                ErrorMessages::FailedToReadObjectAtField,
-                                "EntityLinkage", "linkage", "object")
-        .build();
-  }
-
-  auto ExpectedEntityLinkage = entityLinkageFromJSON(*OptEntityLinkageObject);
-  if (!ExpectedEntityLinkage) {
-    return ErrorBuilder::wrap(ExpectedEntityLinkage.takeError())
-        .context(ErrorMessages::ReadingFromField, "EntityLinkage", "linkage")
-        .build();
-  }
-
-  return std::make_pair(std::move(EI), std::move(*ExpectedEntityLinkage));
-}
-
-Object JSONFormat::linkageTableEntryToJSON(EntityId EI,
-                                           const EntityLinkage &EL) const {
-  Object Entry;
-  Entry["id"] = entityIdToJSON(EI);
-  Entry["linkage"] = entityLinkageToJSON(EL);
-  return Entry;
-}
-
-//----------------------------------------------------------------------------
-// LinkageTable
-//----------------------------------------------------------------------------
-
-llvm::Expected<std::map<EntityId, EntityLinkage>>
-JSONFormat::linkageTableFromJSON(const Array &LinkageTableArray,
-                                 std::set<EntityId> EntityIds) const {
-  std::map<EntityId, EntityLinkage> LinkageTable;
-
-  for (const auto &[Index, LinkageTableEntryValue] :
-       llvm::enumerate(LinkageTableArray)) {
-
-    const Object *OptLinkageTableEntryObject =
-        LinkageTableEntryValue.getAsObject();
-    if (!OptLinkageTableEntryObject) {
-      return ErrorBuilder::create(std::errc::invalid_argument,
-                                  ErrorMessages::FailedToReadObjectAtIndex,
-                                  "LinkageTable entry", Index, "object")
-          .build();
-    }
-
-    auto ExpectedLinkageTableEntry =
-        linkageTableEntryFromJSON(*OptLinkageTableEntryObject);
-    if (!ExpectedLinkageTableEntry)
-      return ErrorBuilder::wrap(ExpectedLinkageTableEntry.takeError())
-          .context(ErrorMessages::ReadingFromIndex, "LinkageTable entry", 
Index)
-          .build();
-
-    const EntityId EI = ExpectedLinkageTableEntry->first;
-
-    auto [It, Inserted] =
-        LinkageTable.insert(std::move(*ExpectedLinkageTableEntry));
-    if (!Inserted) {
-      return ErrorBuilder::create(std::errc::invalid_argument,
-                                  ErrorMessages::FailedInsertionOnDuplication,
-                                  "LinkageTable entry", Index, "EntityId",
-                                  getIndex(It->first))
-          .context(ErrorMessages::ReadingFromIndex, "LinkageTable entry", 
Index)
-          .build();
-    }
-
-    if (EntityIds.erase(EI) == 0) {
-      return ErrorBuilder::create(
-                 std::errc::invalid_argument,
-                 ErrorMessages::FailedToDeserializeLinkageTableExtraId,
-                 getIndex(EI))
-          .context(ErrorMessages::ReadingFromIndex, "LinkageTable entry", 
Index)
-          .build();
-    }
-  }
-
-  if (!EntityIds.empty()) {
-    return ErrorBuilder::create(
-               std::errc::invalid_argument,
-               ErrorMessages::FailedToDeserializeLinkageTableMissingId,
-               getIndex(*EntityIds.begin()))
-        .build();
-  }
-
-  return LinkageTable;
-}
-
-Array JSONFormat::linkageTableToJSON(
-    const std::map<EntityId, EntityLinkage> &LinkageTable) const {
-  Array Result;
-  Result.reserve(LinkageTable.size());
-
-  for (const auto &[EI, EL] : LinkageTable) {
-    Result.push_back(linkageTableEntryToJSON(EI, EL));
-  }
-
-  return Result;
-}
-
 //----------------------------------------------------------------------------
 // NestedBuildNamespace
 //----------------------------------------------------------------------------
@@ -573,6 +382,68 @@ Object JSONFormat::entityNameToJSON(const EntityName &EN) 
const {
   return Result;
 }
 
+//----------------------------------------------------------------------------
+// EntityLinkageType
+//----------------------------------------------------------------------------
+
+namespace {
+
+std::optional<EntityLinkage::LinkageType>
+parseEntityLinkageType(llvm::StringRef S) {
+  if (S == "none")
+    return EntityLinkage::LinkageType::None;
+  if (S == "internal")
+    return EntityLinkage::LinkageType::Internal;
+  if (S == "external")
+    return EntityLinkage::LinkageType::External;
+  return std::nullopt;
+}
+
+llvm::StringRef entityLinkageTypeToJSON(EntityLinkage::LinkageType LT) {
+  switch (LT) {
+  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
+
+//----------------------------------------------------------------------------
+// EntityLinkage
+//----------------------------------------------------------------------------
+
+llvm::Expected<EntityLinkage>
+JSONFormat::entityLinkageFromJSON(const Object &EntityLinkageObject) const {
+  auto OptLinkageStr = EntityLinkageObject.getString("type");
+  if (!OptLinkageStr) {
+    return ErrorBuilder::create(std::errc::invalid_argument,
+                                ErrorMessages::FailedToReadObjectAtField,
+                                "EntityLinkageType", "type", "string")
+        .build();
+  }
+
+  auto OptLinkageType = parseEntityLinkageType(*OptLinkageStr);
+  if (!OptLinkageType) {
+    return ErrorBuilder::create(std::errc::invalid_argument,
+                                ErrorMessages::InvalidEntityLinkageType,
+                                *OptLinkageStr)
+        .build();
+  }
+
+  return EntityLinkage(*OptLinkageType);
+}
+
+Object JSONFormat::entityLinkageToJSON(const EntityLinkage &EL) const {
+  Object Result;
+  Result["type"] = entityLinkageTypeToJSON(getLinkage(EL));
+  return Result;
+}
+
 //----------------------------------------------------------------------------
 // EntityIdTableEntry
 //----------------------------------------------------------------------------
@@ -685,6 +556,135 @@ Array JSONFormat::entityIdTableToJSON(const EntityIdTable 
&IdTable) const {
   return EntityIdTableArray;
 }
 
+//----------------------------------------------------------------------------
+// LinkageTableEntry
+//----------------------------------------------------------------------------
+
+llvm::Expected<std::pair<EntityId, EntityLinkage>>
+JSONFormat::linkageTableEntryFromJSON(
+    const Object &LinkageTableEntryObject) const {
+  const Value *EntityIdIntValue = LinkageTableEntryObject.get("id");
+  if (!EntityIdIntValue) {
+    return ErrorBuilder::create(std::errc::invalid_argument,
+                                ErrorMessages::FailedToReadObjectAtField,
+                                "EntityId", "id",
+                                "number (unsigned 64-bit integer)")
+        .build();
+  }
+
+  const std::optional<uint64_t> OptEntityIdInt =
+      EntityIdIntValue->getAsUINT64();
+  if (!OptEntityIdInt) {
+    return ErrorBuilder::create(std::errc::invalid_argument,
+                                ErrorMessages::FailedToReadObjectAtField,
+                                "EntityId", "id",
+                                "number (unsigned 64-bit integer)")
+        .build();
+  }
+
+  EntityId EI = entityIdFromJSON(*OptEntityIdInt);
+
+  const Object *OptEntityLinkageObject =
+      LinkageTableEntryObject.getObject("linkage");
+  if (!OptEntityLinkageObject) {
+    return ErrorBuilder::create(std::errc::invalid_argument,
+                                ErrorMessages::FailedToReadObjectAtField,
+                                "EntityLinkage", "linkage", "object")
+        .build();
+  }
+
+  auto ExpectedEntityLinkage = entityLinkageFromJSON(*OptEntityLinkageObject);
+  if (!ExpectedEntityLinkage) {
+    return ErrorBuilder::wrap(ExpectedEntityLinkage.takeError())
+        .context(ErrorMessages::ReadingFromField, "EntityLinkage", "linkage")
+        .build();
+  }
+
+  return std::make_pair(std::move(EI), std::move(*ExpectedEntityLinkage));
+}
+
+Object JSONFormat::linkageTableEntryToJSON(EntityId EI,
+                                           const EntityLinkage &EL) const {
+  Object Entry;
+  Entry["id"] = entityIdToJSON(EI);
+  Entry["linkage"] = entityLinkageToJSON(EL);
+  return Entry;
+}
+
+//----------------------------------------------------------------------------
+// LinkageTable
+//----------------------------------------------------------------------------
+
+llvm::Expected<std::map<EntityId, EntityLinkage>>
+JSONFormat::linkageTableFromJSON(const Array &LinkageTableArray,
+                                 std::set<EntityId> EntityIds) const {
+  std::map<EntityId, EntityLinkage> LinkageTable;
+
+  for (const auto &[Index, LinkageTableEntryValue] :
+       llvm::enumerate(LinkageTableArray)) {
+
+    const Object *OptLinkageTableEntryObject =
+        LinkageTableEntryValue.getAsObject();
+    if (!OptLinkageTableEntryObject) {
+      return ErrorBuilder::create(std::errc::invalid_argument,
+                                  ErrorMessages::FailedToReadObjectAtIndex,
+                                  "LinkageTable entry", Index, "object")
+          .build();
+    }
+
+    auto ExpectedLinkageTableEntry =
+        linkageTableEntryFromJSON(*OptLinkageTableEntryObject);
+    if (!ExpectedLinkageTableEntry)
+      return ErrorBuilder::wrap(ExpectedLinkageTableEntry.takeError())
+          .context(ErrorMessages::ReadingFromIndex, "LinkageTable entry", 
Index)
+          .build();
+
+    const EntityId EI = ExpectedLinkageTableEntry->first;
+
+    auto [It, Inserted] =
+        LinkageTable.insert(std::move(*ExpectedLinkageTableEntry));
+    if (!Inserted) {
+      return ErrorBuilder::create(std::errc::invalid_argument,
+                                  ErrorMessages::FailedInsertionOnDuplication,
+                                  "LinkageTable entry", Index, "EntityId",
+                                  getIndex(It->first))
+          .context(ErrorMessages::ReadingFromIndex, "LinkageTable entry", 
Index)
+          .build();
+    }
+
+    if (EntityIds.erase(EI) == 0) {
+      return ErrorBuilder::create(
+                 std::errc::invalid_argument,
+                 ErrorMessages::FailedToDeserializeLinkageTableExtraId,
+                 getIndex(EI))
+          .context(ErrorMessages::ReadingFromIndex, "LinkageTable entry", 
Index)
+          .build();
+    }
+  }
+
+  if (!EntityIds.empty()) {
+    return ErrorBuilder::create(
+               std::errc::invalid_argument,
+               ErrorMessages::FailedToDeserializeLinkageTableMissingId,
+               getIndex(*EntityIds.begin()))
+        .build();
+  }
+
+  return LinkageTable;
+}
+
+Array JSONFormat::linkageTableToJSON(
+    const std::map<EntityId, EntityLinkage> &LinkageTable) const {
+  Array Result;
+  Result.reserve(LinkageTable.size());
+
+  for (const auto &[EI, EL] : LinkageTable) {
+    Result.push_back(linkageTableEntryToJSON(EI, EL));
+  }
+
+  return Result;
+}
+
 //----------------------------------------------------------------------------
 // EntitySummary
 //----------------------------------------------------------------------------

>From 875abaa8513e23230fcd99ef0bda4a57f8d57117 Mon Sep 17 00:00:00 2001
From: Aviral Goel <[email protected]>
Date: Mon, 23 Feb 2026 16:40:38 -0800
Subject: [PATCH 4/4] Minor fixes.

---
 .../Scalable/Serialization/JSONFormat.h       | 28 +++++++++----------
 .../Scalable/Serialization/JSONFormat.cpp     |  5 ++--
 2 files changed, 16 insertions(+), 17 deletions(-)

diff --git a/clang/include/clang/Analysis/Scalable/Serialization/JSONFormat.h 
b/clang/include/clang/Analysis/Scalable/Serialization/JSONFormat.h
index 25fdd07b7f469..706ace7e8feb8 100644
--- a/clang/include/clang/Analysis/Scalable/Serialization/JSONFormat.h
+++ b/clang/include/clang/Analysis/Scalable/Serialization/JSONFormat.h
@@ -72,20 +72,6 @@ class JSONFormat final : public SerializationFormat {
   llvm::Expected<BuildNamespaceKind>
   buildNamespaceKindFromJSON(llvm::StringRef BuildNamespaceKindStr) const;
 
-  llvm::Expected<EntityLinkage>
-  entityLinkageFromJSON(const Object &EntityLinkageObject) const;
-  Object entityLinkageToJSON(const EntityLinkage &EL) const;
-
-  llvm::Expected<std::pair<EntityId, EntityLinkage>>
-  linkageTableEntryFromJSON(const Object &LinkageTableEntryObject) const;
-  Object linkageTableEntryToJSON(EntityId EI, const EntityLinkage &EL) const;
-
-  llvm::Expected<std::map<EntityId, EntityLinkage>>
-  linkageTableFromJSON(const Array &LinkageTableArray,
-                       std::set<EntityId> EntityIds) const;
-  Array linkageTableToJSON(
-      const std::map<EntityId, EntityLinkage> &LinkageTable) const;
-
   llvm::Expected<BuildNamespace>
   buildNamespaceFromJSON(const Object &BuildNamespaceObject) const;
   Object buildNamespaceToJSON(const BuildNamespace &BN) const;
@@ -98,6 +84,10 @@ class JSONFormat final : public SerializationFormat {
   entityNameFromJSON(const Object &EntityNameObject) const;
   Object entityNameToJSON(const EntityName &EN) const;
 
+  llvm::Expected<EntityLinkage>
+  entityLinkageFromJSON(const Object &EntityLinkageObject) const;
+  Object entityLinkageToJSON(const EntityLinkage &EL) const;
+
   llvm::Expected<std::pair<EntityName, EntityId>>
   entityIdTableEntryFromJSON(const Object &EntityIdTableEntryObject) const;
   llvm::Expected<EntityIdTable>
@@ -105,6 +95,16 @@ class JSONFormat final : public SerializationFormat {
   Object entityIdTableEntryToJSON(const EntityName &EN, EntityId EI) const;
   Array entityIdTableToJSON(const EntityIdTable &IdTable) const;
 
+  llvm::Expected<std::pair<EntityId, EntityLinkage>>
+  linkageTableEntryFromJSON(const Object &LinkageTableEntryObject) const;
+  Object linkageTableEntryToJSON(EntityId EI, const EntityLinkage &EL) const;
+
+  llvm::Expected<std::map<EntityId, EntityLinkage>>
+  linkageTableFromJSON(const Array &LinkageTableArray,
+                       std::set<EntityId> EntityIds) const;
+  Array linkageTableToJSON(
+      const std::map<EntityId, EntityLinkage> &LinkageTable) const;
+
   llvm::Expected<std::unique_ptr<EntitySummary>>
   entitySummaryFromJSON(const SummaryName &SN,
                         const Object &EntitySummaryObject,
diff --git a/clang/lib/Analysis/Scalable/Serialization/JSONFormat.cpp 
b/clang/lib/Analysis/Scalable/Serialization/JSONFormat.cpp
index 1c79f41df11a3..c5449012c18f4 100644
--- a/clang/lib/Analysis/Scalable/Serialization/JSONFormat.cpp
+++ b/clang/lib/Analysis/Scalable/Serialization/JSONFormat.cpp
@@ -622,7 +622,6 @@ JSONFormat::linkageTableFromJSON(const Array 
&LinkageTableArray,
 
   for (const auto &[Index, LinkageTableEntryValue] :
        llvm::enumerate(LinkageTableArray)) {
-
     const Object *OptLinkageTableEntryObject =
         LinkageTableEntryValue.getAsObject();
     if (!OptLinkageTableEntryObject) {
@@ -634,10 +633,11 @@ JSONFormat::linkageTableFromJSON(const Array 
&LinkageTableArray,
 
     auto ExpectedLinkageTableEntry =
         linkageTableEntryFromJSON(*OptLinkageTableEntryObject);
-    if (!ExpectedLinkageTableEntry)
+    if (!ExpectedLinkageTableEntry) {
       return ErrorBuilder::wrap(ExpectedLinkageTableEntry.takeError())
           .context(ErrorMessages::ReadingFromIndex, "LinkageTable entry", 
Index)
           .build();
+    }
 
     const EntityId EI = ExpectedLinkageTableEntry->first;
 
@@ -648,7 +648,6 @@ JSONFormat::linkageTableFromJSON(const Array 
&LinkageTableArray,
                                   ErrorMessages::FailedInsertionOnDuplication,
                                   "LinkageTable entry", Index, "EntityId",
                                   getIndex(It->first))
-          .context(ErrorMessages::ReadingFromIndex, "LinkageTable entry", 
Index)
           .build();
     }
 

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

Reply via email to