================ @@ -0,0 +1,390 @@ +//===- SummaryDataTest.cpp ------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "../TestFixture.h" +#include "clang/Analysis/Scalable/EntityLinker/LUSummary.h" +#include "clang/Analysis/Scalable/Model/BuildNamespace.h" +#include "clang/Analysis/Scalable/Model/EntityId.h" +#include "clang/Analysis/Scalable/Model/EntityIdTable.h" +#include "clang/Analysis/Scalable/Model/EntityLinkage.h" +#include "clang/Analysis/Scalable/Model/EntityName.h" +#include "clang/Analysis/Scalable/Model/SummaryName.h" +#include "clang/Analysis/Scalable/SummaryData/LUSummaryConsumer.h" +#include "clang/Analysis/Scalable/SummaryData/SummaryDataBuilderRegistry.h" +#include "clang/Analysis/Scalable/TUSummary/EntitySummary.h" +#include "llvm/Testing/Support/Error.h" +#include "gtest/gtest.h" +#include <algorithm> +#include <memory> +#include <utility> +#include <vector> + +using namespace clang; +using namespace ssaf; + +namespace { + +// --------------------------------------------------------------------------- +// Instance counter +// --------------------------------------------------------------------------- + +static int NextSummaryInstanceId = 0; + +// --------------------------------------------------------------------------- +// Entity summaries +// --------------------------------------------------------------------------- + +class Analysis1EntitySummary : public EntitySummary { +public: + int InstanceId = NextSummaryInstanceId++; + SummaryName getSummaryName() const override { + return SummaryName("Analysis1"); + } +}; + +class Analysis2EntitySummary : public EntitySummary { +public: + int InstanceId = NextSummaryInstanceId++; + SummaryName getSummaryName() const override { + return SummaryName("Analysis2"); + } +}; + +class Analysis4EntitySummary : public EntitySummary { +public: + int InstanceId = NextSummaryInstanceId++; + SummaryName getSummaryName() const override { + return SummaryName("Analysis4"); + } +}; + +// --------------------------------------------------------------------------- +// Data +// --------------------------------------------------------------------------- + +class Analysis1Data : public SummaryData { +public: + static SummaryName summaryName() { return SummaryName("Analysis1"); } + std::vector<std::pair<EntityId, int>> Entries; + bool WasFinalized = false; +}; + +class Analysis2Data : public SummaryData { +public: + static SummaryName summaryName() { return SummaryName("Analysis2"); } + std::vector<std::pair<EntityId, int>> Entries; + bool WasFinalized = false; +}; + +// No builder or registration for Analysis3. Data for Analysis3 is inserted +// into the LUSummary to verify the consumer silently skips it. +class Analysis3Data : public SummaryData { +public: + static SummaryName summaryName() { return SummaryName("Analysis3"); } +}; + +// Analysis4 has a registered builder but no data is inserted into the +// LUSummary, so the builder is never invoked and getData returns nullptr. +class Analysis4Data : public SummaryData { +public: + static SummaryName summaryName() { return SummaryName("Analysis4"); } + std::vector<std::pair<EntityId, int>> Entries; + bool WasFinalized = false; +}; + +// --------------------------------------------------------------------------- +// Builder destruction flags (reset in SetUp) +// --------------------------------------------------------------------------- + +static bool Analysis1BuilderWasDestroyed = false; +static bool Analysis2BuilderWasDestroyed = false; +static bool Analysis4BuilderWasDestroyed = false; + +// --------------------------------------------------------------------------- +// Builders +// --------------------------------------------------------------------------- + +class Analysis1Builder + : public SummaryDataBuilder<Analysis1Data, Analysis1EntitySummary> { +public: + ~Analysis1Builder() { Analysis1BuilderWasDestroyed = true; } + + void addSummary(EntityId Id, + std::unique_ptr<Analysis1EntitySummary> S) override { + getData().Entries.push_back({Id, S->InstanceId}); + } + + void finalize() override { getData().WasFinalized = true; } +}; + +static SummaryDataBuilderRegistry::Add<Analysis1Builder> + RegAnalysis1("Builder for Analysis1"); + +class Analysis2Builder + : public SummaryDataBuilder<Analysis2Data, Analysis2EntitySummary> { +public: + ~Analysis2Builder() { Analysis2BuilderWasDestroyed = true; } + + void addSummary(EntityId Id, + std::unique_ptr<Analysis2EntitySummary> S) override { + getData().Entries.push_back({Id, S->InstanceId}); + } + + void finalize() override { getData().WasFinalized = true; } +}; + +static SummaryDataBuilderRegistry::Add<Analysis2Builder> + RegAnalysis2("Builder for Analysis2"); + +class Analysis4Builder + : public SummaryDataBuilder<Analysis4Data, Analysis4EntitySummary> { +public: + ~Analysis4Builder() { Analysis4BuilderWasDestroyed = true; } + + void addSummary(EntityId Id, + std::unique_ptr<Analysis4EntitySummary> S) override { + getData().Entries.push_back({Id, S->InstanceId}); + } + + void finalize() override { getData().WasFinalized = true; } +}; + +static SummaryDataBuilderRegistry::Add<Analysis4Builder> + RegAnalysis4("Builder for Analysis4"); + +// --------------------------------------------------------------------------- +// Fixture +// --------------------------------------------------------------------------- + +class LUSummaryConsumerTest : public TestFixture { +protected: + static constexpr EntityLinkage ExternalLinkage = + EntityLinkage(EntityLinkageType::External); + + void SetUp() override { + NextSummaryInstanceId = 0; + Analysis1BuilderWasDestroyed = false; + Analysis2BuilderWasDestroyed = false; + Analysis4BuilderWasDestroyed = false; + } + + std::unique_ptr<LUSummary> makeLUSummary() { + NestedBuildNamespace NS( + {BuildNamespace(BuildNamespaceKind::LinkUnit, "TestLU")}); + return std::make_unique<LUSummary>(std::move(NS)); + } + + EntityId addEntity(LUSummary &LU, llvm::StringRef USR) { + NestedBuildNamespace NS( + {BuildNamespace(BuildNamespaceKind::LinkUnit, "TestLU")}); + EntityName Name(USR.str(), "", NS); + EntityId Id = getIdTable(LU).getId(Name); + getLinkageTable(LU).insert({Id, ExternalLinkage}); + return Id; + } + + static bool hasEntry(const std::vector<std::pair<EntityId, int>> &Entries, + EntityId Id, int InstanceId) { + return std::find(Entries.begin(), Entries.end(), + std::make_pair(Id, InstanceId)) != Entries.end(); + } + + /// Inserts a freshly constructed SummaryT for the given entity and returns + /// the summary's InstanceId so the test can verify delivery later. + template <typename SummaryT> + int insertSummary(LUSummary &LU, llvm::StringRef SN, EntityId Id) { + auto S = std::make_unique<SummaryT>(); + int InstanceId = S->InstanceId; + getData(LU)[SummaryName(SN.str())][Id] = std::move(S); + return InstanceId; + } +}; + +// --------------------------------------------------------------------------- +// Tests +// --------------------------------------------------------------------------- + +TEST(SummaryDataBuilderRegistryTest, BuilderIsRegistered) { + EXPECT_FALSE(SummaryDataBuilderRegistry::contains("Analysis10")); + EXPECT_TRUE(SummaryDataBuilderRegistry::contains("Analysis1")); + EXPECT_TRUE(SummaryDataBuilderRegistry::contains("Analysis2")); + EXPECT_TRUE(SummaryDataBuilderRegistry::contains("Analysis4")); +} + +TEST(SummaryDataBuilderRegistryTest, BuilderCanBeInstantiated) { + EXPECT_EQ(SummaryDataBuilderRegistry::instantiate("Analysis10"), nullptr); + EXPECT_NE(SummaryDataBuilderRegistry::instantiate("Analysis1"), nullptr); + EXPECT_NE(SummaryDataBuilderRegistry::instantiate("Analysis2"), nullptr); + EXPECT_NE(SummaryDataBuilderRegistry::instantiate("Analysis4"), nullptr); +} + +// run() — processes all registered analyses present in the LUSummary. +TEST_F(LUSummaryConsumerTest, RunAll) { + auto LU = makeLUSummary(); + const auto E1 = addEntity(*LU, "Entity1"); + const auto E2 = addEntity(*LU, "Entity2"); + const auto E3 = addEntity(*LU, "Entity3"); + + int s1a = insertSummary<Analysis1EntitySummary>(*LU, "Analysis1", E1); + int s1b = insertSummary<Analysis1EntitySummary>(*LU, "Analysis1", E2); + int s2a = insertSummary<Analysis2EntitySummary>(*LU, "Analysis2", E2); + int s2b = insertSummary<Analysis2EntitySummary>(*LU, "Analysis2", E3); + + // No registered builder — Analysis3 data silently skipped. + [[maybe_unused]] int s3a = + insertSummary<Analysis1EntitySummary>(*LU, "Analysis3", E1); + + LUSummaryConsumer Consumer(std::move(LU)); + SummaryDataStore Store = std::move(Consumer).run(); + + { + auto Data1OrErr = Store.get<Analysis1Data>(); ---------------- steakhal wrote:
FYI The use of `Analysis10` tripped me here too. I figured `Data1O` is actually `Data` and `10`. No actions expected here. https://github.com/llvm/llvm-project/pull/185803 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
