================
@@ -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; }
----------------
steakhal wrote:
I think what I don't understand here is that right now I think the operator
delete has 3 redecls in this order:
1) the implicit decl inserted by the compiler at the beginning of the TU -
since this is the first of the redecl chain, it is also known as the canonical
decl.
2) the fwd declaration, spelled as `void operator delete[](void *p) noexcept;`
3) the definition, spelled as `void operator delete[](void *p) noexcept {
(void)p; }`
And I'm challenging, maybe we only need just two redecls for the test.
If a test contains code that doesn't contribute to the test outcome, then that
is effectively dead code, and should be removed to avoid confusing the reader.
https://github.com/llvm/llvm-project/pull/206600
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits