[clang] [clang][ssaf] Implement TUSummaryBuilder with test infrastructure (PR #181220)
Balázs Benics via cfe-commits
cfe-commits at lists.llvm.org
Tue Feb 17 10:34:38 PST 2026
================
@@ -9,10 +9,47 @@
#ifndef LLVM_CLANG_ANALYSIS_SCALABLE_TUSUMMARY_TUSUMMARYBUILDER_H
#define LLVM_CLANG_ANALYSIS_SCALABLE_TUSUMMARY_TUSUMMARYBUILDER_H
+#include "clang/Analysis/Scalable/Model/EntityId.h"
+#include "clang/Analysis/Scalable/TUSummary/EntitySummary.h"
+#include <memory>
+#include <utility>
+
namespace clang::ssaf {
+class EntityName;
+class TUSummary;
+
class TUSummaryBuilder {
- // Empty for now.
+public:
+ explicit TUSummaryBuilder(TUSummary &Summary) : Summary(Summary) {}
+
+ /// Add an entity to the summary and return its EntityId.
+ /// If the entity already exists, returns the existing ID (idempotent).
+ EntityId addEntity(const EntityName &E);
+
+ /// Associate the \p Data EntitySummary with the \p Entity.
+ /// This consumes the \p Data only if \p Entity wasn't associated yet with the
+ /// same kind of EntitySummary.
+ /// \returns a pointer to the EntitySummary and whether it inserted or not.
+ template <typename ConcreteEntitySummary,
+ DerivesFromEntitySummary<ConcreteEntitySummary> * = nullptr>
+ std::pair<EntitySummary *, bool>
+ addSummary(EntityId Entity, std::unique_ptr<ConcreteEntitySummary> &&Data) {
+ std::unique_ptr<EntitySummary> TypeErasedData = std::move(Data);
+ auto [It, Inserted] = addSummaryImpl(Entity, std::move(TypeErasedData));
+ // Move it back on failue to keep the `Data` unconsumed.
+ if (!Inserted) {
+ Data = std::unique_ptr<ConcreteEntitySummary>(
+ static_cast<ConcreteEntitySummary *>(TypeErasedData.release()));
+ }
+ return {It, Inserted};
+ }
----------------
steakhal wrote:
The problem here is that most people would use `std::make_unique<FancySummary>(...)` that would create a `std::unique_ptr<FancySummary>`.
However, the `addSummary` would only take a `std::unique_ptr<EntitySummary>` so a conversion would need to happen; so at the callsite it would more-or-less implicitly look like this:
```c++
auto Summ = std::make_unique<FancySummary>(...);
Builder.addSummary(ID, std::unique_ptr<EntitySummary>(std::move(Summ))); // <-- implicit uptr conversion is now spelled out.
```
And that means that the callsite has no way of recovering the FancySummary object if the insertion failed.
Constructing a FancySummary might be expensive, so we don't want to lose it.
However, with the templated addSummary, I can restore back the summary as-if the move didn't happen.
This is natural. The `try_emplace` has the same contract - it only moves on insertion.
Now the question is, how should an extractor recover a failed insertion?
It could take the existing summary and "merge" it with the one it wanted to insert. Since the `addSummary` returns the pointer to the object it can store back the result without an additional traversal of the map.
It could sanity check that the existing summary is semantically equivalent to the one it wanted to insert.
Or it can discard it - and assume the existing one is "good enough".
Finally, it could just assert that the insertion must always go through and abort if that's not the case.
Remember, it depends on the analysis (extractor) if a duplicated EntitySummary is fine or not.
For example, extracting some information about definitions. We can have duplicated definitions of some types, like enums for example, or even structs in some context. This would mean that `addSummary` would need to deal with duplicated EntitySummaries of this kind.
For the most part, C++ is kind of guarded by this under the One definition rule, but this might not always hold for other types of program properties.
https://github.com/llvm/llvm-project/pull/181220
More information about the cfe-commits
mailing list