aboutsummaryrefslogtreecommitdiff
path: root/include/clang/AST/RecursiveASTVisitor.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/clang/AST/RecursiveASTVisitor.h')
-rw-r--r--include/clang/AST/RecursiveASTVisitor.h464
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