[clang] [clang][ssaf] Add EntityLinkage support to TUSummaryBuilder and CallGraphExtractor (PR #194448)
Balázs Benics via cfe-commits
cfe-commits at lists.llvm.org
Mon Apr 27 12:54:33 PDT 2026
https://github.com/steakhal created https://github.com/llvm/llvm-project/pull/194448
Add TUSummaryBuilder::setLinkage to record linkage for each entity.
CallGraphExtractor now calls setLinkage for both callers and callees.
This API won't live for long. I already have the patches to bundle this into `addEntity`.
However, for making reviews easier, I think it's better to land this first and then the patches I mentioned to reduce the PR sizes.
Hopefully, we can merge these two in close succession to not confuse anynoe rebasing and constantly changing these APIs.
Assisted-By: claude
>From a5fb55354f74749cb3dee877f74df09cf9ceff17 Mon Sep 17 00:00:00 2001
From: Balazs Benics <benicsbalazs at gmail.com>
Date: Fri, 10 Apr 2026 11:04:55 +0100
Subject: [PATCH] [clang][ssaf] Add EntityLinkage support to TUSummaryBuilder
and CallGraphExtractor
Add TUSummaryBuilder::setLinkage to record linkage for each entity.
CallGraphExtractor now calls setLinkage for both callers and callees.
This API won't live for long. I already have the patches to bundle this
into `addEntity`. However, for making reviews easier, I think it's
better to land this first and then the patches I mentioned to reduce the
PR sizes.
Hopefully, we can merge these two in close succession to not confuse
anynoe rebasing and constantly changing these APIs.
Assisted-By: claude
---
.../Core/TUSummary/TUSummaryBuilder.h | 8 +
.../Analyses/CallGraph/CallGraphExtractor.cpp | 2 +
.../Core/Model/EntityIdTable.cpp | 2 +-
.../Core/TUSummary/TUSummaryBuilder.cpp | 35 ++++
.../Scalable/ssaf-linker/Outputs/lu-1+2.json | 194 +++++++++---------
.../Scalable/ssaf-linker/Outputs/lu-1.json | 106 +++++-----
.../Scalable/ssaf-linker/Outputs/lu-2.json | 108 +++++-----
.../EntityIdTableTest.cpp | 29 ++-
.../TUSummaryBuilderTest.cpp | 54 +++++
9 files changed, 325 insertions(+), 213 deletions(-)
diff --git a/clang/include/clang/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummaryBuilder.h b/clang/include/clang/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummaryBuilder.h
index d386876675873..666d1b71dd42c 100644
--- a/clang/include/clang/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummaryBuilder.h
+++ b/clang/include/clang/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummaryBuilder.h
@@ -9,7 +9,9 @@
#ifndef LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_CORE_TUSUMMARY_TUSUMMARYBUILDER_H
#define LLVM_CLANG_SCALABLESTATICANALYSISFRAMEWORK_CORE_TUSUMMARY_TUSUMMARYBUILDER_H
+#include "clang/AST/DeclBase.h"
#include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityId.h"
+#include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityLinkage.h"
#include "clang/ScalableStaticAnalysisFramework/Core/TUSummary/EntitySummary.h"
#include <memory>
#include <utility>
@@ -23,6 +25,12 @@ class TUSummaryBuilder {
public:
explicit TUSummaryBuilder(TUSummary &Summary) : Summary(Summary) {}
+ /// Set the linkage of the \p Entity.
+ void setLinkage(EntityId Entity, EntityLinkageType Linkage);
+
+ /// Set the linkage of the \p Entity.
+ void setLinkage(EntityId Entity, const Decl *D);
+
/// 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);
diff --git a/clang/lib/ScalableStaticAnalysisFramework/Analyses/CallGraph/CallGraphExtractor.cpp b/clang/lib/ScalableStaticAnalysisFramework/Analyses/CallGraph/CallGraphExtractor.cpp
index 1dbed7e0b0d8a..e0d24af1f441b 100644
--- a/clang/lib/ScalableStaticAnalysisFramework/Analyses/CallGraph/CallGraphExtractor.cpp
+++ b/clang/lib/ScalableStaticAnalysisFramework/Analyses/CallGraph/CallGraphExtractor.cpp
@@ -85,6 +85,7 @@ void CallGraphExtractor::handleCallGraphNode(const ASTContext &Ctx,
continue;
EntityId CalleeId = SummaryBuilder.addEntity(*CalleeName);
+ SummaryBuilder.setLinkage(CalleeId, CalleeDecl);
if (const auto *MD = dyn_cast_or_null<CXXMethodDecl>(CalleeDecl);
MD && MD->isVirtual()) {
FnSummary->VirtualCallees.insert(CalleeId);
@@ -94,6 +95,7 @@ void CallGraphExtractor::handleCallGraphNode(const ASTContext &Ctx,
}
EntityId CallerId = SummaryBuilder.addEntity(*CallerName);
+ SummaryBuilder.setLinkage(CallerId, Definition);
SummaryBuilder.addSummary(CallerId, std::move(FnSummary));
}
diff --git a/clang/lib/ScalableStaticAnalysisFramework/Core/Model/EntityIdTable.cpp b/clang/lib/ScalableStaticAnalysisFramework/Core/Model/EntityIdTable.cpp
index cb514581ca9ec..7b64a1ca5249e 100644
--- a/clang/lib/ScalableStaticAnalysisFramework/Core/Model/EntityIdTable.cpp
+++ b/clang/lib/ScalableStaticAnalysisFramework/Core/Model/EntityIdTable.cpp
@@ -12,7 +12,7 @@
namespace clang::ssaf {
EntityId EntityIdTable::getId(const EntityName &Name) {
- EntityId Id(Entities.size());
+ EntityId Id(Entities.size() + 1);
const auto Res = Entities.try_emplace(Name, Id);
return Res.first->second;
}
diff --git a/clang/lib/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummaryBuilder.cpp b/clang/lib/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummaryBuilder.cpp
index f3280b02ce5ef..79051d488c0aa 100644
--- a/clang/lib/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummaryBuilder.cpp
+++ b/clang/lib/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummaryBuilder.cpp
@@ -1,5 +1,7 @@
#include "clang/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummaryBuilder.h"
+#include "clang/AST/Decl.h"
#include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityId.h"
+#include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityLinkage.h"
#include "clang/ScalableStaticAnalysisFramework/Core/TUSummary/EntitySummary.h"
#include "clang/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummary.h"
#include <memory>
@@ -8,6 +10,39 @@
using namespace clang;
using namespace ssaf;
+static EntityLinkageType getLinkageForDecl(const Decl *D) {
+ const auto *ND = dyn_cast<NamedDecl>(D);
+ if (!ND)
+ return EntityLinkageType::None;
+
+ switch (ND->getFormalLinkage()) {
+ case Linkage::Invalid: {
+ llvm_unreachable("Shouldn't be invalid");
+ }
+ case Linkage::None:
+ return EntityLinkageType::None;
+ case Linkage::Internal:
+ return EntityLinkageType::Internal;
+ case Linkage::UniqueExternal:
+ return EntityLinkageType::Internal;
+ case Linkage::VisibleNone:
+ return EntityLinkageType::Internal;
+ case Linkage::Module:
+ return EntityLinkageType::External;
+ case Linkage::External:
+ return EntityLinkageType::External;
+ }
+ llvm_unreachable("Unhandled clang::Linkage kind");
+}
+
+void TUSummaryBuilder::setLinkage(EntityId Entity, const Decl *D) {
+ Summary.LinkageTable.try_emplace(Entity, getLinkageForDecl(D));
+}
+
+void TUSummaryBuilder::setLinkage(EntityId Entity, EntityLinkageType Linkage) {
+ Summary.LinkageTable.try_emplace(Entity, Linkage);
+}
+
EntityId TUSummaryBuilder::addEntity(const EntityName &E) {
return Summary.IdTable.getId(E);
}
diff --git a/clang/test/Analysis/Scalable/ssaf-linker/Outputs/lu-1+2.json b/clang/test/Analysis/Scalable/ssaf-linker/Outputs/lu-1+2.json
index 568a175730ce6..ff388bfe4b41b 100644
--- a/clang/test/Analysis/Scalable/ssaf-linker/Outputs/lu-1+2.json
+++ b/clang/test/Analysis/Scalable/ssaf-linker/Outputs/lu-1+2.json
@@ -3,152 +3,152 @@
{
"summary_data": [
{
- "entity_id": 0,
+ "entity_id": 1,
"entity_summary": {
"call_count": 3,
"callees": [
- {
- "@": 1
- },
{
"@": 2
},
{
"@": 3
+ },
+ {
+ "@": 4
}
]
}
},
{
- "entity_id": 1,
+ "entity_id": 2,
"entity_summary": {
"call_count": 2,
"callees": [
{
- "@": 0
+ "@": 1
},
{
- "@": 4
+ "@": 5
}
]
}
},
{
- "entity_id": 2,
+ "entity_id": 3,
"entity_summary": {
"call_count": 1,
"callees": [
{
- "@": 5
+ "@": 6
}
]
}
},
{
- "entity_id": 3,
+ "entity_id": 4,
"entity_summary": {
"call_count": 2,
"callees": [
{
- "@": 0
+ "@": 1
},
{
- "@": 1
+ "@": 2
}
]
}
},
{
- "entity_id": 4,
+ "entity_id": 5,
"entity_summary": {
"call_count": 1,
"callees": [
{
- "@": 3
+ "@": 4
}
]
}
},
{
- "entity_id": 5,
+ "entity_id": 6,
"entity_summary": {
"call_count": 3,
"callees": [
{
- "@": 0
+ "@": 1
},
{
- "@": 3
+ "@": 4
},
{
- "@": 4
+ "@": 5
}
]
}
},
{
- "entity_id": 6,
+ "entity_id": 7,
"entity_summary": {
"call_count": 2,
"callees": [
{
- "@": 0
+ "@": 1
},
{
- "@": 8
+ "@": 9
}
]
}
},
{
- "entity_id": 7,
+ "entity_id": 8,
"entity_summary": {
"call_count": 1,
"callees": [
{
- "@": 9
+ "@": 10
}
]
}
},
{
- "entity_id": 8,
+ "entity_id": 9,
"entity_summary": {
"call_count": 2,
"callees": [
{
- "@": 0
+ "@": 1
},
{
- "@": 7
+ "@": 8
}
]
}
},
{
- "entity_id": 9,
+ "entity_id": 10,
"entity_summary": {
"call_count": 1,
"callees": [
{
- "@": 8
+ "@": 9
}
]
}
},
{
- "entity_id": 10,
+ "entity_id": 11,
"entity_summary": {
"call_count": 3,
"callees": [
- {
- "@": 6
- },
{
"@": 7
},
{
"@": 8
+ },
+ {
+ "@": 9
}
]
}
@@ -159,21 +159,21 @@
{
"summary_data": [
{
- "entity_id": 0,
+ "entity_id": 1,
"entity_summary": {
"direct": {
- "@": 3
+ "@": 4
},
"indirect": [
{
"entity": {
- "@": 1
+ "@": 2
},
"level": 1
},
{
"entity": {
- "@": 4
+ "@": 5
},
"level": 2
}
@@ -181,21 +181,21 @@
}
},
{
- "entity_id": 1,
+ "entity_id": 2,
"entity_summary": {
"direct": {
- "@": 0
+ "@": 1
},
"indirect": [
{
"entity": {
- "@": 2
+ "@": 3
},
"level": 1
},
{
"entity": {
- "@": 5
+ "@": 6
},
"level": 2
}
@@ -203,15 +203,15 @@
}
},
{
- "entity_id": 2,
+ "entity_id": 3,
"entity_summary": {
"direct": {
- "@": 1
+ "@": 2
},
"indirect": [
{
"entity": {
- "@": 3
+ "@": 4
},
"level": 1
}
@@ -219,21 +219,21 @@
}
},
{
- "entity_id": 3,
+ "entity_id": 4,
"entity_summary": {
"direct": {
- "@": 4
+ "@": 5
},
"indirect": [
{
"entity": {
- "@": 0
+ "@": 1
},
"level": 1
},
{
"entity": {
- "@": 2
+ "@": 3
},
"level": 2
}
@@ -241,15 +241,15 @@
}
},
{
- "entity_id": 4,
+ "entity_id": 5,
"entity_summary": {
"direct": {
- "@": 5
+ "@": 6
},
"indirect": [
{
"entity": {
- "@": 1
+ "@": 2
},
"level": 1
}
@@ -257,27 +257,27 @@
}
},
{
- "entity_id": 5,
+ "entity_id": 6,
"entity_summary": {
"direct": {
- "@": 2
+ "@": 3
},
"indirect": [
{
"entity": {
- "@": 0
+ "@": 1
},
"level": 1
},
{
"entity": {
- "@": 3
+ "@": 4
},
"level": 2
},
{
"entity": {
- "@": 4
+ "@": 5
},
"level": 3
}
@@ -285,15 +285,15 @@
}
},
{
- "entity_id": 6,
+ "entity_id": 7,
"entity_summary": {
"direct": {
- "@": 0
+ "@": 1
},
"indirect": [
{
"entity": {
- "@": 9
+ "@": 10
},
"level": 1
}
@@ -301,21 +301,21 @@
}
},
{
- "entity_id": 7,
+ "entity_id": 8,
"entity_summary": {
"direct": {
- "@": 10
+ "@": 11
},
"indirect": [
{
"entity": {
- "@": 0
+ "@": 1
},
"level": 1
},
{
"entity": {
- "@": 8
+ "@": 9
},
"level": 2
}
@@ -323,21 +323,21 @@
}
},
{
- "entity_id": 8,
+ "entity_id": 9,
"entity_summary": {
"direct": {
- "@": 6
+ "@": 7
},
"indirect": [
{
"entity": {
- "@": 7
+ "@": 8
},
"level": 1
},
{
"entity": {
- "@": 0
+ "@": 1
},
"level": 2
}
@@ -345,21 +345,21 @@
}
},
{
- "entity_id": 9,
+ "entity_id": 10,
"entity_summary": {
"direct": {
- "@": 7
+ "@": 8
},
"indirect": [
{
"entity": {
- "@": 10
+ "@": 11
},
"level": 1
},
{
"entity": {
- "@": 8
+ "@": 9
},
"level": 2
}
@@ -367,27 +367,27 @@
}
},
{
- "entity_id": 10,
+ "entity_id": 11,
"entity_summary": {
"direct": {
- "@": 9
+ "@": 10
},
"indirect": [
{
"entity": {
- "@": 6
+ "@": 7
},
"level": 1
},
{
"entity": {
- "@": 7
+ "@": 8
},
"level": 2
},
{
"entity": {
- "@": 0
+ "@": 1
},
"level": 3
}
@@ -400,7 +400,7 @@
],
"id_table": [
{
- "id": 0,
+ "id": 1,
"name": {
"namespace": [
{
@@ -413,7 +413,7 @@
}
},
{
- "id": 1,
+ "id": 2,
"name": {
"namespace": [
{
@@ -430,7 +430,7 @@
}
},
{
- "id": 6,
+ "id": 7,
"name": {
"namespace": [
{
@@ -447,7 +447,7 @@
}
},
{
- "id": 2,
+ "id": 3,
"name": {
"namespace": [
{
@@ -464,7 +464,7 @@
}
},
{
- "id": 7,
+ "id": 8,
"name": {
"namespace": [
{
@@ -481,7 +481,7 @@
}
},
{
- "id": 3,
+ "id": 4,
"name": {
"namespace": [
{
@@ -494,7 +494,7 @@
}
},
{
- "id": 8,
+ "id": 9,
"name": {
"namespace": [
{
@@ -507,7 +507,7 @@
}
},
{
- "id": 4,
+ "id": 5,
"name": {
"namespace": [
{
@@ -524,7 +524,7 @@
}
},
{
- "id": 9,
+ "id": 10,
"name": {
"namespace": [
{
@@ -541,7 +541,7 @@
}
},
{
- "id": 5,
+ "id": 6,
"name": {
"namespace": [
{
@@ -558,7 +558,7 @@
}
},
{
- "id": 10,
+ "id": 11,
"name": {
"namespace": [
{
@@ -577,67 +577,67 @@
],
"linkage_table": [
{
- "id": 0,
+ "id": 1,
"linkage": {
"type": "External"
}
},
{
- "id": 1,
+ "id": 2,
"linkage": {
"type": "Internal"
}
},
{
- "id": 2,
+ "id": 3,
"linkage": {
"type": "None"
}
},
{
- "id": 3,
+ "id": 4,
"linkage": {
"type": "External"
}
},
{
- "id": 4,
+ "id": 5,
"linkage": {
"type": "Internal"
}
},
{
- "id": 5,
+ "id": 6,
"linkage": {
"type": "None"
}
},
{
- "id": 6,
+ "id": 7,
"linkage": {
"type": "Internal"
}
},
{
- "id": 7,
+ "id": 8,
"linkage": {
"type": "None"
}
},
{
- "id": 8,
+ "id": 9,
"linkage": {
"type": "External"
}
},
{
- "id": 9,
+ "id": 10,
"linkage": {
"type": "Internal"
}
},
{
- "id": 10,
+ "id": 11,
"linkage": {
"type": "None"
}
diff --git a/clang/test/Analysis/Scalable/ssaf-linker/Outputs/lu-1.json b/clang/test/Analysis/Scalable/ssaf-linker/Outputs/lu-1.json
index 004e5490bba26..7be03f9b76e30 100644
--- a/clang/test/Analysis/Scalable/ssaf-linker/Outputs/lu-1.json
+++ b/clang/test/Analysis/Scalable/ssaf-linker/Outputs/lu-1.json
@@ -3,85 +3,85 @@
{
"summary_data": [
{
- "entity_id": 0,
+ "entity_id": 1,
"entity_summary": {
"call_count": 3,
"callees": [
- {
- "@": 1
- },
{
"@": 2
},
{
"@": 3
+ },
+ {
+ "@": 4
}
]
}
},
{
- "entity_id": 1,
+ "entity_id": 2,
"entity_summary": {
"call_count": 2,
"callees": [
{
- "@": 0
+ "@": 1
},
{
- "@": 4
+ "@": 5
}
]
}
},
{
- "entity_id": 2,
+ "entity_id": 3,
"entity_summary": {
"call_count": 1,
"callees": [
{
- "@": 5
+ "@": 6
}
]
}
},
{
- "entity_id": 3,
+ "entity_id": 4,
"entity_summary": {
"call_count": 2,
"callees": [
{
- "@": 0
+ "@": 1
},
{
- "@": 1
+ "@": 2
}
]
}
},
{
- "entity_id": 4,
+ "entity_id": 5,
"entity_summary": {
"call_count": 1,
"callees": [
{
- "@": 3
+ "@": 4
}
]
}
},
{
- "entity_id": 5,
+ "entity_id": 6,
"entity_summary": {
"call_count": 3,
"callees": [
{
- "@": 0
+ "@": 1
},
{
- "@": 3
+ "@": 4
},
{
- "@": 4
+ "@": 5
}
]
}
@@ -92,21 +92,21 @@
{
"summary_data": [
{
- "entity_id": 0,
+ "entity_id": 1,
"entity_summary": {
"direct": {
- "@": 3
+ "@": 4
},
"indirect": [
{
"entity": {
- "@": 1
+ "@": 2
},
"level": 1
},
{
"entity": {
- "@": 4
+ "@": 5
},
"level": 2
}
@@ -114,21 +114,21 @@
}
},
{
- "entity_id": 1,
+ "entity_id": 2,
"entity_summary": {
"direct": {
- "@": 0
+ "@": 1
},
"indirect": [
{
"entity": {
- "@": 2
+ "@": 3
},
"level": 1
},
{
"entity": {
- "@": 5
+ "@": 6
},
"level": 2
}
@@ -136,15 +136,15 @@
}
},
{
- "entity_id": 2,
+ "entity_id": 3,
"entity_summary": {
"direct": {
- "@": 1
+ "@": 2
},
"indirect": [
{
"entity": {
- "@": 3
+ "@": 4
},
"level": 1
}
@@ -152,21 +152,21 @@
}
},
{
- "entity_id": 3,
+ "entity_id": 4,
"entity_summary": {
"direct": {
- "@": 4
+ "@": 5
},
"indirect": [
{
"entity": {
- "@": 0
+ "@": 1
},
"level": 1
},
{
"entity": {
- "@": 2
+ "@": 3
},
"level": 2
}
@@ -174,15 +174,15 @@
}
},
{
- "entity_id": 4,
+ "entity_id": 5,
"entity_summary": {
"direct": {
- "@": 5
+ "@": 6
},
"indirect": [
{
"entity": {
- "@": 1
+ "@": 2
},
"level": 1
}
@@ -190,27 +190,27 @@
}
},
{
- "entity_id": 5,
+ "entity_id": 6,
"entity_summary": {
"direct": {
- "@": 2
+ "@": 3
},
"indirect": [
{
"entity": {
- "@": 0
+ "@": 1
},
"level": 1
},
{
"entity": {
- "@": 3
+ "@": 4
},
"level": 2
},
{
"entity": {
- "@": 4
+ "@": 5
},
"level": 3
}
@@ -223,7 +223,7 @@
],
"id_table": [
{
- "id": 0,
+ "id": 1,
"name": {
"namespace": [
{
@@ -236,7 +236,7 @@
}
},
{
- "id": 1,
+ "id": 2,
"name": {
"namespace": [
{
@@ -253,7 +253,7 @@
}
},
{
- "id": 2,
+ "id": 3,
"name": {
"namespace": [
{
@@ -270,7 +270,7 @@
}
},
{
- "id": 3,
+ "id": 4,
"name": {
"namespace": [
{
@@ -283,7 +283,7 @@
}
},
{
- "id": 4,
+ "id": 5,
"name": {
"namespace": [
{
@@ -300,7 +300,7 @@
}
},
{
- "id": 5,
+ "id": 6,
"name": {
"namespace": [
{
@@ -319,37 +319,37 @@
],
"linkage_table": [
{
- "id": 0,
+ "id": 1,
"linkage": {
"type": "External"
}
},
{
- "id": 1,
+ "id": 2,
"linkage": {
"type": "Internal"
}
},
{
- "id": 2,
+ "id": 3,
"linkage": {
"type": "None"
}
},
{
- "id": 3,
+ "id": 4,
"linkage": {
"type": "External"
}
},
{
- "id": 4,
+ "id": 5,
"linkage": {
"type": "Internal"
}
},
{
- "id": 5,
+ "id": 6,
"linkage": {
"type": "None"
}
diff --git a/clang/test/Analysis/Scalable/ssaf-linker/Outputs/lu-2.json b/clang/test/Analysis/Scalable/ssaf-linker/Outputs/lu-2.json
index 1ed0e7fd38f6c..e5fb7bbe1479a 100644
--- a/clang/test/Analysis/Scalable/ssaf-linker/Outputs/lu-2.json
+++ b/clang/test/Analysis/Scalable/ssaf-linker/Outputs/lu-2.json
@@ -3,85 +3,85 @@
{
"summary_data": [
{
- "entity_id": 0,
+ "entity_id": 1,
"entity_summary": {
"call_count": 3,
"callees": [
{
- "@": 1
+ "@": 2
},
{
- "@": 2
+ "@": 3
},
{
- "@": 5
+ "@": 6
}
]
}
},
{
- "entity_id": 1,
+ "entity_id": 2,
"entity_summary": {
"call_count": 2,
"callees": [
{
- "@": 0
+ "@": 1
},
{
- "@": 3
+ "@": 4
}
]
}
},
{
- "entity_id": 2,
+ "entity_id": 3,
"entity_summary": {
"call_count": 1,
"callees": [
{
- "@": 4
+ "@": 5
}
]
}
},
{
- "entity_id": 3,
+ "entity_id": 4,
"entity_summary": {
"call_count": 2,
"callees": [
{
- "@": 0
+ "@": 1
},
{
- "@": 2
+ "@": 3
}
]
}
},
{
- "entity_id": 4,
+ "entity_id": 5,
"entity_summary": {
"call_count": 1,
"callees": [
{
- "@": 3
+ "@": 4
}
]
}
},
{
- "entity_id": 5,
+ "entity_id": 6,
"entity_summary": {
"call_count": 3,
"callees": [
- {
- "@": 1
- },
{
"@": 2
},
{
"@": 3
+ },
+ {
+ "@": 4
}
]
}
@@ -92,21 +92,21 @@
{
"summary_data": [
{
- "entity_id": 0,
+ "entity_id": 1,
"entity_summary": {
"direct": {
- "@": 3
+ "@": 4
},
"indirect": [
{
"entity": {
- "@": 2
+ "@": 3
},
"level": 1
},
{
"entity": {
- "@": 5
+ "@": 6
},
"level": 2
}
@@ -114,15 +114,15 @@
}
},
{
- "entity_id": 1,
+ "entity_id": 2,
"entity_summary": {
"direct": {
- "@": 0
+ "@": 1
},
"indirect": [
{
"entity": {
- "@": 4
+ "@": 5
},
"level": 1
}
@@ -130,21 +130,21 @@
}
},
{
- "entity_id": 2,
+ "entity_id": 3,
"entity_summary": {
"direct": {
- "@": 5
+ "@": 6
},
"indirect": [
{
"entity": {
- "@": 0
+ "@": 1
},
"level": 1
},
{
"entity": {
- "@": 3
+ "@": 4
},
"level": 2
}
@@ -152,21 +152,21 @@
}
},
{
- "entity_id": 3,
+ "entity_id": 4,
"entity_summary": {
"direct": {
- "@": 1
+ "@": 2
},
"indirect": [
{
"entity": {
- "@": 2
+ "@": 3
},
"level": 1
},
{
"entity": {
- "@": 0
+ "@": 1
},
"level": 2
}
@@ -174,21 +174,21 @@
}
},
{
- "entity_id": 4,
+ "entity_id": 5,
"entity_summary": {
"direct": {
- "@": 2
+ "@": 3
},
"indirect": [
{
"entity": {
- "@": 5
+ "@": 6
},
"level": 1
},
{
"entity": {
- "@": 3
+ "@": 4
},
"level": 2
}
@@ -196,27 +196,27 @@
}
},
{
- "entity_id": 5,
+ "entity_id": 6,
"entity_summary": {
"direct": {
- "@": 4
+ "@": 5
},
"indirect": [
{
"entity": {
- "@": 1
+ "@": 2
},
"level": 1
},
{
"entity": {
- "@": 2
+ "@": 3
},
"level": 2
},
{
"entity": {
- "@": 0
+ "@": 1
},
"level": 3
}
@@ -229,7 +229,7 @@
],
"id_table": [
{
- "id": 0,
+ "id": 1,
"name": {
"namespace": [
{
@@ -242,7 +242,7 @@
}
},
{
- "id": 1,
+ "id": 2,
"name": {
"namespace": [
{
@@ -259,7 +259,7 @@
}
},
{
- "id": 2,
+ "id": 3,
"name": {
"namespace": [
{
@@ -276,7 +276,7 @@
}
},
{
- "id": 3,
+ "id": 4,
"name": {
"namespace": [
{
@@ -289,7 +289,7 @@
}
},
{
- "id": 4,
+ "id": 5,
"name": {
"namespace": [
{
@@ -306,7 +306,7 @@
}
},
{
- "id": 5,
+ "id": 6,
"name": {
"namespace": [
{
@@ -325,37 +325,37 @@
],
"linkage_table": [
{
- "id": 0,
+ "id": 1,
"linkage": {
"type": "External"
}
},
{
- "id": 1,
+ "id": 2,
"linkage": {
"type": "Internal"
}
},
{
- "id": 2,
+ "id": 3,
"linkage": {
"type": "None"
}
},
{
- "id": 3,
+ "id": 4,
"linkage": {
"type": "External"
}
},
{
- "id": 4,
+ "id": 5,
"linkage": {
"type": "Internal"
}
},
{
- "id": 5,
+ "id": 6,
"linkage": {
"type": "None"
}
diff --git a/clang/unittests/ScalableStaticAnalysisFramework/EntityIdTableTest.cpp b/clang/unittests/ScalableStaticAnalysisFramework/EntityIdTableTest.cpp
index 7afa4943bcb79..cb1eff88fec18 100644
--- a/clang/unittests/ScalableStaticAnalysisFramework/EntityIdTableTest.cpp
+++ b/clang/unittests/ScalableStaticAnalysisFramework/EntityIdTableTest.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityIdTable.h"
+#include "TestFixture.h"
#include "clang/ScalableStaticAnalysisFramework/Core/Model/BuildNamespace.h"
#include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityId.h"
#include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityName.h"
@@ -16,7 +17,9 @@ namespace clang {
namespace ssaf {
namespace {
-TEST(EntityIdTableTest, CreateNewEntity) {
+struct EntityIdTableTest : ssaf::TestFixture {};
+
+TEST_F(EntityIdTableTest, CreateNewEntity) {
EntityIdTable Table;
EntityName Entity("c:@F at foo", "", {});
@@ -25,7 +28,7 @@ TEST(EntityIdTableTest, CreateNewEntity) {
EXPECT_TRUE(Table.contains(Entity));
}
-TEST(EntityIdTableTest, Idempotency) {
+TEST_F(EntityIdTableTest, Idempotency) {
EntityIdTable Table;
EntityName Entity("c:@F at foo", "", {});
@@ -40,7 +43,7 @@ TEST(EntityIdTableTest, Idempotency) {
EXPECT_EQ(Id1, Id3);
}
-TEST(EntityIdTableTest, ExistsTrue) {
+TEST_F(EntityIdTableTest, ExistsTrue) {
EntityIdTable Table;
EntityName Entity1("c:@F at foo", "", {});
@@ -53,7 +56,7 @@ TEST(EntityIdTableTest, ExistsTrue) {
EXPECT_TRUE(Table.contains(Entity2));
}
-TEST(EntityIdTableTest, ExistsFalse) {
+TEST_F(EntityIdTableTest, ExistsFalse) {
EntityIdTable Table;
EntityName Entity1("c:@F at foo", "", {});
@@ -65,7 +68,7 @@ TEST(EntityIdTableTest, ExistsFalse) {
EXPECT_FALSE(Table.contains(Entity2));
}
-TEST(EntityIdTableTest, MultipleEntities) {
+TEST_F(EntityIdTableTest, MultipleEntities) {
EntityIdTable Table;
EntityName Entity1("c:@F at foo", "", {});
@@ -81,7 +84,7 @@ TEST(EntityIdTableTest, MultipleEntities) {
EXPECT_NE(Id2, Id3);
}
-TEST(EntityIdTableTest, WithBuildNamespace) {
+TEST_F(EntityIdTableTest, WithBuildNamespace) {
EntityIdTable Table;
NestedBuildNamespace NS = NestedBuildNamespace::makeCompilationUnit("test.o");
@@ -96,7 +99,7 @@ TEST(EntityIdTableTest, WithBuildNamespace) {
EXPECT_NE(Id1, Id2);
}
-TEST(EntityIdTableTest, ForEachEmptyTable) {
+TEST_F(EntityIdTableTest, ForEachEmptyTable) {
EntityIdTable Table;
int CallbackCount = 0;
@@ -106,7 +109,7 @@ TEST(EntityIdTableTest, ForEachEmptyTable) {
EXPECT_EQ(CallbackCount, 0);
}
-TEST(EntityIdTableTest, ForEachMultipleEntities) {
+TEST_F(EntityIdTableTest, ForEachMultipleEntities) {
EntityIdTable Table;
EntityName Entity1("c:@F at foo", "", {});
@@ -137,6 +140,16 @@ TEST(EntityIdTableTest, ForEachMultipleEntities) {
EXPECT_TRUE(VisitedNames.count(Entity3));
}
+TEST_F(EntityIdTableTest, IndexZeroIsReserved) {
+ EntityIdTable Table;
+ EntityId Id1 = Table.getId(EntityName{"c:@F at foo", "", {}});
+ EntityId Id2 = Table.getId(EntityName{"c:@F at bar", "", {}});
+
+ // Index 0 is reserved; the first assigned ID should start at 1.
+ EXPECT_NE(getIndex(Id1), 0U);
+ EXPECT_NE(getIndex(Id2), 0U);
+}
+
} // namespace
} // namespace ssaf
} // namespace clang
diff --git a/clang/unittests/ScalableStaticAnalysisFramework/TUSummaryBuilderTest.cpp b/clang/unittests/ScalableStaticAnalysisFramework/TUSummaryBuilderTest.cpp
index ece39e2164df7..23f8fb8abf4b0 100644
--- a/clang/unittests/ScalableStaticAnalysisFramework/TUSummaryBuilderTest.cpp
+++ b/clang/unittests/ScalableStaticAnalysisFramework/TUSummaryBuilderTest.cpp
@@ -10,6 +10,7 @@
#include "TestFixture.h"
#include "clang/ScalableStaticAnalysisFramework/Core/Model/BuildNamespace.h"
#include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityId.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/Serialization/SerializationFormat.h"
@@ -266,4 +267,57 @@ TEST_F(TUSummaryBuilderTest, AddConflictingSummaryToSameEntity) {
Optional(Field(&MockSummaryData1::Value, 30)));
}
+TEST_F(TUSummaryBuilderTest, SetLinkageWithExplicitType) {
+ EntityId ID = addTestEntity(Builder, "c:@F at foo");
+ Builder.setLinkage(ID, EntityLinkageType::External);
+
+ const auto < = getLinkageTable(Summary);
+ auto It = LT.find(ID);
+ ASSERT_NE(It, LT.end());
+ EXPECT_EQ(It->second.getLinkage(), EntityLinkageType::External);
+}
+
+TEST_F(TUSummaryBuilderTest, SetLinkageMultipleEntities) {
+ EntityId ID1 = addTestEntity(Builder, "c:@F at foo");
+ EntityId ID2 = addTestEntity(Builder, "c:@F at bar");
+
+ Builder.setLinkage(ID1, EntityLinkageType::External);
+ Builder.setLinkage(ID2, EntityLinkageType::Internal);
+
+ const auto < = getLinkageTable(Summary);
+ ASSERT_EQ(LT.size(), 2U);
+
+ auto It1 = LT.find(ID1);
+ ASSERT_NE(It1, LT.end());
+ EXPECT_EQ(It1->second.getLinkage(), EntityLinkageType::External);
+
+ auto It2 = LT.find(ID2);
+ ASSERT_NE(It2, LT.end());
+ EXPECT_EQ(It2->second.getLinkage(), EntityLinkageType::Internal);
+}
+
+TEST_F(TUSummaryBuilderTest, SetLinkageIsIdempotent) {
+ EntityId ID = addTestEntity(Builder, "c:@F at foo");
+
+ // First call sets the linkage.
+ Builder.setLinkage(ID, EntityLinkageType::Internal);
+ // Second call with a different value should not overwrite (try_emplace).
+ Builder.setLinkage(ID, EntityLinkageType::External);
+
+ const auto < = getLinkageTable(Summary);
+ auto It = LT.find(ID);
+ ASSERT_NE(It, LT.end());
+ EXPECT_EQ(It->second.getLinkage(), EntityLinkageType::Internal);
+}
+
+TEST_F(TUSummaryBuilderTest, SetLinkageNone) {
+ EntityId ID = addTestEntity(Builder, "c:@F at foo");
+ Builder.setLinkage(ID, EntityLinkageType::None);
+
+ const auto < = getLinkageTable(Summary);
+ auto It = LT.find(ID);
+ ASSERT_NE(It, LT.end());
+ EXPECT_EQ(It->second.getLinkage(), EntityLinkageType::None);
+}
+
} // namespace
More information about the cfe-commits
mailing list