https://github.com/aviralg created https://github.com/llvm/llvm-project/pull/182961
This change adds full read/write support for the `TUSummary::LinkageTable` field that maps each entity to its linkage kind. The deserialization step validates that the set of entity ids in `LinkageTable` exactly matches the set in `IdTable` in a single `O(N log N)` pass. Existing tests have been updated and new tests have been added to ensure 100% coverage of the new code. >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] 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 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
