Fix quadratic slowdown in AST matcher parent map generation (#87824)
Avoids the need to linearly re-scan all seen parent nodes to check for duplicates, which previously caused a slowdown for ancestry checks in Clang AST matchers. Fixes: #86881
This commit is contained in:
parent
04bf1a4090
commit
c54afe5c33
@ -646,6 +646,9 @@ Fixed Point Support in Clang
|
|||||||
AST Matchers
|
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++"``.
|
- ``isInStdNamespace`` now supports Decl declared with ``extern "C++"``.
|
||||||
- Add ``isExplicitObjectMemberFunction``.
|
- Add ``isExplicitObjectMemberFunction``.
|
||||||
- Fixed ``forEachArgumentWithParam`` and ``forEachArgumentWithParamType`` to
|
- Fixed ``forEachArgumentWithParam`` and ``forEachArgumentWithParamType`` to
|
||||||
|
@ -61,7 +61,26 @@ class ParentMapContext::ParentMap {
|
|||||||
template <typename, typename...> friend struct ::MatchParents;
|
template <typename, typename...> friend struct ::MatchParents;
|
||||||
|
|
||||||
/// Contains parents of a node.
|
/// Contains parents of a node.
|
||||||
using ParentVector = llvm::SmallVector<DynTypedNode, 2>;
|
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<DynTypedNode> view() const { return Items; }
|
||||||
|
private:
|
||||||
|
llvm::SmallVector<DynTypedNode, 2> Items;
|
||||||
|
llvm::SmallDenseSet<DynTypedNode, 2> Seen;
|
||||||
|
};
|
||||||
|
|
||||||
/// Maps from a node to its parents. This is used for nodes that have
|
/// 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
|
/// pointer identity only, which are more common and we can save space by
|
||||||
@ -99,7 +118,7 @@ class ParentMapContext::ParentMap {
|
|||||||
return llvm::ArrayRef<DynTypedNode>();
|
return llvm::ArrayRef<DynTypedNode>();
|
||||||
}
|
}
|
||||||
if (const auto *V = I->second.template dyn_cast<ParentVector *>()) {
|
if (const auto *V = I->second.template dyn_cast<ParentVector *>()) {
|
||||||
return llvm::ArrayRef(*V);
|
return V->view();
|
||||||
}
|
}
|
||||||
return getSingleDynTypedNodeFromParentMap(I->second);
|
return getSingleDynTypedNodeFromParentMap(I->second);
|
||||||
}
|
}
|
||||||
@ -252,7 +271,7 @@ public:
|
|||||||
const auto *S = It->second.dyn_cast<const Stmt *>();
|
const auto *S = It->second.dyn_cast<const Stmt *>();
|
||||||
if (!S) {
|
if (!S) {
|
||||||
if (auto *Vec = It->second.dyn_cast<ParentVector *>())
|
if (auto *Vec = It->second.dyn_cast<ParentVector *>())
|
||||||
return llvm::ArrayRef(*Vec);
|
return Vec->view();
|
||||||
return getSingleDynTypedNodeFromParentMap(It->second);
|
return getSingleDynTypedNodeFromParentMap(It->second);
|
||||||
}
|
}
|
||||||
const auto *P = dyn_cast<Expr>(S);
|
const auto *P = dyn_cast<Expr>(S);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user