diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index f5359afe1f099..c4a4893aec5cd 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -646,6 +646,9 @@ Fixed Point Support in Clang AST Matchers ------------ +- Fixes a long-standing performance issue in parent map generation for + ancestry-based matchers such as ``hasParent`` and ``hasAncestor``, making + them significantly faster. - ``isInStdNamespace`` now supports Decl declared with ``extern "C++"``. - Add ``isExplicitObjectMemberFunction``. - Fixed ``forEachArgumentWithParam`` and ``forEachArgumentWithParamType`` to diff --git a/clang/lib/AST/ParentMapContext.cpp b/clang/lib/AST/ParentMapContext.cpp index 21cfd5b1de6e9..9723c0cfa83bb 100644 --- a/clang/lib/AST/ParentMapContext.cpp +++ b/clang/lib/AST/ParentMapContext.cpp @@ -61,7 +61,26 @@ class ParentMapContext::ParentMap { template friend struct ::MatchParents; /// Contains parents of a node. - using ParentVector = llvm::SmallVector; + class ParentVector { + public: + ParentVector() = default; + explicit ParentVector(size_t N, const DynTypedNode &Value) { + Items.reserve(N); + for (; N > 0; --N) + push_back(Value); + } + bool contains(const DynTypedNode &Value) { + return Seen.contains(Value); + } + void push_back(const DynTypedNode &Value) { + if (!Value.getMemoizationData() || Seen.insert(Value).second) + Items.push_back(Value); + } + llvm::ArrayRef view() const { return Items; } + private: + llvm::SmallVector Items; + llvm::SmallDenseSet Seen; + }; /// Maps from a node to its parents. This is used for nodes that have /// pointer identity only, which are more common and we can save space by @@ -99,7 +118,7 @@ class ParentMapContext::ParentMap { return llvm::ArrayRef(); } if (const auto *V = I->second.template dyn_cast()) { - return llvm::ArrayRef(*V); + return V->view(); } return getSingleDynTypedNodeFromParentMap(I->second); } @@ -252,7 +271,7 @@ class ParentMapContext::ParentMap { const auto *S = It->second.dyn_cast(); if (!S) { if (auto *Vec = It->second.dyn_cast()) - return llvm::ArrayRef(*Vec); + return Vec->view(); return getSingleDynTypedNodeFromParentMap(It->second); } const auto *P = dyn_cast(S);