[clang] [clang][ssaf] Add EntityLinkage support to TUSummaryBuilder and CallGraphExtractor (PR #194448)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Apr 27 12:55:02 PDT 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-ssaf
Author: Balázs Benics (steakhal)
<details>
<summary>Changes</summary>
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
---
Patch is 38.14 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/194448.diff
9 Files Affected:
- (modified) clang/include/clang/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummaryBuilder.h (+8)
- (modified) clang/lib/ScalableStaticAnalysisFramework/Analyses/CallGraph/CallGraphExtractor.cpp (+2)
- (modified) clang/lib/ScalableStaticAnalysisFramework/Core/Model/EntityIdTable.cpp (+1-1)
- (modified) clang/lib/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummaryBuilder.cpp (+35)
- (modified) clang/test/Analysis/Scalable/ssaf-linker/Outputs/lu-1+2.json (+97-97)
- (modified) clang/test/Analysis/Scalable/ssaf-linker/Outputs/lu-1.json (+53-53)
- (modified) clang/test/Analysis/Scalable/ssaf-linker/Outputs/lu-2.json (+54-54)
- (modified) clang/unittests/ScalableStaticAnalysisFramework/EntityIdTableTest.cpp (+21-8)
- (modified) clang/unittests/ScalableStaticAnalysisFramework/TUSummaryBuilderTest.cpp (+54)
``````````diff
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
+ ...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/194448
More information about the cfe-commits
mailing list