[clang] [clang][ssaf] Rework TUSummaryBuilder::addEntity to take NamedDecl (PR #194448)
Balázs Benics via cfe-commits
cfe-commits at lists.llvm.org
Tue Apr 28 08:23:49 PDT 2026
https://github.com/steakhal updated https://github.com/llvm/llvm-project/pull/194448
>From 072e87c3f6cedcfa34d181e5a10afa3a8ee2a8cc Mon Sep 17 00:00:00 2001
From: Balazs Benics <benicsbalazs at gmail.com>
Date: Tue, 28 Apr 2026 16:20:17 +0100
Subject: [PATCH 1/2] [clang][ssaf][NFC] Hoist findFnByName and findDeclByName
---
.../ASTEntityMappingTest.cpp | 31 ++++--------
.../FindDecl.h | 49 +++++++++++++++++++
2 files changed, 59 insertions(+), 21 deletions(-)
create mode 100644 clang/unittests/ScalableStaticAnalysisFramework/FindDecl.h
diff --git a/clang/unittests/ScalableStaticAnalysisFramework/ASTEntityMappingTest.cpp b/clang/unittests/ScalableStaticAnalysisFramework/ASTEntityMappingTest.cpp
index da921b7b7ab35..9d79647f841c8 100644
--- a/clang/unittests/ScalableStaticAnalysisFramework/ASTEntityMappingTest.cpp
+++ b/clang/unittests/ScalableStaticAnalysisFramework/ASTEntityMappingTest.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "clang/ScalableStaticAnalysisFramework/Core/ASTEntityMapping.h"
+#include "FindDecl.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
@@ -20,23 +21,11 @@ using namespace clang::ast_matchers;
namespace clang::ssaf {
namespace {
-// Helper function to find a declaration by name
-template <typename DeclType>
-const DeclType *findDecl(ASTContext &Ctx, StringRef Name) {
- auto Matcher = namedDecl(hasName(Name)).bind("decl");
- auto Matches = match(Matcher, Ctx);
- if (Matches.empty())
- return nullptr;
- if (auto Result = Matches[0].getNodeAs<DeclType>("decl"))
- return dyn_cast<DeclType>(Result->getCanonicalDecl());
- return nullptr;
-}
-
TEST(ASTEntityMappingTest, FunctionDecl) {
auto AST = tooling::buildASTFromCode(R"cpp(void foo() {})cpp");
auto &Ctx = AST->getASTContext();
- const auto *FD = findDecl<FunctionDecl>(Ctx, "foo");
+ const auto *FD = findFnByName("foo", Ctx);
ASSERT_NE(FD, nullptr);
auto EntityName = getEntityName(FD);
@@ -47,7 +36,7 @@ TEST(ASTEntityMappingTest, VarDecl) {
auto AST = tooling::buildASTFromCode(R"cpp(int x = 42;)cpp");
auto &Ctx = AST->getASTContext();
- const auto *VD = findDecl<VarDecl>(Ctx, "x");
+ const auto *VD = findDeclByName<VarDecl>("x", Ctx);
ASSERT_NE(VD, nullptr);
auto EntityName = getEntityName(VD);
@@ -58,7 +47,7 @@ TEST(ASTEntityMappingTest, ParmVarDecl) {
auto AST = tooling::buildASTFromCode(R"cpp(void foo(int x) {})cpp");
auto &Ctx = AST->getASTContext();
- const auto *FD = findDecl<FunctionDecl>(Ctx, "foo");
+ const auto *FD = findFnByName("foo", Ctx);
ASSERT_NE(FD, nullptr);
ASSERT_EQ(FD->param_size(), 1u);
@@ -73,7 +62,7 @@ TEST(ASTEntityMappingTest, RecordDecl) {
auto AST = tooling::buildASTFromCode(R"cpp(struct S {};)cpp");
auto &Ctx = AST->getASTContext();
- const auto *RD = findDecl<RecordDecl>(Ctx, "S");
+ const auto *RD = findDeclByName<RecordDecl>("S", Ctx);
ASSERT_NE(RD, nullptr);
auto EntityName = getEntityName(RD);
@@ -84,7 +73,7 @@ TEST(ASTEntityMappingTest, FieldDecl) {
auto AST = tooling::buildASTFromCode(R"cpp(struct S { int field; };)cpp");
auto &Ctx = AST->getASTContext();
- const auto *FD = findDecl<FieldDecl>(Ctx, "field");
+ const auto *FD = findDeclByName<FieldDecl>("field", Ctx);
ASSERT_NE(FD, nullptr);
auto EntityName = getEntityName(FD);
@@ -143,7 +132,7 @@ TEST(ASTEntityMappingTest, UnsupportedDecl) {
auto AST = tooling::buildASTFromCode(R"cpp(namespace N {})cpp");
auto &Ctx = AST->getASTContext();
- const auto *ND = findDecl<NamespaceDecl>(Ctx, "N");
+ const auto *ND = findDeclByName<NamespaceDecl>("N", Ctx);
ASSERT_NE(ND, nullptr);
auto EntityName = getEntityName(ND);
@@ -154,7 +143,7 @@ TEST(ASTEntityMappingTest, FunctionReturn) {
auto AST = tooling::buildASTFromCode(R"cpp(int foo() { return 42; })cpp");
auto &Ctx = AST->getASTContext();
- const auto *FD = findDecl<FunctionDecl>(Ctx, "foo");
+ const auto *FD = findFnByName("foo", Ctx);
ASSERT_NE(FD, nullptr);
auto EntityName = getEntityNameForReturn(FD);
@@ -196,8 +185,8 @@ TEST(ASTEntityMappingTest, DifferentFunctionsDifferentNames) {
)cpp");
auto &Ctx = AST->getASTContext();
- const auto *Foo = findDecl<FunctionDecl>(Ctx, "foo");
- const auto *Bar = findDecl<FunctionDecl>(Ctx, "bar");
+ const auto *Foo = findFnByName("foo", Ctx);
+ const auto *Bar = findFnByName("bar", Ctx);
ASSERT_NE(Foo, nullptr);
ASSERT_NE(Bar, nullptr);
diff --git a/clang/unittests/ScalableStaticAnalysisFramework/FindDecl.h b/clang/unittests/ScalableStaticAnalysisFramework/FindDecl.h
new file mode 100644
index 0000000000000..07c28c610380c
--- /dev/null
+++ b/clang/unittests/ScalableStaticAnalysisFramework/FindDecl.h
@@ -0,0 +1,49 @@
+//===- FindDecl.h -----------------------------------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_UNITTESTS_SCALABLESTATICANALYSISFRAMEWORK_FINDDECL_H
+#define LLVM_CLANG_UNITTESTS_SCALABLESTATICANALYSISFRAMEWORK_FINDDECL_H
+
+#include "clang/AST/Decl.h"
+#include "clang/AST/DynamicRecursiveASTVisitor.h"
+
+namespace clang::ssaf {
+
+template <typename SomeDecl = clang::NamedDecl>
+const SomeDecl *findDeclByName(StringRef Name, ASTContext &Ctx) {
+ class NamedDeclFinder : public DynamicRecursiveASTVisitor {
+ public:
+ StringRef SearchingName;
+ const NamedDecl *FoundDecl = nullptr;
+
+ NamedDeclFinder(StringRef SearchingName) : SearchingName(SearchingName) {}
+
+ bool VisitDecl(Decl *D) override {
+ if (const auto *ND = dyn_cast<SomeDecl>(D)) {
+ if (ND->getNameAsString() == SearchingName) {
+ FoundDecl = ND;
+ return false;
+ }
+ }
+ return true;
+ }
+ };
+
+ NamedDeclFinder Finder(Name);
+
+ Finder.TraverseDecl(Ctx.getTranslationUnitDecl());
+ return dyn_cast_or_null<SomeDecl>(Finder.FoundDecl);
+}
+
+inline const FunctionDecl *findFnByName(StringRef Name, ASTContext &Ctx) {
+ return findDeclByName<FunctionDecl>(Name, Ctx);
+}
+
+} // namespace clang::ssaf
+
+#endif // LLVM_CLANG_UNITTESTS_SCALABLESTATICANALYSISFRAMEWORK_FINDDECL_H
>From c60b9b9c149ffa4d93b0517a7890c52c9c1c515a Mon Sep 17 00:00:00 2001
From: Balazs Benics <benicsbalazs at gmail.com>
Date: Tue, 28 Apr 2026 16:21:21 +0100
Subject: [PATCH 2/2] [clang][ssaf] Rework addEntity to populate linkage as
well
---
.../EntityPointerLevel/EntityPointerLevel.h | 12 ++-
.../Core/TUSummary/TUSummaryBuilder.h | 16 +++-
.../Analyses/CallGraph/CallGraphExtractor.cpp | 17 ++--
.../EntityPointerLevel/EntityPointerLevel.cpp | 86 +++++++++++--------
.../UnsafeBufferUsageExtractor.cpp | 13 +--
.../Core/TUSummary/TUSummaryBuilder.cpp | 51 ++++++++++-
.../UnsafeBufferUsageTest.cpp | 60 +++----------
.../TUSummaryBuilderTest.cpp | 80 +++++++++++++----
8 files changed, 205 insertions(+), 130 deletions(-)
diff --git a/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/EntityPointerLevel/EntityPointerLevel.h b/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/EntityPointerLevel/EntityPointerLevel.h
index 429bb74fb417e..b46f0573177b3 100644
--- a/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/EntityPointerLevel/EntityPointerLevel.h
+++ b/clang/include/clang/ScalableStaticAnalysisFramework/Analyses/EntityPointerLevel/EntityPointerLevel.h
@@ -11,11 +11,10 @@
#include "clang/AST/Expr.h"
#include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityId.h"
-#include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityName.h"
-#include "llvm/ADT/STLFunctionalExtras.h"
#include <set>
namespace clang::ssaf {
+class TUSummaryBuilder;
/// An EntityPointerLevel is associated with a level of the declared
/// pointer/array type of an entity. In the fully-expanded spelling of the
@@ -93,9 +92,9 @@ using EntityPointerLevelSet =
/// \param Ctx the AST context of `E`
/// \param AddEntity the callback provided by the caller to convert EntityNames
/// to EntityIds.
-llvm::Expected<EntityPointerLevelSet> translateEntityPointerLevel(
- const Expr *E, ASTContext &Ctx,
- llvm::function_ref<EntityId(EntityName EN)> AddEntity);
+llvm::Expected<EntityPointerLevelSet>
+translateEntityPointerLevel(const Expr *E, ASTContext &Ctx,
+ TUSummaryBuilder &Builder);
/// Creates a `EntityPointerLevel` from a pair of an EntityId and a pointer
/// level:
@@ -109,8 +108,7 @@ EntityPointerLevel buildEntityPointerLevel(EntityId, unsigned);
/// \param IsFunRet true iff the created EPL is associated with the return type
/// of a function entity.
llvm::Expected<EntityPointerLevel>
-createEntityPointerLevel(const NamedDecl *ND,
- llvm::function_ref<EntityId(EntityName EN)> AddEntity,
+createEntityPointerLevel(const NamedDecl *ND, TUSummaryBuilder &Builder,
bool IsFunRet = false);
/// Creates a new EntityPointerLevel (EPL) from `E` by incrementing `E`'s
diff --git a/clang/include/clang/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummaryBuilder.h b/clang/include/clang/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummaryBuilder.h
index d386876675873..7b76dc49dc706 100644
--- a/clang/include/clang/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummaryBuilder.h
+++ b/clang/include/clang/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummaryBuilder.h
@@ -9,9 +9,11 @@
#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/TUSummary/EntitySummary.h"
#include <memory>
+#include <optional>
#include <utility>
namespace clang::ssaf {
@@ -23,9 +25,15 @@ class TUSummaryBuilder {
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);
+ /// Creates EntityName from the Decl, registers the entity, and sets its
+ /// linkage atomically.
+ /// \returns the EntityId, or std::nullopt if EntityName creation fails.
+ std::optional<EntityId> addEntity(const NamedDecl *D);
+
+ /// Creates EntityName for the return value of \p FD, registers the entity,
+ /// and sets its linkage atomically.
+ /// \returns the EntityId, or std::nullopt if EntityName creation fails.
+ std::optional<EntityId> addEntityForReturn(const FunctionDecl *FD);
/// Associate the \p Data \c EntitySummary with the \p Entity.
/// This consumes the \p Data only if \p Entity wasn't associated yet with the
@@ -39,6 +47,8 @@ class TUSummaryBuilder {
private:
TUSummary &Summary;
+ EntityId addEntityImpl(const EntityName &Name, const Decl *D);
+
std::pair<EntitySummary *, bool>
addSummaryImpl(EntityId Entity, std::unique_ptr<EntitySummary> &&Data);
};
diff --git a/clang/lib/ScalableStaticAnalysisFramework/Analyses/CallGraph/CallGraphExtractor.cpp b/clang/lib/ScalableStaticAnalysisFramework/Analyses/CallGraph/CallGraphExtractor.cpp
index 1dbed7e0b0d8a..22038e915a32b 100644
--- a/clang/lib/ScalableStaticAnalysisFramework/Analyses/CallGraph/CallGraphExtractor.cpp
+++ b/clang/lib/ScalableStaticAnalysisFramework/Analyses/CallGraph/CallGraphExtractor.cpp
@@ -14,7 +14,6 @@
#include "clang/Analysis/CallGraph.h"
#include "clang/Basic/SourceManager.h"
#include "clang/ScalableStaticAnalysisFramework/Analyses/CallGraph/CallGraphSummary.h"
-#include "clang/ScalableStaticAnalysisFramework/Core/ASTEntityMapping.h"
#include "clang/ScalableStaticAnalysisFramework/Core/TUSummary/ExtractorRegistry.h"
#include "clang/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummaryBuilder.h"
#include "llvm/ADT/STLExtras.h"
@@ -53,8 +52,8 @@ void CallGraphExtractor::handleCallGraphNode(const ASTContext &Ctx,
// FIXME: `clang::CallGraph` does not create entries for primary templates.
assert(!Definition->isTemplated());
- auto CallerName = getEntityName(Definition);
- if (!CallerName)
+ auto CallerId = SummaryBuilder.addEntity(Definition);
+ if (!CallerId)
return;
auto FnSummary = std::make_unique<CallGraphSummary>();
@@ -80,21 +79,19 @@ void CallGraphExtractor::handleCallGraphNode(const ASTContext &Ctx,
// FIXME: `clang::CallGraph` does not create entries for primary templates.
assert(!CalleeDecl->isTemplated());
- auto CalleeName = getEntityName(CalleeDecl);
- if (!CalleeName)
+ auto CalleeId = SummaryBuilder.addEntity(cast<NamedDecl>(CalleeDecl));
+ if (!CalleeId)
continue;
- EntityId CalleeId = SummaryBuilder.addEntity(*CalleeName);
if (const auto *MD = dyn_cast_or_null<CXXMethodDecl>(CalleeDecl);
MD && MD->isVirtual()) {
- FnSummary->VirtualCallees.insert(CalleeId);
+ FnSummary->VirtualCallees.insert(*CalleeId);
continue;
}
- FnSummary->DirectCallees.insert(CalleeId);
+ FnSummary->DirectCallees.insert(*CalleeId);
}
- EntityId CallerId = SummaryBuilder.addEntity(*CallerName);
- SummaryBuilder.addSummary(CallerId, std::move(FnSummary));
+ SummaryBuilder.addSummary(*CallerId, std::move(FnSummary));
}
static TUSummaryExtractorRegistry::Add<CallGraphExtractor>
diff --git a/clang/lib/ScalableStaticAnalysisFramework/Analyses/EntityPointerLevel/EntityPointerLevel.cpp b/clang/lib/ScalableStaticAnalysisFramework/Analyses/EntityPointerLevel/EntityPointerLevel.cpp
index 52e6705ec43af..7a760b72c9d11 100644
--- a/clang/lib/ScalableStaticAnalysisFramework/Analyses/EntityPointerLevel/EntityPointerLevel.cpp
+++ b/clang/lib/ScalableStaticAnalysisFramework/Analyses/EntityPointerLevel/EntityPointerLevel.cpp
@@ -12,8 +12,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/ScalableStaticAnalysisFramework/Analyses/EntityPointerLevel/EntityPointerLevelFormat.h"
-#include "clang/ScalableStaticAnalysisFramework/Core/ASTEntityMapping.h"
-#include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityName.h"
+#include "clang/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummaryBuilder.h"
#include <optional>
using namespace clang;
@@ -51,8 +50,23 @@ class EntityPointerLevelTranslator
E->getStmtClassName());
}
- EntityPointerLevel createEntityPointerLevelFor(const EntityName &Name) {
- return EntityPointerLevel({AddEntity(Name), 1});
+ Expected<EntityPointerLevel>
+ createEntityPointerLevelFor(const NamedDecl *ND) {
+ std::optional<EntityId> Id = Builder.addEntity(ND);
+ if (!Id)
+ return makeErrAtNode(Ctx, ND, "failed to create EntityId for %s",
+ ND->getDeclKindName());
+ return EntityPointerLevel{buildEntityPointerLevel(*Id, 1)};
+ }
+
+ Expected<EntityPointerLevel>
+ createEntityPointerLevelForReturn(const FunctionDecl *FD) {
+ std::optional<EntityId> Id = Builder.addEntityForReturn(FD);
+ if (!Id) {
+ return makeErrAtNode(Ctx, FD, "failed to create EntityId for function %s",
+ cast<NamedDecl>(FD)->getNameAsString().c_str());
+ }
+ return EntityPointerLevel{buildEntityPointerLevel(*Id, 1)};
}
// The common helper function for Translate(*base):
@@ -68,28 +82,25 @@ class EntityPointerLevelTranslator
return EntityPointerLevelSet{Incremented.begin(), Incremented.end()};
}
- std::function<EntityId(EntityName EN)> AddEntity;
+ TUSummaryBuilder &Builder;
ASTContext &Ctx;
public:
- EntityPointerLevelTranslator(std::function<EntityId(EntityName EN)> AddEntity,
- ASTContext &Ctx)
- : AddEntity(AddEntity), Ctx(Ctx) {}
+ EntityPointerLevelTranslator(TUSummaryBuilder &Builder, ASTContext &Ctx)
+ : Builder(Builder), Ctx(Ctx) {}
Expected<EntityPointerLevelSet> translate(const Expr *E) { return Visit(E); }
Expected<EntityPointerLevel> translate(const NamedDecl *D, bool IsRet) {
- if (IsRet && !isa<FunctionDecl>(D))
- return makeErrAtNode(
- Ctx, D,
- "attempt to call getEntityNameForReturn on a NamedDecl of %s kind",
- D->getDeclKindName());
-
- std::optional<EntityName> EN =
- IsRet ? getEntityNameForReturn(cast<FunctionDecl>(D))
- : getEntityName(D);
- if (EN)
- return createEntityPointerLevelFor(*EN);
- return makeEntityNameErr(Ctx, D);
+ if (!IsRet)
+ return createEntityPointerLevelFor(D);
+
+ if (const auto *FD = dyn_cast<FunctionDecl>(D))
+ return createEntityPointerLevelForReturn(FD);
+
+ return makeErrAtNode(
+ Ctx, D,
+ "attempt to call getEntityNameForReturn on a NamedDecl of %s kind",
+ D->getDeclKindName());
}
static EntityPointerLevel incrementPointerLevel(const EntityPointerLevel &E) {
@@ -167,10 +178,10 @@ class EntityPointerLevelTranslator
// Translate(f(...)) -> {} if it is an indirect call
// -> {(f_return, 1)}, otherwise
Expected<EntityPointerLevelSet> VisitCallExpr(const CallExpr *E) {
- if (auto *FD = E->getDirectCallee())
- if (auto FDEntityName = getEntityNameForReturn(FD))
- return EntityPointerLevelSet{
- createEntityPointerLevelFor(*FDEntityName)};
+ if (auto *FD = E->getDirectCallee()) {
+ if (auto ReturnId = Builder.addEntityForReturn(FD))
+ return EntityPointerLevelSet{buildEntityPointerLevel(*ReturnId, 1)};
+ }
return EntityPointerLevelSet{};
}
@@ -210,16 +221,18 @@ class EntityPointerLevelTranslator
// Translate(DRE) -> {(Decl, 1)}
Expected<EntityPointerLevelSet> VisitDeclRefExpr(const DeclRefExpr *E) {
- if (auto EntityName = getEntityName(E->getDecl()))
- return EntityPointerLevelSet{createEntityPointerLevelFor(*EntityName)};
- return makeEntityNameErr(Ctx, E->getDecl());
+ auto Res = createEntityPointerLevelFor(E->getDecl());
+ if (!Res)
+ return Res.takeError();
+ return EntityPointerLevelSet{*Res};
}
// Translate({., ->}f) -> {(MemberDecl, 1)}
Expected<EntityPointerLevelSet> VisitMemberExpr(const MemberExpr *E) {
- if (auto EntityName = getEntityName(E->getMemberDecl()))
- return EntityPointerLevelSet{createEntityPointerLevelFor(*EntityName)};
- return makeEntityNameErr(Ctx, E->getMemberDecl());
+ auto Res = createEntityPointerLevelFor(E->getMemberDecl());
+ if (!Res)
+ return Res.takeError();
+ return EntityPointerLevelSet{*Res};
}
Expected<EntityPointerLevelSet>
@@ -229,19 +242,18 @@ class EntityPointerLevelTranslator
};
} // namespace clang::ssaf
-Expected<EntityPointerLevelSet> clang::ssaf::translateEntityPointerLevel(
- const Expr *E, ASTContext &Ctx,
- llvm::function_ref<EntityId(EntityName EN)> AddEntity) {
- EntityPointerLevelTranslator Translator(AddEntity, Ctx);
+Expected<EntityPointerLevelSet>
+clang::ssaf::translateEntityPointerLevel(const Expr *E, ASTContext &Ctx,
+ TUSummaryBuilder &Builder) {
+ EntityPointerLevelTranslator Translator(Builder, Ctx);
return Translator.translate(E);
}
/// Create an EntityPointerLevel from a ValueDecl of a pointer type.
Expected<EntityPointerLevel> clang::ssaf::createEntityPointerLevel(
- const NamedDecl *ND, llvm::function_ref<EntityId(EntityName EN)> AddEntity,
- bool IsFunRet) {
- EntityPointerLevelTranslator Translator(AddEntity, ND->getASTContext());
+ const NamedDecl *ND, TUSummaryBuilder &Builder, bool IsFunRet) {
+ EntityPointerLevelTranslator Translator(Builder, ND->getASTContext());
return Translator.translate(ND, IsFunRet);
}
diff --git a/clang/lib/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageExtractor.cpp b/clang/lib/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageExtractor.cpp
index 550416c353fb7..dda2fb6131b8f 100644
--- a/clang/lib/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageExtractor.cpp
+++ b/clang/lib/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageExtractor.cpp
@@ -13,8 +13,6 @@
#include "clang/Analysis/Analyses/UnsafeBufferUsage.h"
#include "clang/ScalableStaticAnalysisFramework/Analyses/EntityPointerLevel/EntityPointerLevel.h"
#include "clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.h"
-#include "clang/ScalableStaticAnalysisFramework/Core/ASTEntityMapping.h"
-#include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityName.h"
#include "clang/ScalableStaticAnalysisFramework/Core/TUSummary/ExtractorRegistry.h"
#include "clang/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummaryBuilder.h"
#include "clang/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummaryExtractor.h"
@@ -51,9 +49,7 @@ clang::ssaf::UnsafeBufferUsageTUSummaryExtractor::extractEntitySummary(
for (const Expr *Ptr : UnsafePointers) {
Expected<EntityPointerLevelSet> Translation =
- translateEntityPointerLevel(Ptr, Ctx, [this](const EntityName &EN) {
- return SummaryBuilder.addEntity(EN);
- });
+ translateEntityPointerLevel(Ptr, Ctx, SummaryBuilder);
if (Translation) {
// Filter out those temporary invalid EntityPointerLevels associated
@@ -86,14 +82,13 @@ void clang::ssaf::UnsafeBufferUsageTUSummaryExtractor::HandleTranslationUnit(
if ((*EntitySummary)->empty())
continue;
- auto ContributorName = getEntityName(CD);
+ auto ContributorId = SummaryBuilder.addEntity(CD);
- if (!ContributorName)
+ if (!ContributorId)
llvm::reportFatalInternalError(makeEntityNameErr(Ctx, CD));
[[maybe_unused]] auto [Ignored, InsertionSucceeded] =
- SummaryBuilder.addSummary(SummaryBuilder.addEntity(*ContributorName),
- std::move(*EntitySummary));
+ SummaryBuilder.addSummary(*ContributorId, std::move(*EntitySummary));
assert(InsertionSucceeded && "duplicated contributor extraction");
}
diff --git a/clang/lib/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummaryBuilder.cpp b/clang/lib/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummaryBuilder.cpp
index f3280b02ce5ef..00c1f72cc9996 100644
--- a/clang/lib/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummaryBuilder.cpp
+++ b/clang/lib/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummaryBuilder.cpp
@@ -1,15 +1,62 @@
#include "clang/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummaryBuilder.h"
+#include "clang/AST/Decl.h"
+#include "clang/ScalableStaticAnalysisFramework/Core/ASTEntityMapping.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>
+#include <optional>
#include <utility>
using namespace clang;
using namespace ssaf;
-EntityId TUSummaryBuilder::addEntity(const EntityName &E) {
- return Summary.IdTable.getId(E);
+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");
+}
+
+EntityId TUSummaryBuilder::addEntityImpl(const EntityName &Name,
+ const Decl *D) {
+ EntityId Id = Summary.IdTable.getId(Name);
+ Summary.LinkageTable.try_emplace(Id, getLinkageForDecl(D));
+ return Id;
+}
+
+std::optional<EntityId> TUSummaryBuilder::addEntity(const NamedDecl *D) {
+ auto Name = getEntityName(D);
+ if (!Name)
+ return std::nullopt;
+ return addEntityImpl(*Name, D);
+}
+
+std::optional<EntityId>
+TUSummaryBuilder::addEntityForReturn(const FunctionDecl *FD) {
+ auto Name = getEntityNameForReturn(FD);
+ if (!Name)
+ return std::nullopt;
+ return addEntityImpl(*Name, FD);
}
std::pair<EntitySummary *, bool>
diff --git a/clang/unittests/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.cpp b/clang/unittests/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.cpp
index 4a631a28897d0..2490d43992bfa 100644
--- a/clang/unittests/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.cpp
+++ b/clang/unittests/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.cpp
@@ -7,13 +7,12 @@
//===----------------------------------------------------------------------===//
#include "clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsage.h"
+#include "FindDecl.h"
#include "TestFixture.h"
#include "clang/AST/ASTConsumer.h"
-#include "clang/AST/DynamicRecursiveASTVisitor.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/ScalableStaticAnalysisFramework/Analyses/EntityPointerLevel/EntityPointerLevel.h"
#include "clang/ScalableStaticAnalysisFramework/Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.h"
-#include "clang/ScalableStaticAnalysisFramework/Core/ASTEntityMapping.h"
#include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityId.h"
#include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityIdTable.h"
#include "clang/ScalableStaticAnalysisFramework/Core/Model/EntityName.h"
@@ -36,36 +35,6 @@ using namespace ssaf;
using testing::UnorderedElementsAre;
namespace {
-template <typename SomeDecl = NamedDecl>
-const SomeDecl *findDeclByName(StringRef Name, ASTContext &Ctx) {
- class NamedDeclFinder : public DynamicRecursiveASTVisitor {
- public:
- StringRef SearchingName;
- const NamedDecl *FoundDecl = nullptr;
-
- NamedDeclFinder(StringRef SearchingName) : SearchingName(SearchingName) {}
-
- bool VisitDecl(Decl *D) override {
- if (const auto *ND = dyn_cast<SomeDecl>(D)) {
- if (ND->getNameAsString() == SearchingName) {
- FoundDecl = ND;
- return false;
- }
- }
- return true;
- }
- };
-
- NamedDeclFinder Finder(Name);
-
- Finder.TraverseDecl(Ctx.getTranslationUnitDecl());
- return dyn_cast_or_null<SomeDecl>(Finder.FoundDecl);
-}
-
-const FunctionDecl *findFnByName(StringRef Name, ASTContext &Ctx) {
- return findDeclByName<FunctionDecl>(Name, Ctx);
-}
-
class UnsafeBufferUsageTest : public TestFixture {
protected:
TUSummary TUSum;
@@ -104,15 +73,14 @@ class UnsafeBufferUsageTest : public TestFixture {
return nullptr;
}
- std::optional<EntityName> EN = getEntityName(ContributorDefn);
-
- if (!EN) {
+ std::optional<EntityId> ContributorEntityId =
+ Builder.addEntity(ContributorDefn);
+ if (!ContributorEntityId) {
ADD_FAILURE() << "failed to get EntityName for contributor \""
<< ContributorEntityName << "\"";
return nullptr;
}
- EntityId ContributorEntityId = Builder.addEntity(*EN);
auto &TUSumData = getData(TUSum);
auto EntitiesSumIter =
TUSumData.find(UnsafeBufferUsageEntitySummary::summaryName());
@@ -122,7 +90,7 @@ class UnsafeBufferUsageTest : public TestFixture {
if (EntitiesSumIter == TUSumData.end())
return nullptr;
- auto EntitySumIter = EntitiesSumIter->second.find(ContributorEntityId);
+ auto EntitySumIter = EntitiesSumIter->second.find(*ContributorEntityId);
// If entity summary is empty, it may not exist:
if (EntitySumIter == EntitiesSumIter->second.end())
@@ -133,15 +101,13 @@ class UnsafeBufferUsageTest : public TestFixture {
std::optional<EntityId> getEntityId(StringRef Name) {
if (const auto *D = findDeclByName(Name, AST->getASTContext()))
- if (auto EntityName = getEntityName(D))
- return Builder.addEntity(*EntityName);
+ return Builder.addEntity(D);
return std::nullopt;
}
std::optional<EntityId> getEntityIdForReturn(StringRef FunName) {
if (const auto *D = findFnByName(FunName, AST->getASTContext()))
- if (auto EntityName = getEntityNameForReturn(D))
- return Builder.addEntity(*EntityName);
+ return Builder.addEntityForReturn(D);
return std::nullopt;
}
@@ -181,8 +147,9 @@ getSubsetOf(const EntityPointerLevelSet &Set, EntityId Entity) {
}
TEST_F(UnsafeBufferUsageTest, EntityPointerLevelComparison) {
- EntityId E1 = Builder.addEntity({"c:@F at foo", "", {}});
- EntityId E2 = Builder.addEntity({"c:@F at bar", "", {}});
+ EntityIdTable Table;
+ EntityId E1 = Table.getId({"c:@F at foo", "", {}});
+ EntityId E2 = Table.getId({"c:@F at bar", "", {}});
auto P1 = buildEntityPointerLevel(E1, 2);
auto P2 = buildEntityPointerLevel(E1, 2);
@@ -200,9 +167,10 @@ TEST_F(UnsafeBufferUsageTest, EntityPointerLevelComparison) {
}
TEST_F(UnsafeBufferUsageTest, UnsafeBufferUsageEntityPointerLevelSetTest) {
- EntityId E1 = Builder.addEntity({"c:@F at foo", "", {}});
- EntityId E2 = Builder.addEntity({"c:@F at bar", "", {}});
- EntityId E3 = Builder.addEntity({"c:@F at baz", "", {}});
+ EntityIdTable Table;
+ EntityId E1 = Table.getId({"c:@F at foo", "", {}});
+ EntityId E2 = Table.getId({"c:@F at bar", "", {}});
+ EntityId E3 = Table.getId({"c:@F at baz", "", {}});
auto P1 = buildEntityPointerLevel(E1, 1);
auto P2 = buildEntityPointerLevel(E1, 2);
diff --git a/clang/unittests/ScalableStaticAnalysisFramework/TUSummaryBuilderTest.cpp b/clang/unittests/ScalableStaticAnalysisFramework/TUSummaryBuilderTest.cpp
index ece39e2164df7..0eae3a3a0fe32 100644
--- a/clang/unittests/ScalableStaticAnalysisFramework/TUSummaryBuilderTest.cpp
+++ b/clang/unittests/ScalableStaticAnalysisFramework/TUSummaryBuilderTest.cpp
@@ -7,14 +7,16 @@
//===----------------------------------------------------------------------===//
#include "clang/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummaryBuilder.h"
+#include "FindDecl.h"
#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"
#include "clang/ScalableStaticAnalysisFramework/Core/TUSummary/EntitySummary.h"
#include "clang/ScalableStaticAnalysisFramework/Core/TUSummary/TUSummary.h"
+#include "clang/Tooling/Tooling.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
@@ -32,11 +34,6 @@ using testing::Field;
using testing::Optional;
using testing::UnorderedElementsAre;
-[[nodiscard]]
-static EntityId addTestEntity(TUSummaryBuilder &Builder, llvm::StringRef USR) {
- return Builder.addEntity(EntityName(USR, /*Suffix=*/"", /*Namespace=*/{}));
-}
-
struct SummaryResult {
EntitySummary *Summary;
bool Inserted;
@@ -95,6 +92,11 @@ struct TUSummaryBuilderTest : ssaf::TestFixture {
BuildNamespace(BuildNamespaceKind::CompilationUnit, "Mock.cpp")};
TUSummaryBuilder Builder = TUSummaryBuilder(this->Summary);
+ [[nodiscard]] EntityId addTestEntity(llvm::StringRef USR) {
+ return getIdTable(Summary).getId(
+ EntityName(USR, /*Suffix=*/"", /*Namespace=*/{}));
+ }
+
[[nodiscard]] static SmallVector<SummaryName>
summaryNames(const TUSummary &Summary) {
return llvm::to_vector(llvm::make_first_range(getData(Summary)));
@@ -128,22 +130,23 @@ TEST_F(TUSummaryBuilderTest, AddEntity) {
EntityName EN1("c:@F at foo", "", /*Namespace=*/{});
EntityName EN2("c:@F at bar", "", /*Namespace=*/{});
- EntityId ID = Builder.addEntity(EN1);
- EntityId IDAlias = Builder.addEntity(EN1);
+ EntityIdTable &IdTable = getIdTable(Summary);
+
+ EntityId ID = IdTable.getId(EN1);
+ EntityId IDAlias = IdTable.getId(EN1);
EXPECT_EQ(ID, IDAlias); // Idenpotency
- EntityId ID2 = Builder.addEntity(EN2);
+ EntityId ID2 = IdTable.getId(EN2);
EXPECT_NE(ID, ID2);
EXPECT_NE(IDAlias, ID2);
- const EntityIdTable &IdTable = getIdTable(Summary);
EXPECT_EQ(IdTable.count(), 2U);
EXPECT_TRUE(IdTable.contains(EN1));
EXPECT_TRUE(IdTable.contains(EN2));
}
TEST_F(TUSummaryBuilderTest, TUSummaryBuilderAddSingleSummary) {
- EntityId ID = addTestEntity(Builder, "c:@F at foo");
+ EntityId ID = addTestEntity("c:@F at foo");
auto [Name, Res] = addSummaryTo(Builder, ID, MockSummaryData1(10));
ASSERT_TRUE(Res.Inserted);
ASSERT_TRUE(Res.Summary);
@@ -157,7 +160,7 @@ TEST_F(TUSummaryBuilderTest, TUSummaryBuilderAddSingleSummary) {
}
TEST_F(TUSummaryBuilderTest, AddMultipleSummariesToSameEntity) {
- EntityId ID = addTestEntity(Builder, "c:@F at foo");
+ EntityId ID = addTestEntity("c:@F at foo");
// Add different summary types to the same entity.
auto [Name1, Res1] = addSummaryTo(Builder, ID, MockSummaryData1(42));
@@ -188,9 +191,9 @@ TEST_F(TUSummaryBuilderTest, AddMultipleSummariesToSameEntity) {
}
TEST_F(TUSummaryBuilderTest, AddSameSummaryTypeToMultipleEntities) {
- EntityId ID1 = addTestEntity(Builder, "c:@F at foo");
- EntityId ID2 = addTestEntity(Builder, "c:@F at bar");
- EntityId ID3 = addTestEntity(Builder, "c:@F at baz");
+ EntityId ID1 = addTestEntity("c:@F at foo");
+ EntityId ID2 = addTestEntity("c:@F at bar");
+ EntityId ID3 = addTestEntity("c:@F at baz");
// Add the same summary type to different entities.
auto [Name1, Res1] = addSummaryTo(Builder, ID1, MockSummaryData1(1));
@@ -220,7 +223,7 @@ TEST_F(TUSummaryBuilderTest, AddSameSummaryTypeToMultipleEntities) {
}
TEST_F(TUSummaryBuilderTest, AddConflictingSummaryToSameEntity) {
- EntityId ID = addTestEntity(Builder, "c:@F at foo");
+ EntityId ID = addTestEntity("c:@F at foo");
auto [Name, Res] = addSummaryTo(Builder, ID, MockSummaryData1(10));
ASSERT_TRUE(Res.Inserted);
@@ -266,4 +269,49 @@ TEST_F(TUSummaryBuilderTest, AddConflictingSummaryToSameEntity) {
Optional(Field(&MockSummaryData1::Value, 30)));
}
+struct TUSummaryBuilderLinkageTest : TUSummaryBuilderTest {
+ std::unique_ptr<ASTUnit> AST;
+
+ const FunctionDecl *findFnByName(StringRef Name) {
+ return ssaf::findFnByName(Name, AST->getASTContext());
+ }
+
+ std::optional<EntityLinkageType> getLinkageFor(std::optional<EntityId> ID) {
+ if (!ID)
+ return std::nullopt;
+ if (auto It = getLinkageTable(Summary).find(*ID);
+ It != getLinkageTable(Summary).end())
+ return It->second.getLinkage();
+ return std::nullopt;
+ }
+};
+
+TEST_F(TUSummaryBuilderLinkageTest, HasInternalLinkage) {
+ AST = tooling::buildASTFromCode("static void target() {}");
+ const FunctionDecl *Fn = findFnByName("target");
+ ASSERT_TRUE(Fn);
+ EXPECT_EQ(getLinkageFor(Builder.addEntity(Fn)), EntityLinkageType::Internal);
+}
+
+TEST_F(TUSummaryBuilderLinkageTest, HasExternalLinkage) {
+ AST = tooling::buildASTFromCode("void target() {}");
+ const FunctionDecl *Fn = findFnByName("target");
+ ASSERT_TRUE(Fn);
+ EXPECT_EQ(getLinkageFor(Builder.addEntity(Fn)), EntityLinkageType::External);
+}
+
+TEST_F(TUSummaryBuilderLinkageTest, HasExternalLinkageWithInline) {
+ AST = tooling::buildASTFromCode("inline void target() {}");
+ const FunctionDecl *Fn = findFnByName("target");
+ ASSERT_TRUE(Fn);
+ EXPECT_EQ(getLinkageFor(Builder.addEntity(Fn)), EntityLinkageType::External);
+}
+
+TEST_F(TUSummaryBuilderLinkageTest, HasInternalLinkageWithStaticInline) {
+ AST = tooling::buildASTFromCode("static inline void target() {}");
+ const FunctionDecl *Fn = findFnByName("target");
+ ASSERT_TRUE(Fn);
+ EXPECT_EQ(getLinkageFor(Builder.addEntity(Fn)), EntityLinkageType::Internal);
+}
+
} // namespace
More information about the cfe-commits
mailing list