aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/clang/lib/ASTMatchers/ASTMatchFinder.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2021-06-13 19:31:46 +0000
committerDimitry Andric <dim@FreeBSD.org>2021-06-13 19:37:19 +0000
commite8d8bef961a50d4dc22501cde4fb9fb0be1b2532 (patch)
tree94f04805f47bb7c59ae29690d8952b6074fff602 /contrib/llvm-project/clang/lib/ASTMatchers/ASTMatchFinder.cpp
parentbb130ff39747b94592cb26d71b7cb097b9a4ea6b (diff)
parentb60736ec1405bb0a8dd40989f67ef4c93da068ab (diff)
downloadsrc-e8d8bef961a50d4dc22501cde4fb9fb0be1b2532.tar.gz
src-e8d8bef961a50d4dc22501cde4fb9fb0be1b2532.zip
Merge llvm-project main llvmorg-12-init-17869-g8e464dd76bef
This updates llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp to llvmorg-12-init-17869-g8e464dd76bef, the last commit before the upstream release/12.x branch was created. PR: 255570 MFC after: 6 weeks
Diffstat (limited to 'contrib/llvm-project/clang/lib/ASTMatchers/ASTMatchFinder.cpp')
-rw-r--r--contrib/llvm-project/clang/lib/ASTMatchers/ASTMatchFinder.cpp447
1 files changed, 348 insertions, 99 deletions
diff --git a/contrib/llvm-project/clang/lib/ASTMatchers/ASTMatchFinder.cpp b/contrib/llvm-project/clang/lib/ASTMatchers/ASTMatchFinder.cpp
index e88da16dd3d4..8ddd3c87e09d 100644
--- a/contrib/llvm-project/clang/lib/ASTMatchers/ASTMatchFinder.cpp
+++ b/contrib/llvm-project/clang/lib/ASTMatchers/ASTMatchFinder.cpp
@@ -95,9 +95,11 @@ public:
// matching the descendants.
MatchChildASTVisitor(const DynTypedMatcher *Matcher, ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder, int MaxDepth,
- TraversalKind Traversal, ASTMatchFinder::BindKind Bind)
+ bool IgnoreImplicitChildren,
+ ASTMatchFinder::BindKind Bind)
: Matcher(Matcher), Finder(Finder), Builder(Builder), CurrentDepth(0),
- MaxDepth(MaxDepth), Traversal(Traversal), Bind(Bind), Matches(false) {}
+ MaxDepth(MaxDepth), IgnoreImplicitChildren(IgnoreImplicitChildren),
+ Bind(Bind), Matches(false) {}
// Returns true if a match is found in the subtree rooted at the
// given AST node. This is done via a set of mutually recursive
@@ -128,6 +130,9 @@ public:
traverse(*T);
else if (const auto *C = DynNode.get<CXXCtorInitializer>())
traverse(*C);
+ else if (const TemplateArgumentLoc *TALoc =
+ DynNode.get<TemplateArgumentLoc>())
+ traverse(*TALoc);
// FIXME: Add other base types after adding tests.
// It's OK to always overwrite the bound nodes, as if there was
@@ -142,6 +147,11 @@ public:
// They are public only to allow CRTP to work. They are *not *part
// of the public API of this class.
bool TraverseDecl(Decl *DeclNode) {
+
+ if (DeclNode && DeclNode->isImplicit() &&
+ Finder->isTraversalIgnoringImplicitNodes())
+ return baseTraverse(*DeclNode);
+
ScopedIncrement ScopedDepth(&CurrentDepth);
return (DeclNode == nullptr) || traverse(*DeclNode);
}
@@ -150,19 +160,13 @@ public:
Stmt *StmtToTraverse = StmtNode;
if (auto *ExprNode = dyn_cast_or_null<Expr>(StmtNode)) {
auto *LambdaNode = dyn_cast_or_null<LambdaExpr>(StmtNode);
- if (LambdaNode &&
- Finder->getASTContext().getParentMapContext().getTraversalKind() ==
- TK_IgnoreUnlessSpelledInSource)
+ if (LambdaNode && Finder->isTraversalIgnoringImplicitNodes())
StmtToTraverse = LambdaNode;
else
StmtToTraverse =
Finder->getASTContext().getParentMapContext().traverseIgnored(
ExprNode);
}
- if (Traversal == TraversalKind::TK_IgnoreImplicitCastsAndParentheses) {
- if (Expr *ExprNode = dyn_cast_or_null<Expr>(StmtNode))
- StmtToTraverse = ExprNode->IgnoreParenImpCasts();
- }
return StmtToTraverse;
}
@@ -175,6 +179,10 @@ public:
Stmt *StmtToTraverse = getStmtToTraverse(StmtNode);
if (!StmtToTraverse)
return true;
+
+ if (IgnoreImplicitChildren && isa<CXXDefaultArgExpr>(StmtNode))
+ return true;
+
if (!match(*StmtToTraverse))
return false;
return VisitorBase::TraverseStmt(StmtToTraverse, Queue);
@@ -224,9 +232,35 @@ public:
ScopedIncrement ScopedDepth(&CurrentDepth);
return traverse(*CtorInit);
}
+ bool TraverseTemplateArgumentLoc(TemplateArgumentLoc TAL) {
+ ScopedIncrement ScopedDepth(&CurrentDepth);
+ return traverse(TAL);
+ }
+ bool TraverseCXXForRangeStmt(CXXForRangeStmt *Node) {
+ if (!Finder->isTraversalIgnoringImplicitNodes())
+ return VisitorBase::TraverseCXXForRangeStmt(Node);
+ if (!Node)
+ return true;
+ ScopedIncrement ScopedDepth(&CurrentDepth);
+ if (auto *Init = Node->getInit())
+ if (!match(*Init))
+ return false;
+ if (!match(*Node->getLoopVariable()) || !match(*Node->getRangeInit()) ||
+ !match(*Node->getBody()))
+ return false;
+ return VisitorBase::TraverseStmt(Node->getBody());
+ }
+ bool TraverseCXXRewrittenBinaryOperator(CXXRewrittenBinaryOperator *Node) {
+ if (!Finder->isTraversalIgnoringImplicitNodes())
+ return VisitorBase::TraverseCXXRewrittenBinaryOperator(Node);
+ if (!Node)
+ return true;
+ ScopedIncrement ScopedDepth(&CurrentDepth);
+
+ return match(*Node->getLHS()) && match(*Node->getRHS());
+ }
bool TraverseLambdaExpr(LambdaExpr *Node) {
- if (Finder->getASTContext().getParentMapContext().getTraversalKind() !=
- TK_IgnoreUnlessSpelledInSource)
+ if (!Finder->isTraversalIgnoringImplicitNodes())
return VisitorBase::TraverseLambdaExpr(Node);
if (!Node)
return true;
@@ -261,7 +295,7 @@ public:
}
bool shouldVisitTemplateInstantiations() const { return true; }
- bool shouldVisitImplicitCode() const { return true; }
+ bool shouldVisitImplicitCode() const { return !IgnoreImplicitChildren; }
private:
// Used for updating the depth during traversal.
@@ -304,6 +338,9 @@ private:
return VisitorBase::TraverseConstructorInitializer(
const_cast<CXXCtorInitializer *>(&CtorInit));
}
+ bool baseTraverse(TemplateArgumentLoc TAL) {
+ return VisitorBase::TraverseTemplateArgumentLoc(TAL);
+ }
// Sets 'Matched' to true if 'Matcher' matches 'Node' and:
// 0 < CurrentDepth <= MaxDepth.
@@ -352,7 +389,7 @@ private:
BoundNodesTreeBuilder ResultBindings;
int CurrentDepth;
const int MaxDepth;
- const TraversalKind Traversal;
+ const bool IgnoreImplicitChildren;
const ASTMatchFinder::BindKind Bind;
bool Matches;
};
@@ -447,16 +484,94 @@ public:
bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS);
bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS);
bool TraverseConstructorInitializer(CXXCtorInitializer *CtorInit);
+ bool TraverseTemplateArgumentLoc(TemplateArgumentLoc TAL);
+
+ bool dataTraverseNode(Stmt *S, DataRecursionQueue *Queue) {
+ if (auto *RF = dyn_cast<CXXForRangeStmt>(S)) {
+ for (auto *SubStmt : RF->children()) {
+ if (SubStmt == RF->getInit() || SubStmt == RF->getLoopVarStmt() ||
+ SubStmt == RF->getRangeInit() || SubStmt == RF->getBody()) {
+ TraverseStmt(SubStmt, Queue);
+ } else {
+ ASTNodeNotSpelledInSourceScope RAII(this, true);
+ TraverseStmt(SubStmt, Queue);
+ }
+ }
+ return true;
+ } else if (auto *RBO = dyn_cast<CXXRewrittenBinaryOperator>(S)) {
+ {
+ ASTNodeNotAsIsSourceScope RAII(this, true);
+ TraverseStmt(const_cast<Expr *>(RBO->getLHS()));
+ TraverseStmt(const_cast<Expr *>(RBO->getRHS()));
+ }
+ {
+ ASTNodeNotSpelledInSourceScope RAII(this, true);
+ for (auto *SubStmt : RBO->children()) {
+ TraverseStmt(SubStmt);
+ }
+ }
+ return true;
+ } else if (auto *LE = dyn_cast<LambdaExpr>(S)) {
+ for (auto I : llvm::zip(LE->captures(), LE->capture_inits())) {
+ auto C = std::get<0>(I);
+ ASTNodeNotSpelledInSourceScope RAII(
+ this, TraversingASTNodeNotSpelledInSource || !C.isExplicit());
+ TraverseLambdaCapture(LE, &C, std::get<1>(I));
+ }
+
+ {
+ ASTNodeNotSpelledInSourceScope RAII(this, true);
+ TraverseDecl(LE->getLambdaClass());
+ }
+ {
+ ASTNodeNotAsIsSourceScope RAII(this, true);
+
+ // We need to poke around to find the bits that might be explicitly
+ // written.
+ TypeLoc TL = LE->getCallOperator()->getTypeSourceInfo()->getTypeLoc();
+ FunctionProtoTypeLoc Proto = TL.getAsAdjusted<FunctionProtoTypeLoc>();
+
+ if (auto *TPL = LE->getTemplateParameterList()) {
+ for (NamedDecl *D : *TPL) {
+ TraverseDecl(D);
+ }
+ if (Expr *RequiresClause = TPL->getRequiresClause()) {
+ TraverseStmt(RequiresClause);
+ }
+ }
+
+ if (LE->hasExplicitParameters()) {
+ // Visit parameters.
+ for (ParmVarDecl *Param : Proto.getParams())
+ TraverseDecl(Param);
+ }
+
+ const auto *T = Proto.getTypePtr();
+ for (const auto &E : T->exceptions())
+ TraverseType(E);
+
+ if (Expr *NE = T->getNoexceptExpr())
+ TraverseStmt(NE, Queue);
+
+ if (LE->hasExplicitResultType())
+ TraverseTypeLoc(Proto.getReturnLoc());
+ TraverseStmt(LE->getTrailingRequiresClause());
+
+ TraverseStmt(LE->getBody());
+ }
+ return true;
+ }
+ return RecursiveASTVisitor<MatchASTVisitor>::dataTraverseNode(S, Queue);
+ }
// Matches children or descendants of 'Node' with 'BaseMatcher'.
bool memoizedMatchesRecursively(const DynTypedNode &Node, ASTContext &Ctx,
const DynTypedMatcher &Matcher,
BoundNodesTreeBuilder *Builder, int MaxDepth,
- TraversalKind Traversal, BindKind Bind) {
+ BindKind Bind) {
// For AST-nodes that don't have an identity, we can't memoize.
if (!Node.getMemoizationData() || !Builder->isComparable())
- return matchesRecursively(Node, Matcher, Builder, MaxDepth, Traversal,
- Bind);
+ return matchesRecursively(Node, Matcher, Builder, MaxDepth, Bind);
MatchKey Key;
Key.MatcherID = Matcher.getID();
@@ -474,8 +589,8 @@ public:
MemoizedMatchResult Result;
Result.Nodes = *Builder;
- Result.ResultOfMatch = matchesRecursively(Node, Matcher, &Result.Nodes,
- MaxDepth, Traversal, Bind);
+ Result.ResultOfMatch =
+ matchesRecursively(Node, Matcher, &Result.Nodes, MaxDepth, Bind);
MemoizedMatchResult &CachedResult = ResultCache[Key];
CachedResult = std::move(Result);
@@ -488,9 +603,20 @@ public:
bool matchesRecursively(const DynTypedNode &Node,
const DynTypedMatcher &Matcher,
BoundNodesTreeBuilder *Builder, int MaxDepth,
- TraversalKind Traversal, BindKind Bind) {
- MatchChildASTVisitor Visitor(
- &Matcher, this, Builder, MaxDepth, Traversal, Bind);
+ BindKind Bind) {
+ bool ScopedTraversal = TraversingASTNodeNotSpelledInSource ||
+ TraversingASTChildrenNotSpelledInSource;
+
+ bool IgnoreImplicitChildren = false;
+
+ if (isTraversalIgnoringImplicitNodes()) {
+ IgnoreImplicitChildren = true;
+ }
+
+ ASTNodeNotSpelledInSourceScope RAII(this, ScopedTraversal);
+
+ MatchChildASTVisitor Visitor(&Matcher, this, Builder, MaxDepth,
+ IgnoreImplicitChildren, Bind);
return Visitor.findMatch(Node);
}
@@ -507,12 +633,10 @@ public:
// Implements ASTMatchFinder::matchesChildOf.
bool matchesChildOf(const DynTypedNode &Node, ASTContext &Ctx,
const DynTypedMatcher &Matcher,
- BoundNodesTreeBuilder *Builder, TraversalKind Traversal,
- BindKind Bind) override {
+ BoundNodesTreeBuilder *Builder, BindKind Bind) override {
if (ResultCache.size() > MaxMemoizationEntries)
ResultCache.clear();
- return memoizedMatchesRecursively(Node, Ctx, Matcher, Builder, 1, Traversal,
- Bind);
+ return memoizedMatchesRecursively(Node, Ctx, Matcher, Builder, 1, Bind);
}
// Implements ASTMatchFinder::matchesDescendantOf.
bool matchesDescendantOf(const DynTypedNode &Node, ASTContext &Ctx,
@@ -522,7 +646,7 @@ public:
if (ResultCache.size() > MaxMemoizationEntries)
ResultCache.clear();
return memoizedMatchesRecursively(Node, Ctx, Matcher, Builder, INT_MAX,
- TraversalKind::TK_AsIs, Bind);
+ Bind);
}
// Implements ASTMatchFinder::matchesAncestorOf.
bool matchesAncestorOf(const DynTypedNode &Node, ASTContext &Ctx,
@@ -533,8 +657,9 @@ public:
// don't invalidate any iterators.
if (ResultCache.size() > MaxMemoizationEntries)
ResultCache.clear();
- return memoizedMatchesAncestorOfRecursively(Node, Ctx, Matcher, Builder,
- MatchMode);
+ if (MatchMode == AncestorMatchMode::AMM_ParentOnly)
+ return matchesParentOf(Node, Matcher, Builder);
+ return matchesAnyAncestorOf(Node, Ctx, Matcher, Builder);
}
// Matches all registered matchers on the given node and calls the
@@ -557,6 +682,8 @@ public:
match(*N);
} else if (auto *N = Node.get<CXXCtorInitializer>()) {
match(*N);
+ } else if (auto *N = Node.get<TemplateArgumentLoc>()) {
+ match(*N);
}
}
@@ -570,7 +697,69 @@ public:
bool shouldVisitTemplateInstantiations() const { return true; }
bool shouldVisitImplicitCode() const { return true; }
+ bool IsMatchingInASTNodeNotSpelledInSource() const override {
+ return TraversingASTNodeNotSpelledInSource;
+ }
+ bool isMatchingChildrenNotSpelledInSource() const override {
+ return TraversingASTChildrenNotSpelledInSource;
+ }
+ void setMatchingChildrenNotSpelledInSource(bool Set) override {
+ TraversingASTChildrenNotSpelledInSource = Set;
+ }
+
+ bool IsMatchingInASTNodeNotAsIs() const override {
+ return TraversingASTNodeNotAsIs;
+ }
+
+ bool TraverseTemplateInstantiations(ClassTemplateDecl *D) {
+ ASTNodeNotSpelledInSourceScope RAII(this, true);
+ return RecursiveASTVisitor<MatchASTVisitor>::TraverseTemplateInstantiations(
+ D);
+ }
+
+ bool TraverseTemplateInstantiations(VarTemplateDecl *D) {
+ ASTNodeNotSpelledInSourceScope RAII(this, true);
+ return RecursiveASTVisitor<MatchASTVisitor>::TraverseTemplateInstantiations(
+ D);
+ }
+
+ bool TraverseTemplateInstantiations(FunctionTemplateDecl *D) {
+ ASTNodeNotSpelledInSourceScope RAII(this, true);
+ return RecursiveASTVisitor<MatchASTVisitor>::TraverseTemplateInstantiations(
+ D);
+ }
+
private:
+ bool TraversingASTNodeNotSpelledInSource = false;
+ bool TraversingASTNodeNotAsIs = false;
+ bool TraversingASTChildrenNotSpelledInSource = false;
+
+ struct ASTNodeNotSpelledInSourceScope {
+ ASTNodeNotSpelledInSourceScope(MatchASTVisitor *V, bool B)
+ : MV(V), MB(V->TraversingASTNodeNotSpelledInSource) {
+ V->TraversingASTNodeNotSpelledInSource = B;
+ }
+ ~ASTNodeNotSpelledInSourceScope() {
+ MV->TraversingASTNodeNotSpelledInSource = MB;
+ }
+
+ private:
+ MatchASTVisitor *MV;
+ bool MB;
+ };
+
+ struct ASTNodeNotAsIsSourceScope {
+ ASTNodeNotAsIsSourceScope(MatchASTVisitor *V, bool B)
+ : MV(V), MB(V->TraversingASTNodeNotAsIs) {
+ V->TraversingASTNodeNotAsIs = B;
+ }
+ ~ASTNodeNotAsIsSourceScope() { MV->TraversingASTNodeNotAsIs = MB; }
+
+ private:
+ MatchASTVisitor *MV;
+ bool MB;
+ };
+
class TimeBucketRegion {
public:
TimeBucketRegion() : Bucket(nullptr) {}
@@ -680,12 +869,29 @@ private:
void matchDispatch(const CXXCtorInitializer *Node) {
matchWithoutFilter(*Node, Matchers->CtorInit);
}
+ void matchDispatch(const TemplateArgumentLoc *Node) {
+ matchWithoutFilter(*Node, Matchers->TemplateArgumentLoc);
+ }
void matchDispatch(const void *) { /* Do nothing. */ }
/// @}
+ // Returns whether a direct parent of \p Node matches \p Matcher.
+ // Unlike matchesAnyAncestorOf there's no memoization: it doesn't save much.
+ bool matchesParentOf(const DynTypedNode &Node, const DynTypedMatcher &Matcher,
+ BoundNodesTreeBuilder *Builder) {
+ for (const auto &Parent : ActiveASTContext->getParents(Node)) {
+ BoundNodesTreeBuilder BuilderCopy = *Builder;
+ if (Matcher.matches(Parent, this, &BuilderCopy)) {
+ *Builder = std::move(BuilderCopy);
+ return true;
+ }
+ }
+ return false;
+ }
+
// Returns whether an ancestor of \p Node matches \p Matcher.
//
- // The order of matching ((which can lead to different nodes being bound in
+ // The order of matching (which can lead to different nodes being bound in
// case there are multiple matches) is breadth first search.
//
// To allow memoization in the very common case of having deeply nested
@@ -696,51 +902,64 @@ private:
// Once there are multiple parents, the breadth first search order does not
// allow simple memoization on the ancestors. Thus, we only memoize as long
// as there is a single parent.
- bool memoizedMatchesAncestorOfRecursively(const DynTypedNode &Node,
- ASTContext &Ctx,
- const DynTypedMatcher &Matcher,
- BoundNodesTreeBuilder *Builder,
- AncestorMatchMode MatchMode) {
- // For AST-nodes that don't have an identity, we can't memoize.
- // When doing a single-level match, we don't need to memoize because
- // ParentMap (in ASTContext) already memoizes the result.
- if (!Builder->isComparable() ||
- MatchMode == AncestorMatchMode::AMM_ParentOnly)
- return matchesAncestorOfRecursively(Node, Ctx, Matcher, Builder,
- MatchMode);
-
- MatchKey Key;
- Key.MatcherID = Matcher.getID();
- Key.Node = Node;
- Key.BoundNodes = *Builder;
- Key.Traversal = Ctx.getParentMapContext().getTraversalKind();
- Key.Type = MatchType::Ancestors;
+ //
+ // We avoid a recursive implementation to prevent excessive stack use on
+ // very deep ASTs (similarly to RecursiveASTVisitor's data recursion).
+ bool matchesAnyAncestorOf(DynTypedNode Node, ASTContext &Ctx,
+ const DynTypedMatcher &Matcher,
+ BoundNodesTreeBuilder *Builder) {
- // Note that we cannot use insert and reuse the iterator, as recursive
- // calls to match might invalidate the result cache iterators.
- MemoizationMap::iterator I = ResultCache.find(Key);
- if (I != ResultCache.end()) {
- *Builder = I->second.Nodes;
- return I->second.ResultOfMatch;
- }
+ // Memoization keys that can be updated with the result.
+ // These are the memoizable nodes in the chain of unique parents, which
+ // terminates when a node has multiple parents, or matches, or is the root.
+ std::vector<MatchKey> Keys;
+ // When returning, update the memoization cache.
+ auto Finish = [&](bool Matched) {
+ for (const auto &Key : Keys) {
+ MemoizedMatchResult &CachedResult = ResultCache[Key];
+ CachedResult.ResultOfMatch = Matched;
+ CachedResult.Nodes = *Builder;
+ }
+ return Matched;
+ };
+
+ // Loop while there's a single parent and we want to attempt memoization.
+ DynTypedNodeList Parents{ArrayRef<DynTypedNode>()}; // after loop: size != 1
+ for (;;) {
+ // A cache key only makes sense if memoization is possible.
+ if (Builder->isComparable()) {
+ Keys.emplace_back();
+ Keys.back().MatcherID = Matcher.getID();
+ Keys.back().Node = Node;
+ Keys.back().BoundNodes = *Builder;
+ Keys.back().Traversal = Ctx.getParentMapContext().getTraversalKind();
+ Keys.back().Type = MatchType::Ancestors;
+
+ // Check the cache.
+ MemoizationMap::iterator I = ResultCache.find(Keys.back());
+ if (I != ResultCache.end()) {
+ Keys.pop_back(); // Don't populate the cache for the matching node!
+ *Builder = I->second.Nodes;
+ return Finish(I->second.ResultOfMatch);
+ }
+ }
- MemoizedMatchResult Result;
- Result.Nodes = *Builder;
- Result.ResultOfMatch = matchesAncestorOfRecursively(
- Node, Ctx, Matcher, &Result.Nodes, MatchMode);
+ Parents = ActiveASTContext->getParents(Node);
+ // Either no parents or multiple parents: leave chain+memoize mode and
+ // enter bfs+forgetful mode.
+ if (Parents.size() != 1)
+ break;
- MemoizedMatchResult &CachedResult = ResultCache[Key];
- CachedResult = std::move(Result);
-
- *Builder = CachedResult.Nodes;
- return CachedResult.ResultOfMatch;
- }
+ // Check the next parent.
+ Node = *Parents.begin();
+ BoundNodesTreeBuilder BuilderCopy = *Builder;
+ if (Matcher.matches(Node, this, &BuilderCopy)) {
+ *Builder = std::move(BuilderCopy);
+ return Finish(true);
+ }
+ }
+ // We reached the end of the chain.
- bool matchesAncestorOfRecursively(const DynTypedNode &Node, ASTContext &Ctx,
- const DynTypedMatcher &Matcher,
- BoundNodesTreeBuilder *Builder,
- AncestorMatchMode MatchMode) {
- const auto &Parents = ActiveASTContext->getParents(Node);
if (Parents.empty()) {
// Nodes may have no parents if:
// a) the node is the TranslationUnitDecl
@@ -759,46 +978,30 @@ private:
llvm_unreachable("Parent map should be complete!");
}
#endif
- return false;
- }
- if (Parents.size() == 1) {
- // Only one parent - do recursive memoization.
- const DynTypedNode Parent = Parents[0];
- BoundNodesTreeBuilder BuilderCopy = *Builder;
- if (Matcher.matches(Parent, this, &BuilderCopy)) {
- *Builder = std::move(BuilderCopy);
- return true;
- }
- if (MatchMode != ASTMatchFinder::AMM_ParentOnly) {
- return memoizedMatchesAncestorOfRecursively(Parent, Ctx, Matcher,
- Builder, MatchMode);
- // Once we get back from the recursive call, the result will be the
- // same as the parent's result.
- }
} else {
- // Multiple parents - BFS over the rest of the nodes.
- llvm::DenseSet<const void *> Visited;
+ assert(Parents.size() > 1);
+ // BFS starting from the parents not yet considered.
+ // Memoization of newly visited nodes is not possible (but we still update
+ // results for the elements in the chain we found above).
std::deque<DynTypedNode> Queue(Parents.begin(), Parents.end());
+ llvm::DenseSet<const void *> Visited;
while (!Queue.empty()) {
BoundNodesTreeBuilder BuilderCopy = *Builder;
if (Matcher.matches(Queue.front(), this, &BuilderCopy)) {
*Builder = std::move(BuilderCopy);
- return true;
+ return Finish(true);
}
- if (MatchMode != ASTMatchFinder::AMM_ParentOnly) {
- for (const auto &Parent :
- ActiveASTContext->getParents(Queue.front())) {
- // Make sure we do not visit the same node twice.
- // Otherwise, we'll visit the common ancestors as often as there
- // are splits on the way down.
- if (Visited.insert(Parent.getMemoizationData()).second)
- Queue.push_back(Parent);
- }
+ for (const auto &Parent : ActiveASTContext->getParents(Queue.front())) {
+ // Make sure we do not visit the same node twice.
+ // Otherwise, we'll visit the common ancestors as often as there
+ // are splits on the way down.
+ if (Visited.insert(Parent.getMemoizationData()).second)
+ Queue.push_back(Parent);
}
Queue.pop_front();
}
}
- return false;
+ return Finish(false);
}
// Implements a BoundNodesTree::Visitor that calls a MatchCallback with
@@ -976,6 +1179,26 @@ bool MatchASTVisitor::TraverseDecl(Decl *DeclNode) {
if (!DeclNode) {
return true;
}
+
+ bool ScopedTraversal =
+ TraversingASTNodeNotSpelledInSource || DeclNode->isImplicit();
+ bool ScopedChildren = TraversingASTChildrenNotSpelledInSource;
+
+ if (const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(DeclNode)) {
+ auto SK = CTSD->getSpecializationKind();
+ if (SK == TSK_ExplicitInstantiationDeclaration ||
+ SK == TSK_ExplicitInstantiationDefinition)
+ ScopedChildren = true;
+ } else if (const auto *FD = dyn_cast<FunctionDecl>(DeclNode)) {
+ if (FD->isDefaulted())
+ ScopedChildren = true;
+ if (FD->isTemplateInstantiation())
+ ScopedTraversal = true;
+ }
+
+ ASTNodeNotSpelledInSourceScope RAII1(this, ScopedTraversal);
+ ASTChildrenNotSpelledInSourceScope RAII2(this, ScopedChildren);
+
match(*DeclNode);
return RecursiveASTVisitor<MatchASTVisitor>::TraverseDecl(DeclNode);
}
@@ -984,6 +1207,10 @@ bool MatchASTVisitor::TraverseStmt(Stmt *StmtNode, DataRecursionQueue *Queue) {
if (!StmtNode) {
return true;
}
+ bool ScopedTraversal = TraversingASTNodeNotSpelledInSource ||
+ TraversingASTChildrenNotSpelledInSource;
+
+ ASTNodeNotSpelledInSourceScope RAII(this, ScopedTraversal);
match(*StmtNode);
return RecursiveASTVisitor<MatchASTVisitor>::TraverseStmt(StmtNode, Queue);
}
@@ -1029,12 +1256,25 @@ bool MatchASTVisitor::TraverseConstructorInitializer(
if (!CtorInit)
return true;
+ bool ScopedTraversal = TraversingASTNodeNotSpelledInSource ||
+ TraversingASTChildrenNotSpelledInSource;
+
+ if (!CtorInit->isWritten())
+ ScopedTraversal = true;
+
+ ASTNodeNotSpelledInSourceScope RAII1(this, ScopedTraversal);
+
match(*CtorInit);
return RecursiveASTVisitor<MatchASTVisitor>::TraverseConstructorInitializer(
CtorInit);
}
+bool MatchASTVisitor::TraverseTemplateArgumentLoc(TemplateArgumentLoc Loc) {
+ match(Loc);
+ return RecursiveASTVisitor<MatchASTVisitor>::TraverseTemplateArgumentLoc(Loc);
+}
+
class MatchASTConsumer : public ASTConsumer {
public:
MatchASTConsumer(MatchFinder *Finder,
@@ -1111,6 +1351,12 @@ void MatchFinder::addMatcher(const CXXCtorInitializerMatcher &NodeMatch,
Matchers.AllCallbacks.insert(Action);
}
+void MatchFinder::addMatcher(const TemplateArgumentLocMatcher &NodeMatch,
+ MatchCallback *Action) {
+ Matchers.TemplateArgumentLoc.emplace_back(NodeMatch, Action);
+ Matchers.AllCallbacks.insert(Action);
+}
+
bool MatchFinder::addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch,
MatchCallback *Action) {
if (NodeMatch.canConvertTo<Decl>()) {
@@ -1134,6 +1380,9 @@ bool MatchFinder::addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch,
} else if (NodeMatch.canConvertTo<CXXCtorInitializer>()) {
addMatcher(NodeMatch.convertTo<CXXCtorInitializer>(), Action);
return true;
+ } else if (NodeMatch.canConvertTo<TemplateArgumentLoc>()) {
+ addMatcher(NodeMatch.convertTo<TemplateArgumentLoc>(), Action);
+ return true;
}
return false;
}