diff options
Diffstat (limited to 'include/clang/AST/RecursiveASTVisitor.h')
-rw-r--r-- | include/clang/AST/RecursiveASTVisitor.h | 464 |
1 files changed, 274 insertions, 190 deletions
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index 1017656b662c..e6f758364a85 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -14,6 +14,8 @@ #ifndef LLVM_CLANG_AST_RECURSIVEASTVISITOR_H #define LLVM_CLANG_AST_RECURSIVEASTVISITOR_H +#include <type_traits> + #include "clang/AST/Attr.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" @@ -24,6 +26,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" +#include "clang/AST/ExprOpenMP.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/Stmt.h" #include "clang/AST/StmtCXX.h" @@ -42,7 +45,7 @@ OPERATOR(PostInc) OPERATOR(PostDec) OPERATOR(PreInc) OPERATOR(PreDec) \ OPERATOR(AddrOf) OPERATOR(Deref) OPERATOR(Plus) OPERATOR(Minus) \ OPERATOR(Not) OPERATOR(LNot) OPERATOR(Real) OPERATOR(Imag) \ - OPERATOR(Extension) + OPERATOR(Extension) OPERATOR(Coawait) // All binary operators (excluding compound assign operators). #define BINOP_LIST() \ @@ -132,6 +135,12 @@ namespace clang { /// from which they were produced. template <typename Derived> class RecursiveASTVisitor { public: + /// A queue used for performing data recursion over statements. + /// Parameters involving this type are used to implement data + /// recursion over Stmts and Exprs within this class, and should + /// typically not be explicitly specified by derived classes. + typedef SmallVectorImpl<Stmt *> DataRecursionQueue; + /// \brief Return a reference to the derived class. Derived &getDerived() { return *static_cast<Derived *>(this); } @@ -147,19 +156,12 @@ public: /// code, e.g., implicit constructors and destructors. bool shouldVisitImplicitCode() const { return false; } - /// \brief Return whether \param S should be traversed using data recursion - /// to avoid a stack overflow with extreme cases. - bool shouldUseDataRecursionFor(Stmt *S) const { - return isa<BinaryOperator>(S) || isa<UnaryOperator>(S) || - isa<CaseStmt>(S) || isa<CXXOperatorCallExpr>(S); - } - /// \brief Recursively visit a statement or expression, by /// dispatching to Traverse*() based on the argument's dynamic type. /// /// \returns false if the visitation was terminated early, true - /// otherwise (including when the argument is NULL). - bool TraverseStmt(Stmt *S); + /// otherwise (including when the argument is nullptr). + bool TraverseStmt(Stmt *S, DataRecursionQueue *Queue = nullptr); /// \brief Recursively visit a type, by dispatching to /// Traverse*Type() based on the argument's getTypeClass() property. @@ -252,7 +254,14 @@ public: /// \c LE->getBody(). /// /// \returns false if the visitation was terminated early, true otherwise. - bool TraverseLambdaBody(LambdaExpr *LE); + bool TraverseLambdaBody(LambdaExpr *LE, DataRecursionQueue *Queue = nullptr); + + /// \brief Recursively visit the syntactic or semantic form of an + /// initialization list. + /// + /// \returns false if the visitation was terminated early, true otherwise. + bool TraverseSynOrSemInitListExpr(InitListExpr *S, + DataRecursionQueue *Queue = nullptr); // ---- Methods on Attrs ---- @@ -266,9 +275,44 @@ public: // ---- Methods on Stmts ---- +private: + template<typename T, typename U> + struct has_same_member_pointer_type : std::false_type {}; + template<typename T, typename U, typename R, typename... P> + struct has_same_member_pointer_type<R (T::*)(P...), R (U::*)(P...)> + : std::true_type {}; + + // Traverse the given statement. If the most-derived traverse function takes a + // data recursion queue, pass it on; otherwise, discard it. Note that the + // first branch of this conditional must compile whether or not the derived + // class can take a queue, so if we're taking the second arm, make the first + // arm call our function rather than the derived class version. +#define TRAVERSE_STMT_BASE(NAME, CLASS, VAR, QUEUE) \ + (has_same_member_pointer_type<decltype( \ + &RecursiveASTVisitor::Traverse##NAME), \ + decltype(&Derived::Traverse##NAME)>::value \ + ? static_cast<typename std::conditional< \ + has_same_member_pointer_type< \ + decltype(&RecursiveASTVisitor::Traverse##NAME), \ + decltype(&Derived::Traverse##NAME)>::value, \ + Derived &, RecursiveASTVisitor &>::type>(*this) \ + .Traverse##NAME(static_cast<CLASS *>(VAR), QUEUE) \ + : getDerived().Traverse##NAME(static_cast<CLASS *>(VAR))) + +// Try to traverse the given statement, or enqueue it if we're performing data +// recursion in the middle of traversing another statement. Can only be called +// from within a DEF_TRAVERSE_STMT body or similar context. +#define TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S) \ + do { \ + if (!TRAVERSE_STMT_BASE(Stmt, Stmt, S, Queue)) \ + return false; \ + } while (0) + +public: // Declare Traverse*() for all concrete Stmt classes. #define ABSTRACT_STMT(STMT) -#define STMT(CLASS, PARENT) bool Traverse##CLASS(CLASS *S); +#define STMT(CLASS, PARENT) \ + bool Traverse##CLASS(CLASS *S, DataRecursionQueue *Queue = nullptr); #include "clang/AST/StmtNodes.inc" // The above header #undefs ABSTRACT_STMT and STMT upon exit. @@ -288,9 +332,10 @@ public: // operator methods. Unary operators are not classes in themselves // (they're all opcodes in UnaryOperator) but do have visitors. #define OPERATOR(NAME) \ - bool TraverseUnary##NAME(UnaryOperator *S) { \ + bool TraverseUnary##NAME(UnaryOperator *S, \ + DataRecursionQueue *Queue = nullptr) { \ TRY_TO(WalkUpFromUnary##NAME(S)); \ - TRY_TO(TraverseStmt(S->getSubExpr())); \ + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getSubExpr()); \ return true; \ } \ bool WalkUpFromUnary##NAME(UnaryOperator *S) { \ @@ -307,10 +352,10 @@ public: // operator methods. Binary operators are not classes in themselves // (they're all opcodes in BinaryOperator) but do have visitors. #define GENERAL_BINOP_FALLBACK(NAME, BINOP_TYPE) \ - bool TraverseBin##NAME(BINOP_TYPE *S) { \ + bool TraverseBin##NAME(BINOP_TYPE *S, DataRecursionQueue *Queue = nullptr) { \ TRY_TO(WalkUpFromBin##NAME(S)); \ - TRY_TO(TraverseStmt(S->getLHS())); \ - TRY_TO(TraverseStmt(S->getRHS())); \ + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getLHS()); \ + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getRHS()); \ return true; \ } \ bool WalkUpFromBin##NAME(BINOP_TYPE *S) { \ @@ -436,98 +481,45 @@ private: /// \brief Process clauses with list of variables. template <typename T> bool VisitOMPClauseList(T *Node); - struct EnqueueJob { - Stmt *S; - Stmt::child_iterator StmtIt; - - EnqueueJob(Stmt *S) : S(S), StmtIt() {} - }; - bool dataTraverse(Stmt *S); - bool dataTraverseNode(Stmt *S, bool &EnqueueChildren); + bool dataTraverseNode(Stmt *S, DataRecursionQueue *Queue); }; template <typename Derived> -bool RecursiveASTVisitor<Derived>::dataTraverse(Stmt *S) { - - SmallVector<EnqueueJob, 16> Queue; - Queue.push_back(S); - - while (!Queue.empty()) { - EnqueueJob &job = Queue.back(); - Stmt *CurrS = job.S; - if (!CurrS) { - Queue.pop_back(); - continue; - } - - if (getDerived().shouldUseDataRecursionFor(CurrS)) { - if (job.StmtIt == Stmt::child_iterator()) { - bool EnqueueChildren = true; - if (!dataTraverseNode(CurrS, EnqueueChildren)) - return false; - if (!EnqueueChildren) { - Queue.pop_back(); - continue; - } - job.StmtIt = CurrS->child_begin(); - } else { - ++job.StmtIt; - } - - if (job.StmtIt != CurrS->child_end()) - Queue.push_back(*job.StmtIt); - else - Queue.pop_back(); - continue; - } - - Queue.pop_back(); - TRY_TO(TraverseStmt(CurrS)); - } - - return true; -} - -template <typename Derived> bool RecursiveASTVisitor<Derived>::dataTraverseNode(Stmt *S, - bool &EnqueueChildren) { - -// Dispatch to the corresponding WalkUpFrom* function only if the derived -// class didn't override Traverse* (and thus the traversal is trivial). -#define DISPATCH_WALK(NAME, CLASS, VAR) \ - { \ - bool (Derived::*DerivedFn)(CLASS *) = &Derived::Traverse##NAME; \ - bool (Derived::*BaseFn)(CLASS *) = &RecursiveASTVisitor::Traverse##NAME; \ - if (DerivedFn == BaseFn) \ - return getDerived().WalkUpFrom##NAME(static_cast<CLASS *>(VAR)); \ - } \ - EnqueueChildren = false; \ - return getDerived().Traverse##NAME(static_cast<CLASS *>(VAR)); + DataRecursionQueue *Queue) { +#define DISPATCH_STMT(NAME, CLASS, VAR) \ + return TRAVERSE_STMT_BASE(NAME, CLASS, VAR, Queue); + // If we have a binary expr, dispatch to the subcode of the binop. A smart + // optimizer (e.g. LLVM) will fold this comparison into the switch stmt + // below. if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(S)) { switch (BinOp->getOpcode()) { #define OPERATOR(NAME) \ case BO_##NAME: \ - DISPATCH_WALK(Bin##NAME, BinaryOperator, S); + DISPATCH_STMT(Bin##NAME, BinaryOperator, S); BINOP_LIST() #undef OPERATOR +#undef BINOP_LIST #define OPERATOR(NAME) \ case BO_##NAME##Assign: \ - DISPATCH_WALK(Bin##NAME##Assign, CompoundAssignOperator, S); + DISPATCH_STMT(Bin##NAME##Assign, CompoundAssignOperator, S); CAO_LIST() #undef OPERATOR +#undef CAO_LIST } } else if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(S)) { switch (UnOp->getOpcode()) { #define OPERATOR(NAME) \ case UO_##NAME: \ - DISPATCH_WALK(Unary##NAME, UnaryOperator, S); + DISPATCH_STMT(Unary##NAME, UnaryOperator, S); UNARYOP_LIST() #undef OPERATOR +#undef UNARYOP_LIST } } @@ -538,76 +530,43 @@ bool RecursiveASTVisitor<Derived>::dataTraverseNode(Stmt *S, #define ABSTRACT_STMT(STMT) #define STMT(CLASS, PARENT) \ case Stmt::CLASS##Class: \ - DISPATCH_WALK(CLASS, CLASS, S); + DISPATCH_STMT(CLASS, CLASS, S); #include "clang/AST/StmtNodes.inc" } -#undef DISPATCH_WALK - return true; } -#define DISPATCH(NAME, CLASS, VAR) \ - return getDerived().Traverse##NAME(static_cast<CLASS *>(VAR)) +#undef DISPATCH_STMT template <typename Derived> -bool RecursiveASTVisitor<Derived>::TraverseStmt(Stmt *S) { +bool RecursiveASTVisitor<Derived>::TraverseStmt(Stmt *S, + DataRecursionQueue *Queue) { if (!S) return true; -#define DISPATCH_STMT(NAME, CLASS, VAR) DISPATCH(NAME, CLASS, VAR) - - if (getDerived().shouldUseDataRecursionFor(S)) - return dataTraverse(S); - - // If we have a binary expr, dispatch to the subcode of the binop. A smart - // optimizer (e.g. LLVM) will fold this comparison into the switch stmt - // below. - if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(S)) { - switch (BinOp->getOpcode()) { -#define OPERATOR(NAME) \ - case BO_##NAME: \ - DISPATCH_STMT(Bin##NAME, BinaryOperator, S); - - BINOP_LIST() -#undef OPERATOR -#undef BINOP_LIST + if (Queue) { + Queue->push_back(S); + return true; + } -#define OPERATOR(NAME) \ - case BO_##NAME##Assign: \ - DISPATCH_STMT(Bin##NAME##Assign, CompoundAssignOperator, S); + SmallVector<Stmt *, 8> LocalQueue; + LocalQueue.push_back(S); - CAO_LIST() -#undef OPERATOR -#undef CAO_LIST - } - } else if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(S)) { - switch (UnOp->getOpcode()) { -#define OPERATOR(NAME) \ - case UO_##NAME: \ - DISPATCH_STMT(Unary##NAME, UnaryOperator, S); + while (!LocalQueue.empty()) { + Stmt *CurrS = LocalQueue.pop_back_val(); - UNARYOP_LIST() -#undef OPERATOR -#undef UNARYOP_LIST - } - } - - // Top switch stmt: dispatch to TraverseFooStmt for each concrete FooStmt. - switch (S->getStmtClass()) { - case Stmt::NoStmtClass: - break; -#define ABSTRACT_STMT(STMT) -#define STMT(CLASS, PARENT) \ - case Stmt::CLASS##Class: \ - DISPATCH_STMT(CLASS, CLASS, S); -#include "clang/AST/StmtNodes.inc" + size_t N = LocalQueue.size(); + TRY_TO(dataTraverseNode(CurrS, &LocalQueue)); + // Process new children in the order they were added. + std::reverse(LocalQueue.begin() + N, LocalQueue.end()); } return true; } -#undef DISPATCH_STMT +#define DISPATCH(NAME, CLASS, VAR) \ + return getDerived().Traverse##NAME(static_cast<CLASS *>(VAR)) template <typename Derived> bool RecursiveASTVisitor<Derived>::TraverseType(QualType T) { @@ -863,8 +822,9 @@ RecursiveASTVisitor<Derived>::TraverseLambdaCapture(LambdaExpr *LE, } template <typename Derived> -bool RecursiveASTVisitor<Derived>::TraverseLambdaBody(LambdaExpr *LE) { - TRY_TO(TraverseStmt(LE->getBody())); +bool RecursiveASTVisitor<Derived>::TraverseLambdaBody( + LambdaExpr *LE, DataRecursionQueue *Queue) { + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(LE->getBody()); return true; } @@ -1364,6 +1324,8 @@ DEF_TRAVERSE_DECL( DEF_TRAVERSE_DECL(ExternCContextDecl, {}) DEF_TRAVERSE_DECL(NamespaceAliasDecl, { + TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc())); + // We shouldn't traverse an aliased namespace, since it will be // defined (and, therefore, traversed) somewhere else. // @@ -1596,6 +1558,10 @@ DEF_TRAVERSE_DECL(TemplateTemplateParmDecl, { TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters())); }) +DEF_TRAVERSE_DECL(BuiltinTemplateDecl, { + TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters())); +}) + DEF_TRAVERSE_DECL(TemplateTypeParmDecl, { // D is the "T" in something like "template<typename T> class vector;" if (D->getTypeForDecl()) @@ -1906,25 +1872,26 @@ DEF_TRAVERSE_DECL(ParmVarDecl, { // This macro makes available a variable S, the passed-in stmt. #define DEF_TRAVERSE_STMT(STMT, CODE) \ template <typename Derived> \ - bool RecursiveASTVisitor<Derived>::Traverse##STMT(STMT *S) { \ + bool RecursiveASTVisitor<Derived>::Traverse##STMT( \ + STMT *S, DataRecursionQueue *Queue) { \ TRY_TO(WalkUpFrom##STMT(S)); \ { CODE; } \ for (Stmt *SubStmt : S->children()) { \ - TRY_TO(TraverseStmt(SubStmt)); \ + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(SubStmt); \ } \ return true; \ } DEF_TRAVERSE_STMT(GCCAsmStmt, { - TRY_TO(TraverseStmt(S->getAsmString())); + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getAsmString()); for (unsigned I = 0, E = S->getNumInputs(); I < E; ++I) { - TRY_TO(TraverseStmt(S->getInputConstraintLiteral(I))); + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getInputConstraintLiteral(I)); } for (unsigned I = 0, E = S->getNumOutputs(); I < E; ++I) { - TRY_TO(TraverseStmt(S->getOutputConstraintLiteral(I))); + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getOutputConstraintLiteral(I)); } for (unsigned I = 0, E = S->getNumClobbers(); I < E; ++I) { - TRY_TO(TraverseStmt(S->getClobberStringLiteral(I))); + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getClobberStringLiteral(I)); } // children() iterates over inputExpr and outputExpr. }) @@ -1977,9 +1944,9 @@ DEF_TRAVERSE_STMT(ObjCForCollectionStmt, {}) DEF_TRAVERSE_STMT(ObjCAutoreleasePoolStmt, {}) DEF_TRAVERSE_STMT(CXXForRangeStmt, { if (!getDerived().shouldVisitImplicitCode()) { - TRY_TO(TraverseStmt(S->getLoopVarStmt())); - TRY_TO(TraverseStmt(S->getRangeInit())); - TRY_TO(TraverseStmt(S->getBody())); + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getLoopVarStmt()); + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getRangeInit()); + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getBody()); // Visit everything else only if shouldVisitImplicitCode(). return true; } @@ -2012,9 +1979,8 @@ DEF_TRAVERSE_STMT(DependentScopeDeclRefExpr, { TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc())); TRY_TO(TraverseDeclarationNameInfo(S->getNameInfo())); if (S->hasExplicitTemplateArgs()) { - TRY_TO(TraverseTemplateArgumentLocsHelper( - S->getExplicitTemplateArgs().getTemplateArgs(), - S->getNumTemplateArgs())); + TRY_TO(TraverseTemplateArgumentLocsHelper(S->getTemplateArgs(), + S->getNumTemplateArgs())); } }) @@ -2055,64 +2021,60 @@ DEF_TRAVERSE_STMT(CXXStaticCastExpr, { TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc())); }) -// InitListExpr is a tricky one, because we want to do all our work on -// the syntactic form of the listexpr, but this method takes the -// semantic form by default. We can't use the macro helper because it -// calls WalkUp*() on the semantic form, before our code can convert -// to the syntactic form. template <typename Derived> -bool RecursiveASTVisitor<Derived>::TraverseInitListExpr(InitListExpr *S) { - InitListExpr *Syn = S->isSemanticForm() ? S->getSyntacticForm() : S; - if (Syn) { - TRY_TO(WalkUpFromInitListExpr(Syn)); +bool RecursiveASTVisitor<Derived>::TraverseSynOrSemInitListExpr( + InitListExpr *S, DataRecursionQueue *Queue) { + if (S) { + TRY_TO(WalkUpFromInitListExpr(S)); // All we need are the default actions. FIXME: use a helper function. - for (Stmt *SubStmt : Syn->children()) { - TRY_TO(TraverseStmt(SubStmt)); - } - } - InitListExpr *Sem = S->isSemanticForm() ? S : S->getSemanticForm(); - if (Sem) { - TRY_TO(WalkUpFromInitListExpr(Sem)); - for (Stmt *SubStmt : Sem->children()) { - TRY_TO(TraverseStmt(SubStmt)); + for (Stmt *SubStmt : S->children()) { + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(SubStmt); } } return true; } +// This method is called once for each pair of syntactic and semantic +// InitListExpr, and it traverses the subtrees defined by the two forms. This +// may cause some of the children to be visited twice, if they appear both in +// the syntactic and the semantic form. +// +// There is no guarantee about which form \p S takes when this method is called. +DEF_TRAVERSE_STMT(InitListExpr, { + TRY_TO(TraverseSynOrSemInitListExpr( + S->isSemanticForm() ? S->getSyntacticForm() : S, Queue)); + TRY_TO(TraverseSynOrSemInitListExpr( + S->isSemanticForm() ? S : S->getSemanticForm(), Queue)); + return true; +}) + // GenericSelectionExpr is a special case because the types and expressions // are interleaved. We also need to watch out for null types (default // generic associations). -template <typename Derived> -bool RecursiveASTVisitor<Derived>::TraverseGenericSelectionExpr( - GenericSelectionExpr *S) { - TRY_TO(WalkUpFromGenericSelectionExpr(S)); +DEF_TRAVERSE_STMT(GenericSelectionExpr, { TRY_TO(TraverseStmt(S->getControllingExpr())); for (unsigned i = 0; i != S->getNumAssocs(); ++i) { if (TypeSourceInfo *TS = S->getAssocTypeSourceInfo(i)) TRY_TO(TraverseTypeLoc(TS->getTypeLoc())); - TRY_TO(TraverseStmt(S->getAssocExpr(i))); + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getAssocExpr(i)); } return true; -} +}) -// PseudoObjectExpr is a special case because of the wierdness with +// PseudoObjectExpr is a special case because of the weirdness with // syntactic expressions and opaque values. -template <typename Derived> -bool -RecursiveASTVisitor<Derived>::TraversePseudoObjectExpr(PseudoObjectExpr *S) { - TRY_TO(WalkUpFromPseudoObjectExpr(S)); - TRY_TO(TraverseStmt(S->getSyntacticForm())); +DEF_TRAVERSE_STMT(PseudoObjectExpr, { + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getSyntacticForm()); for (PseudoObjectExpr::semantics_iterator i = S->semantics_begin(), e = S->semantics_end(); i != e; ++i) { Expr *sub = *i; if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(sub)) sub = OVE->getSourceExpr(); - TRY_TO(TraverseStmt(sub)); + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(sub); } return true; -} +}) DEF_TRAVERSE_STMT(CXXScalarValueInitExpr, { // This is called for code like 'return T()' where T is a built-in @@ -2151,6 +2113,8 @@ DEF_TRAVERSE_STMT(MSPropertyRefExpr, { TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc())); }) +DEF_TRAVERSE_STMT(MSPropertySubscriptExpr, {}) + DEF_TRAVERSE_STMT(CXXUuidofExpr, { // The child-iterator will pick up the arg if it's an expression, // but not if it's a type. @@ -2168,7 +2132,7 @@ DEF_TRAVERSE_STMT(ArrayTypeTraitExpr, { }) DEF_TRAVERSE_STMT(ExpressionTraitExpr, - { TRY_TO(TraverseStmt(S->getQueriedExpression())); }) + { TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getQueriedExpression()); }) DEF_TRAVERSE_STMT(VAArgExpr, { // The child-iterator will pick up the expression argument. @@ -2181,10 +2145,7 @@ DEF_TRAVERSE_STMT(CXXTemporaryObjectExpr, { }) // Walk only the visible parts of lambda expressions. -template <typename Derived> -bool RecursiveASTVisitor<Derived>::TraverseLambdaExpr(LambdaExpr *S) { - TRY_TO(WalkUpFromLambdaExpr(S)); - +DEF_TRAVERSE_STMT(LambdaExpr, { for (LambdaExpr::capture_iterator C = S->explicit_capture_begin(), CEnd = S->explicit_capture_end(); C != CEnd; ++C) { @@ -2213,12 +2174,11 @@ bool RecursiveASTVisitor<Derived>::TraverseLambdaExpr(LambdaExpr *S) { } if (Expr *NE = T->getNoexceptExpr()) - TRY_TO(TraverseStmt(NE)); + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(NE); } - TRY_TO(TraverseLambdaBody(S)); - return true; -} + return TRAVERSE_STMT_BASE(LambdaBody, LambdaExpr, S, Queue); +}) DEF_TRAVERSE_STMT(CXXUnresolvedConstructExpr, { // This is called for code like 'T()', where T is a template argument. @@ -2235,6 +2195,7 @@ DEF_TRAVERSE_STMT(CXXMemberCallExpr, {}) // over the children. DEF_TRAVERSE_STMT(AddrLabelExpr, {}) DEF_TRAVERSE_STMT(ArraySubscriptExpr, {}) +DEF_TRAVERSE_STMT(OMPArraySectionExpr, {}) DEF_TRAVERSE_STMT(BlockExpr, { TRY_TO(TraverseDecl(S->getBlockDecl())); return true; // no child statements to loop through. @@ -2336,6 +2297,34 @@ DEF_TRAVERSE_STMT(MaterializeTemporaryExpr, {}) DEF_TRAVERSE_STMT(CXXFoldExpr, {}) DEF_TRAVERSE_STMT(AtomicExpr, {}) +// For coroutines expressions, traverse either the operand +// as written or the implied calls, depending on what the +// derived class requests. +DEF_TRAVERSE_STMT(CoroutineBodyStmt, { + if (!getDerived().shouldVisitImplicitCode()) { + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getBody()); + return true; + } +}) +DEF_TRAVERSE_STMT(CoreturnStmt, { + if (!getDerived().shouldVisitImplicitCode()) { + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getOperand()); + return true; + } +}) +DEF_TRAVERSE_STMT(CoawaitExpr, { + if (!getDerived().shouldVisitImplicitCode()) { + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getOperand()); + return true; + } +}) +DEF_TRAVERSE_STMT(CoyieldExpr, { + if (!getDerived().shouldVisitImplicitCode()) { + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getOperand()); + return true; + } +}) + // These literals (all of them) do not need any action. DEF_TRAVERSE_STMT(IntegerLiteral, {}) DEF_TRAVERSE_STMT(CharacterLiteral, {}) @@ -2437,9 +2426,21 @@ DEF_TRAVERSE_STMT(OMPAtomicDirective, DEF_TRAVERSE_STMT(OMPTargetDirective, { TRY_TO(TraverseOMPExecutableDirective(S)); }) +DEF_TRAVERSE_STMT(OMPTargetDataDirective, + { TRY_TO(TraverseOMPExecutableDirective(S)); }) + DEF_TRAVERSE_STMT(OMPTeamsDirective, { TRY_TO(TraverseOMPExecutableDirective(S)); }) +DEF_TRAVERSE_STMT(OMPTaskLoopDirective, + { TRY_TO(TraverseOMPExecutableDirective(S)); }) + +DEF_TRAVERSE_STMT(OMPTaskLoopSimdDirective, + { TRY_TO(TraverseOMPExecutableDirective(S)); }) + +DEF_TRAVERSE_STMT(OMPDistributeDirective, + { TRY_TO(TraverseOMPExecutableDirective(S)); }) + // OpenMP clauses. template <typename Derived> bool RecursiveASTVisitor<Derived>::TraverseOMPClause(OMPClause *C) { @@ -2484,6 +2485,12 @@ bool RecursiveASTVisitor<Derived>::VisitOMPSafelenClause(OMPSafelenClause *C) { } template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPSimdlenClause(OMPSimdlenClause *C) { + TRY_TO(TraverseStmt(C->getSimdlen())); + return true; +} + +template <typename Derived> bool RecursiveASTVisitor<Derived>::VisitOMPCollapseClause(OMPCollapseClause *C) { TRY_TO(TraverseStmt(C->getNumForLoops())); @@ -2509,7 +2516,8 @@ RecursiveASTVisitor<Derived>::VisitOMPScheduleClause(OMPScheduleClause *C) { } template <typename Derived> -bool RecursiveASTVisitor<Derived>::VisitOMPOrderedClause(OMPOrderedClause *) { +bool RecursiveASTVisitor<Derived>::VisitOMPOrderedClause(OMPOrderedClause *C) { + TRY_TO(TraverseStmt(C->getNumForLoops())); return true; } @@ -2555,6 +2563,21 @@ bool RecursiveASTVisitor<Derived>::VisitOMPSeqCstClause(OMPSeqCstClause *) { } template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPThreadsClause(OMPThreadsClause *) { + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPSIMDClause(OMPSIMDClause *) { + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPNogroupClause(OMPNogroupClause *) { + return true; +} + +template <typename Derived> template <typename T> bool RecursiveASTVisitor<Derived>::VisitOMPClauseList(T *Node) { for (auto *E : Node->varlists()) { @@ -2615,6 +2638,9 @@ bool RecursiveASTVisitor<Derived>::VisitOMPLinearClause(OMPLinearClause *C) { TRY_TO(TraverseStmt(C->getStep())); TRY_TO(TraverseStmt(C->getCalcStep())); TRY_TO(VisitOMPClauseList(C)); + for (auto *E : C->privates()) { + TRY_TO(TraverseStmt(E)); + } for (auto *E : C->inits()) { TRY_TO(TraverseStmt(E)); } @@ -2671,6 +2697,9 @@ RecursiveASTVisitor<Derived>::VisitOMPReductionClause(OMPReductionClause *C) { TRY_TO(TraverseNestedNameSpecifierLoc(C->getQualifierLoc())); TRY_TO(TraverseDeclarationNameInfo(C->getNameInfo())); TRY_TO(VisitOMPClauseList(C)); + for (auto *E : C->privates()) { + TRY_TO(TraverseStmt(E)); + } for (auto *E : C->lhs_exprs()) { TRY_TO(TraverseStmt(E)); } @@ -2695,6 +2724,59 @@ bool RecursiveASTVisitor<Derived>::VisitOMPDependClause(OMPDependClause *C) { return true; } +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPDeviceClause(OMPDeviceClause *C) { + TRY_TO(TraverseStmt(C->getDevice())); + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPMapClause(OMPMapClause *C) { + TRY_TO(VisitOMPClauseList(C)); + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPNumTeamsClause( + OMPNumTeamsClause *C) { + TRY_TO(TraverseStmt(C->getNumTeams())); + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPThreadLimitClause( + OMPThreadLimitClause *C) { + TRY_TO(TraverseStmt(C->getThreadLimit())); + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPPriorityClause( + OMPPriorityClause *C) { + TRY_TO(TraverseStmt(C->getPriority())); + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPGrainsizeClause( + OMPGrainsizeClause *C) { + TRY_TO(TraverseStmt(C->getGrainsize())); + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPNumTasksClause( + OMPNumTasksClause *C) { + TRY_TO(TraverseStmt(C->getNumTasks())); + return true; +} + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPHintClause(OMPHintClause *C) { + TRY_TO(TraverseStmt(C->getHint())); + return true; +} + // FIXME: look at the following tricky-seeming exprs to see if we // need to recurse on anything. These are ones that have methods // returning decls or qualtypes or nestednamespecifier -- though I'm @@ -2713,6 +2795,8 @@ bool RecursiveASTVisitor<Derived>::VisitOMPDependClause(OMPDependClause *C) { // Every class that has getQualifier. #undef DEF_TRAVERSE_STMT +#undef TRAVERSE_STMT +#undef TRAVERSE_STMT_BASE #undef TRY_TO |