[clang] 6560fef - [SSAF][Extractor] Extract operator new/delete overload entities that shall retain their types (#206600)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Jul 8 11:50:11 PDT 2026
Author: Ziqing Luo
Date: 2026-07-08T11:50:06-07:00
New Revision: 6560fef7724bbd9baa57d3f09d077c4d2e69c868
URL: https://github.com/llvm/llvm-project/commit/6560fef7724bbd9baa57d3f09d077c4d2e69c868
DIFF: https://github.com/llvm/llvm-project/commit/6560fef7724bbd9baa57d3f09d077c4d2e69c868.diff
LOG: [SSAF][Extractor] Extract operator new/delete overload entities that shall retain their types (#206600)
This commit creates an extractor for operator new/delete overloads.
Overloads of operator new shall retain their void* return type,
regardless of whether they are propagated by unsafe buffers. The same
applies to the parameters of operator delete overloads.
Therefore, clang-reforge eventually need this information.
rdar://179151541
---------
Co-authored-by: Balázs Benics <benicsbalazs at gmail.com>
Added:
clang/include/clang/ScalableStaticAnalysis/Analyses/OperatorNewDelete/OperatorNewDeletePointers.h
clang/lib/ScalableStaticAnalysis/Analyses/OperatorNewDelete/OperatorNewDeletePointersExtractor.cpp
clang/unittests/ScalableStaticAnalysis/Analyses/OperatorNewDelete/OperatorNewDeletePointersExtractorTest.cpp
Modified:
clang/include/clang/ScalableStaticAnalysis/BuiltinAnchorSources.def
clang/lib/ScalableStaticAnalysis/Analyses/CMakeLists.txt
clang/lib/ScalableStaticAnalysis/Analyses/SSAFAnalysesCommon.h
clang/unittests/ScalableStaticAnalysis/CMakeLists.txt
Removed:
################################################################################
diff --git a/clang/include/clang/ScalableStaticAnalysis/Analyses/OperatorNewDelete/OperatorNewDeletePointers.h b/clang/include/clang/ScalableStaticAnalysis/Analyses/OperatorNewDelete/OperatorNewDeletePointers.h
new file mode 100644
index 0000000000000..0e55cecf15e54
--- /dev/null
+++ b/clang/include/clang/ScalableStaticAnalysis/Analyses/OperatorNewDelete/OperatorNewDeletePointers.h
@@ -0,0 +1,62 @@
+//===- OperatorNewDeletePointers.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
+//
+//===----------------------------------------------------------------------===//
+//
+// Declares data structures for analysis that identifies pointer entities in
+// operator new/delete overloads that must have a 'void*' type
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SCALABLESTATICANALYSIS_ANALYSES_OPERATORNEWDELETE_OPERATORNEWDELETEPOINTERS_H
+#define LLVM_CLANG_SCALABLESTATICANALYSIS_ANALYSES_OPERATORNEWDELETE_OPERATORNEWDELETEPOINTERS_H
+
+#include "clang/ScalableStaticAnalysis/Core/Model/EntityId.h"
+#include "clang/ScalableStaticAnalysis/Core/Model/SummaryName.h"
+#include "clang/ScalableStaticAnalysis/Core/TUSummary/EntitySummary.h"
+#include "llvm/ADT/StringRef.h"
+#include <set>
+
+namespace clang::ssaf {
+
+/// \brief Collects specific pointer entities related to operator new and delete
+/// overloads within a contributor.
+///
+/// OperatorNewDeletePointersEntitySummary collects the following entities:
+/// -# The returned entities of `operator new` overloads.
+/// -# The parameter (optionally the second) of `operator new` overloads
+/// representing the pointer to a memory area at which to initialize the
+/// object.
+/// -# The first parameter of `operator delete` overloads representing the
+/// pointer
+/// to a memory block to deallocate (or a null pointer).
+/// -# The parameter (optionally the second) of `operator delete` overloads
+/// representing the pointer used as the placement parameter in the matching
+/// placement `new`.
+struct OperatorNewDeletePointersEntitySummary final : public EntitySummary {
+ static constexpr llvm::StringLiteral Name = "OperatorNewDeletePointers";
+
+ static SummaryName summaryName() { return SummaryName(Name.str()); }
+
+ SummaryName getSummaryName() const override { return summaryName(); }
+
+ bool friend operator==(const OperatorNewDeletePointersEntitySummary &This,
+ const OperatorNewDeletePointersEntitySummary &Other) {
+ return This.Entities == Other.Entities;
+ }
+
+ bool operator==(const std::set<EntityId> &OtherEntities) const {
+ return Entities == OtherEntities;
+ }
+
+ bool empty() const { return Entities.empty(); }
+
+ std::set<EntityId> Entities;
+};
+
+} // namespace clang::ssaf
+
+#endif // LLVM_CLANG_SCALABLESTATICANALYSIS_ANALYSES_OPERATORNEWDELETE_OPERATORNEWDELETEPOINTERS_H
diff --git a/clang/include/clang/ScalableStaticAnalysis/BuiltinAnchorSources.def b/clang/include/clang/ScalableStaticAnalysis/BuiltinAnchorSources.def
index ba4944ea984cb..57b70f37cf61d 100644
--- a/clang/include/clang/ScalableStaticAnalysis/BuiltinAnchorSources.def
+++ b/clang/include/clang/ScalableStaticAnalysis/BuiltinAnchorSources.def
@@ -20,6 +20,7 @@ ANCHOR(AnalysisRegistryAnchorSource)
ANCHOR(CallGraphExtractorAnchorSource)
ANCHOR(CallGraphJSONFormatAnchorSource)
ANCHOR(JSONFormatAnchorSource)
+ANCHOR(OperatorNewDeletePointersExtractorAnchorSource)
ANCHOR(PointerFlowAnalysisAnchorSource)
ANCHOR(PointerFlowExtractorAnchorSource)
ANCHOR(PointerFlowJSONFormatAnchorSource)
diff --git a/clang/lib/ScalableStaticAnalysis/Analyses/CMakeLists.txt b/clang/lib/ScalableStaticAnalysis/Analyses/CMakeLists.txt
index dc72eb6d645d5..e1d14d13c2156 100644
--- a/clang/lib/ScalableStaticAnalysis/Analyses/CMakeLists.txt
+++ b/clang/lib/ScalableStaticAnalysis/Analyses/CMakeLists.txt
@@ -8,6 +8,7 @@ add_clang_library(clangScalableStaticAnalysisAnalyses
CallGraph/CallGraphJSONFormat.cpp
EntityPointerLevel/EntityPointerLevel.cpp
EntityPointerLevel/EntityPointerLevelFormat.cpp
+ OperatorNewDelete/OperatorNewDeletePointersExtractor.cpp
PointerFlow/PointerFlow.cpp
PointerFlow/PointerFlowAnalysis.cpp
PointerFlow/PointerFlowExtractor.cpp
diff --git a/clang/lib/ScalableStaticAnalysis/Analyses/OperatorNewDelete/OperatorNewDeletePointersExtractor.cpp b/clang/lib/ScalableStaticAnalysis/Analyses/OperatorNewDelete/OperatorNewDeletePointersExtractor.cpp
new file mode 100644
index 0000000000000..86e3607b2302f
--- /dev/null
+++ b/clang/lib/ScalableStaticAnalysis/Analyses/OperatorNewDelete/OperatorNewDeletePointersExtractor.cpp
@@ -0,0 +1,118 @@
+//===- OperatorNewDeletePointersExtractor.cpp -----------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Extractor implementation for extracting from user-provided operator
+// new/delete overloadings:
+// 1 return entities of operator new overloads;
+// 2 the parameter (optionally the 2nd) of operator new overloads
+// representing the pointer to a memory area to initialize the object at;
+// 3 the first parameter of operator delete overloads representing the pointer
+// to a memory block to deallocate or a null pointer;
+// 4 the parameter (optionally the 2nd) of operator delete overloads
+// representing the pointer used as the placement parameter in the matching
+// placement new.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../SSAFAnalysesCommon.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/Type.h"
+#include "clang/Basic/OperatorKinds.h"
+#include "clang/ScalableStaticAnalysis/Analyses/OperatorNewDelete/OperatorNewDeletePointers.h"
+#include "clang/ScalableStaticAnalysis/Core/TUSummary/ExtractorRegistry.h"
+#include "clang/ScalableStaticAnalysis/Core/TUSummary/TUSummaryExtractor.h"
+#include "llvm/ADT/StringRef.h"
+#include <memory>
+#include <optional>
+#include <vector>
+
+using namespace clang;
+using namespace ssaf;
+
+namespace {
+
+class OperatorNewDeletePointersExtractor final : public TUSummaryExtractor {
+public:
+ using TUSummaryExtractor::TUSummaryExtractor;
+
+private:
+ void HandleTranslationUnit(ASTContext &Ctx) override;
+
+ std::unique_ptr<OperatorNewDeletePointersEntitySummary>
+ extractEntitySummary(const std::vector<const NamedDecl *> &Decls);
+};
+
+void OperatorNewDeletePointersExtractor::HandleTranslationUnit(
+ ASTContext &Ctx) {
+ extractAndAddSummaries(
+ *this, SummaryBuilder, Ctx,
+ [&](const std::vector<const NamedDecl *> &Decls) {
+ return extractEntitySummary(Decls);
+ },
+ OperatorNewDeletePointersEntitySummary::Name);
+}
+
+std::unique_ptr<OperatorNewDeletePointersEntitySummary>
+OperatorNewDeletePointersExtractor::extractEntitySummary(
+ const std::vector<const NamedDecl *> &ContributorDecls) {
+ auto Summary = std::make_unique<OperatorNewDeletePointersEntitySummary>();
+ auto Matcher = [&Summary, this](const DynTypedNode &Node) {
+ const auto *FD = Node.get<FunctionDecl>();
+
+ if (!FD)
+ return;
+
+ OverloadedOperatorKind OO = FD->getOverloadedOperator();
+
+ switch (OO) {
+ case OO_New:
+ case OO_Array_New:
+ // Extract case 1:
+ if (auto Id = addEntityForReturn(FD))
+ Summary->Entities.insert(*Id);
+ break;
+ case OO_Delete:
+ case OO_Array_Delete:
+ // Extract case 3; ignore ill-formed ones (first param not a pointer).
+ if (!FD->getNumParams() || !hasPtrOrArrType(FD->getParamDecl(0)))
+ return;
+ if (auto Id = addEntity(FD->getParamDecl(0)))
+ Summary->Entities.insert(*Id);
+ break;
+ default:
+ return;
+ };
+ // Extract case 2 & 4: only `operator new(size_t, void*)` and
+ // `operator delete(void*, void*)` are standard-defined with a void* 2nd
+ // param; for user-defined 3+ param overloads the 2nd param type is
+ // unconstrained, so we conservatively skip them.
+ if (FD->getNumParams() == 2 && hasPtrOrArrType(FD->getParamDecl(1))) {
+ if (auto Id = addEntity(FD->getParamDecl(1)))
+ Summary->Entities.insert(*Id);
+ }
+ };
+
+ for (const NamedDecl *Decl : ContributorDecls)
+ findMatchesIn(Decl, Matcher);
+ return Summary;
+}
+
+} // namespace
+
+namespace clang::ssaf {
+// NOLINTNEXTLINE(misc-use-internal-linkage)
+volatile int OperatorNewDeletePointersExtractorAnchorSource = 0;
+} // namespace clang::ssaf
+
+static TUSummaryExtractorRegistry::Add<OperatorNewDeletePointersExtractor>
+ RegisterOperatorNewDeletePointersExtractor(
+ OperatorNewDeletePointersEntitySummary::Name,
+ "Extract pointer entities in operator new/delete overloads that must "
+ "have a 'void*' type");
diff --git a/clang/lib/ScalableStaticAnalysis/Analyses/SSAFAnalysesCommon.h b/clang/lib/ScalableStaticAnalysis/Analyses/SSAFAnalysesCommon.h
index 674ccfcc58313..152168ea73b54 100644
--- a/clang/lib/ScalableStaticAnalysis/Analyses/SSAFAnalysesCommon.h
+++ b/clang/lib/ScalableStaticAnalysis/Analyses/SSAFAnalysesCommon.h
@@ -104,15 +104,20 @@ template <typename ExtractorFnT>
void extractAndAddSummaries(TUSummaryExtractor &Extractor,
TUSummaryBuilder &Builder, ASTContext &Ctx,
ExtractorFnT ExtractFn,
- const char *ExtractorName = "") {
+ llvm::StringRef ExtractorName = "") {
llvm::DenseMap<const NamedDecl *, std::vector<const NamedDecl *>>
Contributors;
findContributors(Ctx, Contributors);
for (const auto &[Cano, Decls] : Contributors) {
+ assert(!Decls.empty() &&
+ "'findContributors' guarantess that 'Decls' are non-empty");
+ assert(!Decls[0]->isImplicit() &&
+ "'findContributors' guarantess that 'Decls' are non-implicit");
+
// Templates are skipped, but their instantiations are handled. The idea
// is that we can conclude facts about a template through all of its
// instantiations.
- if (Cano->isTemplated())
+ if (Decls[0]->isTemplated())
continue;
auto Summary = ExtractFn(Decls);
@@ -120,13 +125,13 @@ void extractAndAddSummaries(TUSummaryExtractor &Extractor,
if (Summary->empty())
continue;
- if (auto Id = Extractor.addEntity(Cano)) {
+ if (auto Id = Extractor.addEntity(Decls[0])) {
if (!Builder.addSummary(*Id, std::move(Summary)).second)
logWarningFromError(makeErrAtNode(
- Ctx, Cano, "dropping duplicate %s summary for entity %s",
- ExtractorName, Cano->getNameAsString().c_str()));
+ Ctx, Decls[0], "dropping duplicate %s summary for entity %s",
+ ExtractorName.str().c_str(), Decls[0]->getNameAsString().c_str()));
} else
- logWarningFromError(makeEntityNameErr(Ctx, Cano));
+ logWarningFromError(makeEntityNameErr(Ctx, Decls[0]));
}
}
diff --git a/clang/unittests/ScalableStaticAnalysis/Analyses/OperatorNewDelete/OperatorNewDeletePointersExtractorTest.cpp b/clang/unittests/ScalableStaticAnalysis/Analyses/OperatorNewDelete/OperatorNewDeletePointersExtractorTest.cpp
new file mode 100644
index 0000000000000..d8b9bef9b65bb
--- /dev/null
+++ b/clang/unittests/ScalableStaticAnalysis/Analyses/OperatorNewDelete/OperatorNewDeletePointersExtractorTest.cpp
@@ -0,0 +1,260 @@
+//===- OperatorNewDeletePointersExtractorTest.cpp -------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "FindDecl.h"
+#include "TestFixture.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Frontend/SSAFOptions.h"
+#include "clang/ScalableStaticAnalysis/Analyses/OperatorNewDelete/OperatorNewDeletePointers.h"
+#include "clang/ScalableStaticAnalysis/Core/Model/EntityId.h"
+#include "clang/ScalableStaticAnalysis/Core/TUSummary/ExtractorRegistry.h"
+#include "clang/ScalableStaticAnalysis/Core/TUSummary/TUSummary.h"
+#include "clang/ScalableStaticAnalysis/Core/TUSummary/TUSummaryBuilder.h"
+#include "clang/ScalableStaticAnalysis/Core/TUSummary/TUSummaryExtractor.h"
+#include "clang/Tooling/Tooling.h"
+#include "gtest/gtest.h"
+#include <memory>
+#include <optional>
+
+using namespace clang;
+using namespace ssaf;
+
+namespace {
+
+/// Look up the \p SummaryT entity summary for the contributor named
+/// \p ContributorName.
+///
+/// \tparam SummaryT The concrete EntitySummary subtype to return.
+/// \tparam ContributorT The NamedDecl subtype to search for (defaults to
+/// FunctionDecl).
+/// \tparam TUSummaryDataT The type of the TUSummary data map, deduced from
+/// the \p TUSummaryData argument.
+///
+/// Returns null without emitting a failure when no summary was recorded for
+/// the entity — that is a valid outcome in tests that assert absence.
+/// Emits ADD_FAILURE and returns null when the decl or its EntityId cannot
+/// be resolved, as those indicate test-infrastructure errors.
+template <typename SummaryT, typename ContributorT = FunctionDecl,
+ typename TUSummaryDataT>
+const SummaryT *getEntitySummary(llvm::StringRef ContributorName,
+ ASTContext &Ctx, TUSummaryExtractor &Extractor,
+ const TUSummaryDataT &TUSummaryData) {
+ const ContributorT *D = findDeclByName<ContributorT>(ContributorName, Ctx);
+
+ if (!D) {
+ ADD_FAILURE() << "failed to find decl '" << ContributorName << "'";
+ return nullptr;
+ }
+
+ std::optional<EntityId> Id = Extractor.addEntity(D);
+
+ if (!Id) {
+ ADD_FAILURE() << "failed to get EntityId for '" << ContributorName << "'";
+ return nullptr;
+ }
+ auto SumIt = TUSummaryData.find(SummaryT::summaryName());
+
+ if (SumIt == TUSummaryData.end())
+ return nullptr;
+
+ auto EntIt = SumIt->second.find(*Id);
+
+ if (EntIt == SumIt->second.end())
+ return nullptr;
+ return static_cast<const SummaryT *>(EntIt->second.get());
+}
+
+class OperatorNewDeletePointersExtractorTest : public ssaf::TestFixture {
+protected:
+ SSAFOptions Opts;
+ TUSummary TUSum;
+ TUSummaryBuilder Builder;
+ std::unique_ptr<TUSummaryExtractor> Extractor;
+ std::unique_ptr<ASTUnit> AST;
+
+ OperatorNewDeletePointersExtractorTest()
+ : TUSum(llvm::Triple("arm64-apple-macosx"),
+ BuildNamespace(BuildNamespaceKind::CompilationUnit, "Mock.cpp")),
+ Builder(TUSum, Opts), Extractor(nullptr) {}
+
+ bool setUpTest(llvm::StringRef Code) {
+ AST = tooling::buildASTFromCodeWithArgs(Code, {"-std=c++20"});
+ if (!AST) {
+ ADD_FAILURE() << "failed to build AST";
+ return false;
+ }
+ for (auto &E : TUSummaryExtractorRegistry::entries()) {
+ if (E.getName() == OperatorNewDeletePointersEntitySummary::Name) {
+ Extractor = E.instantiate(Builder);
+ break;
+ }
+ }
+ if (!Extractor) {
+ ADD_FAILURE() << "failed to find OperatorNewDeletePointersExtractor";
+ return false;
+ }
+ Extractor->HandleTranslationUnit(AST->getASTContext());
+ return true;
+ }
+
+ const OperatorNewDeletePointersEntitySummary *
+ getEntitySummary(llvm::StringRef FnName) {
+ return ::getEntitySummary<OperatorNewDeletePointersEntitySummary>(
+ FnName, AST->getASTContext(), *Extractor, getData(TUSum));
+ }
+
+ std::optional<EntityId> getEntityId(llvm::StringRef Name) {
+ if (const auto *D = findDeclByName(Name, AST->getASTContext()))
+ return Extractor->addEntity(D);
+ return std::nullopt;
+ }
+
+ std::optional<EntityId> getEntityIdForReturn(llvm::StringRef FnName) {
+ if (const FunctionDecl *FD = findFnByName(FnName, AST->getASTContext()))
+ return Extractor->addEntityForReturn(FD);
+ return std::nullopt;
+ }
+};
+
+//===----------------------------------------------------------------------===//
+// Registration sanity
+//===----------------------------------------------------------------------===//
+
+TEST(OperatorNewDeletePointersExtractorRegistration, ExtractorRegistered) {
+ EXPECT_TRUE(isTUSummaryExtractorRegistered(
+ OperatorNewDeletePointersEntitySummary::Name));
+}
+
+//===----------------------------------------------------------------------===//
+// Extractor cases
+//===----------------------------------------------------------------------===//
+
+TEST_F(OperatorNewDeletePointersExtractorTest, FreeOperatorDelete) {
+ ASSERT_TRUE(setUpTest(R"cpp(
+ void operator delete(void *ptr) noexcept;
+ void operator delete(void *ptr) noexcept { (void)ptr; }
+ )cpp"));
+
+ const auto *S = getEntitySummary("operator delete");
+
+ ASSERT_TRUE(S);
+
+ auto PtrId = getEntityId("ptr");
+
+ ASSERT_TRUE(PtrId);
+
+ EXPECT_EQ(*S, std::set{*PtrId});
+}
+
+TEST_F(OperatorNewDeletePointersExtractorTest, MemberOperatorDelete) {
+ ASSERT_TRUE(setUpTest(R"cpp(
+ class T {
+ public:
+ void operator delete(void *p) noexcept { (void)p; }
+ };
+ )cpp"));
+
+ const auto *S = getEntitySummary("operator delete");
+
+ ASSERT_TRUE(S);
+
+ auto PId = getEntityId("p");
+ ASSERT_TRUE(PId);
+
+ EXPECT_EQ(*S, std::set{*PId});
+}
+
+TEST_F(OperatorNewDeletePointersExtractorTest, OperatorDeleteArray) {
+ ASSERT_TRUE(setUpTest(R"cpp(
+ void operator delete[](void *p) noexcept;
+ void operator delete[](void *p) noexcept { (void)p; }
+ )cpp"));
+
+ const auto *S = getEntitySummary("operator delete[]");
+
+ ASSERT_TRUE(S);
+
+ auto PId = getEntityId("p");
+
+ ASSERT_TRUE(PId);
+ EXPECT_EQ(*S, std::set{*PId});
+}
+
+TEST_F(OperatorNewDeletePointersExtractorTest, OperatorNew) {
+ ASSERT_TRUE(setUpTest(R"cpp(
+ typedef unsigned long size_t;
+ void *operator new(size_t size);
+ void *operator new(size_t size) { (void)size; return nullptr; }
+ )cpp"));
+
+ const auto *S = getEntitySummary("operator new");
+
+ ASSERT_TRUE(S);
+
+ auto RetId = getEntityIdForReturn("operator new");
+
+ ASSERT_TRUE(RetId);
+ EXPECT_EQ(*S, std::set{*RetId});
+}
+
+TEST_F(OperatorNewDeletePointersExtractorTest, PlacementNew) {
+ ASSERT_TRUE(setUpTest(R"cpp(
+ typedef unsigned long size_t;
+ void *operator new(size_t size, void *placement) noexcept;
+ void *operator new(size_t size, void *placement) noexcept {
+ (void)size; return placement;
+ }
+ )cpp"));
+
+ const auto *S = getEntitySummary("operator new");
+
+ ASSERT_TRUE(S);
+
+ auto PlacementId = getEntityId("placement");
+ auto RetId = getEntityIdForReturn("operator new");
+
+ ASSERT_TRUE(PlacementId);
+ ASSERT_TRUE(RetId);
+ EXPECT_EQ(*S, (std::set{*PlacementId, *RetId}));
+}
+
+TEST_F(OperatorNewDeletePointersExtractorTest, PlacementDelete) {
+ ASSERT_TRUE(setUpTest(R"cpp(
+ void operator delete(void *ptr, void *placement) noexcept;
+ void operator delete(void *ptr, void *placement) noexcept {
+ (void)ptr; (void)placement;
+ }
+ )cpp"));
+
+ const auto *S = getEntitySummary("operator delete");
+
+ ASSERT_TRUE(S);
+
+ auto PtrId = getEntityId("ptr");
+ auto PlacementId = getEntityId("placement");
+
+ ASSERT_TRUE(PtrId);
+ ASSERT_TRUE(PlacementId);
+ EXPECT_EQ(*S, (std::set{*PtrId, *PlacementId}));
+}
+
+TEST_F(OperatorNewDeletePointersExtractorTest, NoOperatorNewOrDeleteSummary) {
+ ASSERT_TRUE(setUpTest(R"cpp(
+ class T { int x; };
+ )cpp"));
+
+ auto &TUData = getData(TUSum);
+ auto TUSummariesIter =
+ TUData.find(OperatorNewDeletePointersEntitySummary::summaryName());
+
+ ASSERT_EQ(TUSummariesIter, TUData.end());
+}
+
+} // namespace
diff --git a/clang/unittests/ScalableStaticAnalysis/CMakeLists.txt b/clang/unittests/ScalableStaticAnalysis/CMakeLists.txt
index 12ee90f3cbebf..972287132b36d 100644
--- a/clang/unittests/ScalableStaticAnalysis/CMakeLists.txt
+++ b/clang/unittests/ScalableStaticAnalysis/CMakeLists.txt
@@ -2,6 +2,7 @@ add_distinct_clang_unittest(ClangScalableAnalysisTests
Analyses/PointerFlow/PointerFlowTest.cpp
Analyses/PointerFlow/PointerFlowWPATest.cpp
Analyses/CallGraph/CallGraphExtractorTest.cpp
+ Analyses/OperatorNewDelete/OperatorNewDeletePointersExtractorTest.cpp
Analyses/UnsafeBufferUsage/UnsafeBufferUsageTest.cpp
Analyses/UnsafeBufferUsage/UnsafeBufferUsageWPATest.cpp
ASTEntityMappingTest.cpp
More information about the cfe-commits
mailing list