Files
TheRock/compiler/amd-llvm/clang/unittests/ScalableStaticAnalysisFramework/SummaryData/SummaryDataTest.cpp
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

398 lines
14 KiB
C++

//===- 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/ScalableStaticAnalysisFramework/Core/EntityLinker/LUSummary.h"
#include "clang/ScalableStaticAnalysisFramework/Core/Model/BuildNamespace.h"
#include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityId.h"
#include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityIdTable.h"
#include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityLinkage.h"
#include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityName.h"
#include "clang/ScalableStaticAnalysisFramework/Core/Model/SummaryName.h"
#include "clang/ScalableStaticAnalysisFramework/Core/SummaryData/LUSummaryConsumer.h"
#include "clang/ScalableStaticAnalysisFramework/Core/SummaryData/SummaryDataBuilderRegistry.h"
#include "clang/ScalableStaticAnalysisFramework/Core/TUSummary/EntitySummary.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Testing/Support/Error.h"
#include "gtest/gtest.h"
#include <memory>
#include <utility>
#include <vector>
using namespace clang;
using namespace ssaf;
namespace {
// ---------------------------------------------------------------------------
// Instance counter
// ---------------------------------------------------------------------------
static int NextSummaryInstanceId = 0;
// ---------------------------------------------------------------------------
// Entity summaries
// ---------------------------------------------------------------------------
class Analysis1EntitySummary final : public EntitySummary {
public:
int InstanceId = NextSummaryInstanceId++;
SummaryName getSummaryName() const override {
return SummaryName("Analysis1");
}
};
class Analysis2EntitySummary final : public EntitySummary {
public:
int InstanceId = NextSummaryInstanceId++;
SummaryName getSummaryName() const override {
return SummaryName("Analysis2");
}
};
class Analysis3EntitySummary final : public EntitySummary {
public:
int InstanceId = NextSummaryInstanceId++;
SummaryName getSummaryName() const override {
return SummaryName("Analysis3");
}
};
class Analysis4EntitySummary final : public EntitySummary {
public:
int InstanceId = NextSummaryInstanceId++;
SummaryName getSummaryName() const override {
return SummaryName("Analysis4");
}
};
// ---------------------------------------------------------------------------
// Data
// ---------------------------------------------------------------------------
class Analysis1Data final : public SummaryData {
public:
static SummaryName summaryName() { return SummaryName("Analysis1"); }
std::vector<std::pair<EntityId, int>> Entries;
bool WasFinalized = false;
};
class Analysis2Data final : 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 final : 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 final : 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 final
: 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 final
: 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 final
: 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 llvm::is_contained(Entries, std::make_pair(Id, InstanceId));
}
/// 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("AnalysisNonExisting"));
EXPECT_TRUE(SummaryDataBuilderRegistry::contains("Analysis1"));
EXPECT_TRUE(SummaryDataBuilderRegistry::contains("Analysis2"));
EXPECT_TRUE(SummaryDataBuilderRegistry::contains("Analysis4"));
}
TEST(SummaryDataBuilderRegistryTest, BuilderCanBeInstantiated) {
EXPECT_EQ(SummaryDataBuilderRegistry::instantiate("AnalysisNonExisting"),
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.
(void)insertSummary<Analysis3EntitySummary>(*LU, "Analysis3", E1);
LUSummaryConsumer Consumer(std::move(LU));
SummaryDataStore Store = std::move(Consumer).run();
{
auto Data1OrErr = Store.get<Analysis1Data>();
ASSERT_THAT_EXPECTED(Data1OrErr, llvm::Succeeded());
auto &Data1 = *Data1OrErr;
EXPECT_EQ(Data1.Entries.size(), 2u);
EXPECT_TRUE(hasEntry(Data1.Entries, E1, s1a));
EXPECT_TRUE(hasEntry(Data1.Entries, E2, s1b));
EXPECT_TRUE(Data1.WasFinalized);
EXPECT_TRUE(Analysis1BuilderWasDestroyed);
// take() transfers ownership — subsequent get() returns an error.
auto Take1OrErr = Store.take<Analysis1Data>();
ASSERT_THAT_EXPECTED(Take1OrErr, llvm::Succeeded());
EXPECT_NE(*Take1OrErr, nullptr);
EXPECT_THAT_EXPECTED(Store.get<Analysis1Data>(), llvm::Failed());
}
{
auto Data2OrErr = Store.get<Analysis2Data>();
ASSERT_THAT_EXPECTED(Data2OrErr, llvm::Succeeded());
auto &Data2 = *Data2OrErr;
EXPECT_EQ(Data2.Entries.size(), 2u);
EXPECT_TRUE(hasEntry(Data2.Entries, E2, s2a));
EXPECT_TRUE(hasEntry(Data2.Entries, E3, s2b));
EXPECT_TRUE(Data2.WasFinalized);
EXPECT_TRUE(Analysis2BuilderWasDestroyed);
auto Take2OrErr = Store.take<Analysis2Data>();
ASSERT_THAT_EXPECTED(Take2OrErr, llvm::Succeeded());
EXPECT_NE(*Take2OrErr, nullptr);
EXPECT_THAT_EXPECTED(Store.get<Analysis2Data>(), llvm::Failed());
}
// Unregistered — not present in store.
EXPECT_THAT_EXPECTED(Store.get<Analysis3Data>(), llvm::Failed());
// Registered builder but no data in LUSummary — not present in store.
EXPECT_THAT_EXPECTED(Store.get<Analysis4Data>(), llvm::Failed());
EXPECT_FALSE(Analysis4BuilderWasDestroyed);
}
// run(names) — processes only the analyses for the given names.
TEST_F(LUSummaryConsumerTest, RunByName) {
auto LU = makeLUSummary();
const auto E1 = addEntity(*LU, "Entity1");
const auto E2 = addEntity(*LU, "Entity2");
int s1a = insertSummary<Analysis1EntitySummary>(*LU, "Analysis1", E1);
insertSummary<Analysis2EntitySummary>(*LU, "Analysis2", E2);
LUSummaryConsumer Consumer(std::move(LU));
auto StoreOrErr = Consumer.run({SummaryName("Analysis1")});
ASSERT_THAT_EXPECTED(StoreOrErr, llvm::Succeeded());
// Analysis1 was requested and has data — present.
auto Data1OrErr = StoreOrErr->get<Analysis1Data>();
ASSERT_THAT_EXPECTED(Data1OrErr, llvm::Succeeded());
auto &Data1 = *Data1OrErr;
EXPECT_EQ(Data1.Entries.size(), 1u);
EXPECT_TRUE(hasEntry(Data1.Entries, E1, s1a));
EXPECT_TRUE(Data1.WasFinalized);
// Analysis2 was not requested — not present even though data exists.
EXPECT_THAT_EXPECTED(StoreOrErr->get<Analysis2Data>(), llvm::Failed());
}
// run(names) — error when a requested name has no data in LUSummary.
TEST_F(LUSummaryConsumerTest, RunByNameErrorMissingData) {
auto LU = makeLUSummary();
LUSummaryConsumer Consumer(std::move(LU));
EXPECT_THAT_EXPECTED(Consumer.run({SummaryName("Analysis1")}),
llvm::Failed());
}
// run(names) — error when a requested name has no registered builder.
TEST_F(LUSummaryConsumerTest, RunByNameErrorMissingBuilder) {
auto LU = makeLUSummary();
const auto E1 = addEntity(*LU, "Entity1");
insertSummary<Analysis3EntitySummary>(*LU, "Analysis3", E1);
LUSummaryConsumer Consumer(std::move(LU));
// Analysis3 has data but no registered builder.
EXPECT_THAT_EXPECTED(Consumer.run({SummaryName("Analysis3")}),
llvm::Failed());
}
// run<DataTs...>() — type-safe subset.
TEST_F(LUSummaryConsumerTest, RunByType) {
auto LU = makeLUSummary();
const auto E1 = addEntity(*LU, "Entity1");
const auto E2 = addEntity(*LU, "Entity2");
int s1a = insertSummary<Analysis1EntitySummary>(*LU, "Analysis1", E1);
insertSummary<Analysis2EntitySummary>(*LU, "Analysis2", E2);
LUSummaryConsumer Consumer(std::move(LU));
auto StoreOrErr = Consumer.run<Analysis1Data>();
ASSERT_THAT_EXPECTED(StoreOrErr, llvm::Succeeded());
// Analysis1 was requested — present.
auto Data1OrErr = StoreOrErr->get<Analysis1Data>();
ASSERT_THAT_EXPECTED(Data1OrErr, llvm::Succeeded());
auto &Data1 = *Data1OrErr;
EXPECT_EQ(Data1.Entries.size(), 1u);
EXPECT_TRUE(hasEntry(Data1.Entries, E1, s1a));
EXPECT_TRUE(Data1.WasFinalized);
// Analysis2 was not requested — not present even though data exists.
EXPECT_THAT_EXPECTED(StoreOrErr->get<Analysis2Data>(), llvm::Failed());
}
// run<DataTs...>() — error when a requested type has no data in LUSummary.
TEST_F(LUSummaryConsumerTest, RunByTypeErrorMissingData) {
auto LU = makeLUSummary();
LUSummaryConsumer Consumer(std::move(LU));
EXPECT_THAT_EXPECTED(Consumer.run<Analysis1Data>(), llvm::Failed());
}
// contains() — present entries return true; absent entries return false.
TEST_F(LUSummaryConsumerTest, Contains) {
auto LU = makeLUSummary();
const auto E1 = addEntity(*LU, "Entity1");
insertSummary<Analysis1EntitySummary>(*LU, "Analysis1", E1);
LUSummaryConsumer Consumer(std::move(LU));
SummaryDataStore Store = std::move(Consumer).run();
// Type-safe variant.
EXPECT_TRUE(Store.contains<Analysis1Data>());
EXPECT_FALSE(Store.contains<Analysis2Data>());
// Name-based variant.
EXPECT_TRUE(Store.contains(SummaryName("Analysis1")));
EXPECT_FALSE(Store.contains(SummaryName("Analysis2")));
// After take(), contains() returns false.
ASSERT_THAT_EXPECTED(Store.take<Analysis1Data>(), llvm::Succeeded());
EXPECT_FALSE(Store.contains<Analysis1Data>());
EXPECT_FALSE(Store.contains(SummaryName("Analysis1")));
}
} // namespace