diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2021-06-13 19:31:46 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2021-06-13 19:37:19 +0000 |
commit | e8d8bef961a50d4dc22501cde4fb9fb0be1b2532 (patch) | |
tree | 94f04805f47bb7c59ae29690d8952b6074fff602 /contrib/llvm-project/clang/lib/ASTMatchers/ASTMatchFinder.cpp | |
parent | bb130ff39747b94592cb26d71b7cb097b9a4ea6b (diff) | |
parent | b60736ec1405bb0a8dd40989f67ef4c93da068ab (diff) | |
download | src-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.cpp | 447 |
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; } |