[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