https://github.com/ziqingluo-90 updated https://github.com/llvm/llvm-project/pull/206600
>From f6a06234bc653a58a648821989592e6255944c72 Mon Sep 17 00:00:00 2001 From: Ziqing Luo <[email protected]> Date: Mon, 29 Jun 2026 15:00:54 -0700 Subject: [PATCH 1/2] [SSAF][Extractor][Do not merge] Extract operator new/delete overload entities that shall retain their types 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 --- .../OperatorNewDeletePointers.h | 56 ++++ .../BuiltinAnchorSources.def | 1 + .../Analyses/CMakeLists.txt | 1 + .../OperatorNewDeletePointersExtractor.cpp | 119 ++++++++ .../Analyses/SSAFAnalysesCommon.h | 14 +- ...OperatorNewDeletePointersExtractorTest.cpp | 260 ++++++++++++++++++ .../ScalableStaticAnalysis/CMakeLists.txt | 1 + 7 files changed, 447 insertions(+), 5 deletions(-) create mode 100644 clang/include/clang/ScalableStaticAnalysis/Analyses/OperatorNewDelete/OperatorNewDeletePointers.h create mode 100644 clang/lib/ScalableStaticAnalysis/Analyses/OperatorNewDelete/OperatorNewDeletePointersExtractor.cpp create mode 100644 clang/unittests/ScalableStaticAnalysis/Analyses/OperatorNewDelete/OperatorNewDeletePointersExtractorTest.cpp 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..8c030e2a582ba --- /dev/null +++ b/clang/include/clang/ScalableStaticAnalysis/Analyses/OperatorNewDelete/OperatorNewDeletePointers.h @@ -0,0 +1,56 @@ +//===- 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 { + +/// OperatorNewDeletePointersEntitySummary collects the following entities in a +/// contributor: +/// - return entities of operator new overloads; +/// - the parameter (optionally the 2nd) of operator new overloads +/// representing the pointer to a memory area to initialize the object at; +/// - the first parameter of operator delete overloads representing the pointer +/// to a memory block to deallocate or a null pointer; +/// - the parameter (optionally the 2nd) 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(); } + + std::set<EntityId> Entities; + + bool operator==(const OperatorNewDeletePointersEntitySummary &Other) const { + return Entities == Other.Entities; + } + + bool operator==(const std::set<EntityId> &OtherEntities) const { + return Entities == OtherEntities; + } + + bool empty() const { return Entities.empty(); } +}; + +} // 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..8b08805418a8e --- /dev/null +++ b/clang/lib/ScalableStaticAnalysis/Analyses/OperatorNewDelete/OperatorNewDeletePointersExtractor.cpp @@ -0,0 +1,119 @@ +//===- 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>(); + + for (const NamedDecl *Decl : ContributorDecls) { + 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); + } + }; + 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..90780a1d0cbc7 100644 --- a/clang/lib/ScalableStaticAnalysis/Analyses/SSAFAnalysesCommon.h +++ b/clang/lib/ScalableStaticAnalysis/Analyses/SSAFAnalysesCommon.h @@ -109,10 +109,14 @@ void extractAndAddSummaries(TUSummaryExtractor &Extractor, Contributors; findContributors(Ctx, Contributors); for (const auto &[Cano, Decls] : Contributors) { + assert(Decls.size() > 0 && !Decls[0]->isImplicit() && + "guaranteed by 'findContributors'"); + const NamedDecl *Rep = Cano->isImplicit() ? Decls[0] : Cano; + // 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 (Rep->isTemplated()) continue; auto Summary = ExtractFn(Decls); @@ -120,13 +124,13 @@ void extractAndAddSummaries(TUSummaryExtractor &Extractor, if (Summary->empty()) continue; - if (auto Id = Extractor.addEntity(Cano)) { + if (auto Id = Extractor.addEntity(Rep)) { 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, Rep, "dropping duplicate %s summary for entity %s", + ExtractorName, Rep->getNameAsString().c_str())); } else - logWarningFromError(makeEntityNameErr(Ctx, Cano)); + logWarningFromError(makeEntityNameErr(Ctx, Rep)); } } diff --git a/clang/unittests/ScalableStaticAnalysis/Analyses/OperatorNewDelete/OperatorNewDeletePointersExtractorTest.cpp b/clang/unittests/ScalableStaticAnalysis/Analyses/OperatorNewDelete/OperatorNewDeletePointersExtractorTest.cpp new file mode 100644 index 0000000000000..5e1b3d9c720d0 --- /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 387f03dc76fc6..528840804bdd9 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 >From 0b7062ec57739f7e8b7442df10c91e7382e9dead Mon Sep 17 00:00:00 2001 From: Ziqing Luo <[email protected]> Date: Mon, 29 Jun 2026 17:49:33 -0700 Subject: [PATCH 2/2] fix build issue --- .../lib/ScalableStaticAnalysis/Analyses/SSAFAnalysesCommon.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/lib/ScalableStaticAnalysis/Analyses/SSAFAnalysesCommon.h b/clang/lib/ScalableStaticAnalysis/Analyses/SSAFAnalysesCommon.h index 90780a1d0cbc7..ef28503d49d65 100644 --- a/clang/lib/ScalableStaticAnalysis/Analyses/SSAFAnalysesCommon.h +++ b/clang/lib/ScalableStaticAnalysis/Analyses/SSAFAnalysesCommon.h @@ -104,7 +104,7 @@ 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); @@ -128,7 +128,7 @@ void extractAndAddSummaries(TUSummaryExtractor &Extractor, if (!Builder.addSummary(*Id, std::move(Summary)).second) logWarningFromError(makeErrAtNode( Ctx, Rep, "dropping duplicate %s summary for entity %s", - ExtractorName, Rep->getNameAsString().c_str())); + ExtractorName.data(), Rep->getNameAsString().c_str())); } else logWarningFromError(makeEntityNameErr(Ctx, Rep)); } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
