Expand Up
@@ -132,6 +132,12 @@ namespace clang {
// / instantiations will be visited at the same time as the pattern
// / from which they were produced.
template <typename Derived> class RecursiveASTVisitor {
// / 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
// / not be explicitly specified by derived classes.
typedef SmallVectorImpl<Stmt *> DataRecursionQueue;
public:
// / \brief Return a reference to the derived class.
Derived &getDerived () { return *static_cast <Derived *>(this ); }
Expand All
@@ -148,19 +154,12 @@ template <typename Derived> class RecursiveASTVisitor {
// / 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.
Expand Down
Expand Up
@@ -253,13 +252,14 @@ template <typename Derived> class RecursiveASTVisitor {
// / \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);
bool TraverseSynOrSemInitListExpr (InitListExpr *S,
DataRecursionQueue *Queue = nullptr );
// ---- Methods on Attrs ----
Expand All
@@ -273,9 +273,36 @@ template <typename Derived> class RecursiveASTVisitor {
// ---- Methods on Stmts ----
private:
template <typename T, T X, typename U, U Y>
struct is_same_member_pointer : std::false_type {};
template <typename T, T X>
struct is_same_member_pointer <T, X, T, X> : std::true_type {};
// Traverse the given statement. If the traverse function was not overridden,
// pass on the data recursion queue information.
#define TRAVERSE_STMT_BASE (NAME, CLASS, VAR, QUEUE ) \
(is_same_member_pointer<decltype(&Derived::Traverse##NAME), \
&Derived::Traverse##NAME, \
decltype (&RecursiveASTVisitor::Traverse##NAME), \
&RecursiveASTVisitor::Traverse##NAME>::value \
? 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.
Expand All
@@ -295,9 +322,10 @@ template <typename Derived> class RecursiveASTVisitor {
// 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) { \
Expand All
@@ -314,10 +342,10 @@ template <typename Derived> class RecursiveASTVisitor {
// 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) { \
Expand Down
Expand Up
@@ -443,129 +471,32 @@ template <typename Derived> class RecursiveASTVisitor {
// / \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;
SmallVector<Stmt*, 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 ;
}
Stmt *CurrS = Queue.pop_back_val ();
if (job.StmtIt != CurrS->child_end ())
Queue.push_back (*job.StmtIt );
else
Queue.pop_back ();
continue ;
}
Queue.pop_back ();
TRY_TO (TraverseStmt (CurrS));
size_t N = Queue.size ();
TRY_TO (dataTraverseNode (CurrS, &Queue));
// Process new children in the order they were added.
std::reverse (Queue.begin () + N, Queue.end ());
}
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));
if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(S)) {
switch (BinOp->getOpcode ()) {
#define OPERATOR (NAME ) \
case BO_##NAME: \
DISPATCH_WALK (Bin##NAME, BinaryOperator, S);
BINOP_LIST ()
#undef OPERATOR
#define OPERATOR (NAME ) \
case BO_##NAME##Assign: \
DISPATCH_WALK (Bin##NAME##Assign, CompoundAssignOperator, S);
CAO_LIST ()
#undef OPERATOR
}
} else if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(S)) {
switch (UnOp->getOpcode ()) {
#define OPERATOR (NAME ) \
case UO_##NAME: \
DISPATCH_WALK (Unary##NAME, UnaryOperator, S);
UNARYOP_LIST ()
#undef OPERATOR
}
}
// 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_WALK (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))
template <typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseStmt (Stmt *S) {
if (!S)
return true ;
#define DISPATCH_STMT (NAME, CLASS, VAR ) DISPATCH(NAME, CLASS, VAR)
if (getDerived ().shouldUseDataRecursionFor (S))
return dataTraverse (S);
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
Expand Down
Expand Up
@@ -616,6 +547,30 @@ bool RecursiveASTVisitor<Derived>::TraverseStmt(Stmt *S) {
#undef DISPATCH_STMT
template <typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseStmt (Stmt *S,
DataRecursionQueue *Queue) {
if (!S)
return true ;
// If TraverseStmt was overridden (and called the base class version), don't
// do any data recursion; it would be observable.
if (!is_same_member_pointer<decltype (&Derived::TraverseStmt),
&Derived::TraverseStmt,
decltype (&RecursiveASTVisitor::TraverseStmt),
&RecursiveASTVisitor::TraverseStmt>::value)
return dataTraverseNode (S, nullptr );
if (!Queue)
return dataTraverse (S);
Queue->push_back (S);
return true ;
}
#define DISPATCH (NAME, CLASS, VAR ) \
return getDerived ().Traverse ##NAME (static_cast <CLASS *>(VAR))
template <typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseType (QualType T) {
if (T.isNull ())
Expand Down
Expand Up
@@ -870,8 +825,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 ;
}
Expand Down
Expand Up
@@ -1917,25 +1873,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.
})
Expand Down
Expand Up
@@ -1988,9 +1945,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 ;
}
Expand Down
Expand Up
@@ -2067,12 +2024,13 @@ DEF_TRAVERSE_STMT(CXXStaticCastExpr, {
})
template <typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseSynOrSemInitListExpr (InitListExpr *S) {
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 : S->children ()) {
TRY_TO ( TraverseStmt ( SubStmt) );
TRY_TO_TRAVERSE_OR_ENQUEUE_STMT ( SubStmt);
}
}
return true ;
Expand All
@@ -2084,48 +2042,41 @@ bool RecursiveASTVisitor<Derived>::TraverseSynOrSemInitListExpr(InitListExpr *S)
// the syntactic and the semantic form.
//
// There is no guarantee about which form \p S takes when this method is called.
template <typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseInitListExpr (InitListExpr *S) {
DEF_TRAVERSE_STMT (InitListExpr, {
TRY_TO (TraverseSynOrSemInitListExpr (
S->isSemanticForm () ? S->getSyntacticForm () : S));
S->isSemanticForm () ? S->getSyntacticForm () : S, Queue ));
TRY_TO (TraverseSynOrSemInitListExpr (
S->isSemanticForm () ? S : S->getSemanticForm ()));
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
Expand Down
Expand Up
@@ -2181,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.
Expand All
@@ -2194,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) {
Expand Down
Expand Up
@@ -2226,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.
Expand Down
Expand Up
@@ -2355,25 +2302,25 @@ DEF_TRAVERSE_STMT(AtomicExpr, {})
// derived class requests.
DEF_TRAVERSE_STMT (CoroutineBodyStmt, {
if (!getDerived ().shouldVisitImplicitCode ()) {
TRY_TO ( TraverseStmt ( S->getBody () ));
TRY_TO_TRAVERSE_OR_ENQUEUE_STMT ( S->getBody ());
return true ;
}
})
DEF_TRAVERSE_STMT (CoreturnStmt, {
if (!getDerived ().shouldVisitImplicitCode ()) {
TRY_TO ( TraverseStmt ( S->getOperand () ));
TRY_TO_TRAVERSE_OR_ENQUEUE_STMT ( S->getOperand ());
return true ;
}
})
DEF_TRAVERSE_STMT (CoawaitExpr, {
if (!getDerived ().shouldVisitImplicitCode ()) {
TRY_TO ( TraverseStmt ( S->getOperand () ));
TRY_TO_TRAVERSE_OR_ENQUEUE_STMT ( S->getOperand ());
return true ;
}
})
DEF_TRAVERSE_STMT (CoyieldExpr, {
if (!getDerived ().shouldVisitImplicitCode ()) {
TRY_TO ( TraverseStmt ( S->getOperand () ));
TRY_TO_TRAVERSE_OR_ENQUEUE_STMT ( S->getOperand ());
return true ;
}
})
Expand Down
Expand Up
@@ -2793,6 +2740,8 @@ bool RecursiveASTVisitor<Derived>::VisitOMPMapClause(OMPMapClause *C) {
// Every class that has getQualifier.
#undef DEF_TRAVERSE_STMT
#undef TRAVERSE_STMT
#undef TRAVERSE_STMT_BASE
#undef TRY_TO
Expand Down