Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(959)

Unified Diff: include/clang/AST/RecursiveASTVisitor.h

Issue 1607042: change RecursiveASTVisitor to the new design and improve coverage. Base URL: http://llvm.org/svn/llvm-project/cfe/trunk/
Patch Set: addresses Doug and Chandler's comments Created 14 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | lib/Frontend/BoostConAction.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: include/clang/AST/RecursiveASTVisitor.h
===================================================================
--- include/clang/AST/RecursiveASTVisitor.h (revision 105643)
+++ include/clang/AST/RecursiveASTVisitor.h (working copy)
@@ -32,21 +32,61 @@
namespace clang {
-#define DISPATCH(NAME, CLASS, Var) \
-return getDerived().Visit ## NAME(static_cast<CLASS*>(Var))
+// A helper macro to implement short-circuiting when recursing. It
+// invokes CALL_EXPR, which must be a method call, on the derived
+// object (s.t. a user of RecursiveASTVisitor can override the method
+// in CALL_EXPR).
+#define TRY_TO(CALL_EXPR) \
+ do { if (getDerived().CALL_EXPR) return true; } while (0)
-// We use preprocessor meta-programming to generate the Visit*()
-// methods for all subclasses of Stmt, Decl, and Type. Some of the
-// generated definitions, however, need to be customized. The
-// meta-programming technique we use doesn't let us select which
-// methods to generate. Therefore we have to generate ALL of them in
-// a helper class RecursiveASTVisitorImpl, and override the ones we
-// don't like in a child class RecursiveASTVisitor (C++ doesn't allow
-// overriding a method in the same class).
-//
-// Do not use this class directly - use RecursiveASTVisitor instead.
+/// \brief A class that does preorder depth-first traversal on the
+/// entire Clang AST and visits each node.
+///
+/// This class performs three distinct tasks:
+/// 1. traverse the AST (i.e. go to each node);
+/// 2. at a given node, walk up the class hierarchy, starting from
+/// the node's dynamic type, until the top-most class (e.g. Stmt,
+/// Decl, or Type) is reached.
+/// 3. given a (node, class) combination, where 'class' is some base
+/// class of the dynamic type of 'node', call a user-overridable
+/// function to actually visit the node.
+///
+/// These tasks are done by three groups of methods, respectively:
+/// 1. TraverseDecl(Decl* x) does task #1. It is the entry point
+/// for traversing an AST rooted at x. This method simply
+/// dispatches (i.e. forwards) to TraverseFoo(Foo* x) where Foo
+/// is the dynamic type of *x, which calls WalkUpFromFoo(x) and
+/// then recursively visits the child nodes of x.
+/// TraverseStmt(Stmt* x) and TraverseType(QualType x) work
+/// similarly.
+/// 2. WalkUpFromFoo(Foo* x) does task #2. It does not try to visit
+/// any child node of x. Instead, it first calls WalkUpFromBar(x)
+/// where Bar is the direct parent class of Foo (unless Foo has
+/// no parent), and then calls VisitFoo(x) (see the next list item).
+/// 3. VisitFoo(Foo* x) does task #3.
+///
+/// These three method groups are tiered (Traverse* > WalkUpFrom* >
+/// Visit*). A method (e.g. Traverse*) may call methods from the same
+/// tier (e.g. other Traverse*) or one-tier lower (e.g. WalkUpFrom*).
+/// It may not call methods from a higher tier.
+///
+/// This scheme guarantees that all Visit*() calls for the same AST
+/// node are grouped together. In other words, Visit*() methods for
+/// different nodes are never interleaved.
+///
+/// Clients of this visitor should subclass the visitor (providing
+/// themselves as the template argument, using the curiously recurring
+/// template pattern) and override any of the Traverse*, WalkUpFrom*,
+/// and Visit* methods for declarations, types, statements,
+/// expressions, or other AST nodes where the visitor should customize
+/// behavior. Most users only need to override Visit*. Advanced
+/// users may override Traverse* and WalkUpFrom* to implement custom
+/// traversal strategies. Returning true from one of these overridden
+/// functions will abort the entire traversal.
+///
+/// FIXME: reverse the meaning of the bool return value.
template<typename Derived>
-class RecursiveASTVisitorImpl {
+class RecursiveASTVisitor {
public:
/// \brief Return a reference to the derived class.
Derived &getDerived() { return *static_cast<Derived*>(this); }
@@ -57,7 +97,7 @@
///
/// \returns true if the visitation was terminated early, false
/// otherwise (including when the argument is NULL).
- bool Visit(Stmt *S);
+ bool TraverseStmt(Stmt *S);
/// \brief Recursively visit a type, by dispatching to
/// Visit*Type() based on the argument's getTypeClass() property.
@@ -65,7 +105,7 @@
///
/// \returns true if the visitation was terminated early, false
/// otherwise (including when the argument is a Null type).
- bool Visit(QualType T);
+ bool TraverseType(QualType T);
/// \brief Recursively visit a declaration, by dispatching to
/// Visit*Decl() based on the argument's dynamic type. This is
@@ -73,40 +113,100 @@
///
/// \returns true if the visitation was terminated early, false
/// otherwise (including when the argument is NULL).
- bool Visit(Decl *D);
+ bool TraverseDecl(Decl *D);
/// \brief Recursively visit a C++ nested-name-specifier.
///
/// \returns true if the visitation was terminated early, false otherwise.
- bool VisitNestedNameSpecifier(NestedNameSpecifier *NNS);
+ bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS);
- /// \brief Recursively visit a template name.
+ /// \brief Recursively visit a template name and dispatch to the
+ /// appropriate method.
///
/// \returns true if the visitation was terminated early, false otherwise.
- bool VisitTemplateName(TemplateName Template);
+ bool TraverseTemplateName(TemplateName Template);
- /// \brief Recursively visit a template argument.
+ /// \brief Recursively visit a template argument and dispatch to the
+ /// appropriate method for the argument type.
///
/// \returns true if the visitation was terminated early, false otherwise.
- bool VisitTemplateArgument(const TemplateArgument &Arg);
+ // FIXME: take a TemplateArgumentLoc instead.
+ bool TraverseTemplateArgument(const TemplateArgument &Arg);
/// \brief Recursively visit a set of template arguments.
+ /// This can be overridden by a subclass, but it's not expected that
+ /// will be needed -- this visitor always dispatches to another.
///
/// \returns true if the visitation was terminated early, false otherwise.
- bool VisitTemplateArguments(const TemplateArgument *Args, unsigned NumArgs);
+ // FIXME: take a TemplateArgumentLoc* (or TemplateArgumentListInfo) instead.
+ bool TraverseTemplateArguments(const TemplateArgument *Args, unsigned NumArgs);
- // If the implementation chooses not to implement a certain visit method, fall
- // back on VisitExpr or whatever else is the superclass.
-#define STMT(CLASS, PARENT) \
-bool Visit ## CLASS(CLASS *S) { DISPATCH(PARENT, PARENT, S); }
+ // ---- Methods on Stmts ----
+
+ // Declare Traverse*() for all concrete Stmt classes.
+#define ABSTRACT_STMT(STMT)
+#define STMT(CLASS, PARENT) \
+ bool Traverse##CLASS(CLASS *S);
#include "clang/AST/StmtNodes.inc"
+ // The above header #undefs ABSTRACT_STMT and STMT upon exit.
- // If the implementation doesn't implement binary operator methods, fall back
- // on VisitBinaryOperator.
-#define BINOP_FALLBACK(NAME) \
-bool VisitBin ## NAME(BinaryOperator *S) { \
-DISPATCH(BinaryOperator, BinaryOperator, S); \
-}
+ // Define WalkUpFrom*() and empty Visit*() for all Stmt classes.
+ bool WalkUpFromStmt(Stmt *S) { return getDerived().VisitStmt(S); }
+ bool VisitStmt(Stmt *S) { return false; }
+#define STMT(CLASS, PARENT) \
+ bool WalkUpFrom##CLASS(CLASS *S) { \
+ TRY_TO(WalkUpFrom##PARENT(S)); \
+ TRY_TO(Visit##CLASS(S)); \
+ return false; \
+ } \
+ bool Visit##CLASS(CLASS *S) { return false; }
+#include "clang/AST/StmtNodes.inc"
+
+ // Define Traverse*(), WalkUpFrom*(), and Visit*() for unary
+ // operator methods. Unary operators are not classes in themselves
+ // (they're all opcodes in UnaryOperator) but do have visitors.
+#define UNARYOP_FALLBACK(NAME) \
+ bool TraverseUnary##NAME(UnaryOperator *S) { \
+ TRY_TO(WalkUpFromUnary##NAME(S)); \
+ TRY_TO(TraverseStmt(S->getSubExpr())); \
+ return false; \
+ } \
+ bool WalkUpFromUnary##NAME(UnaryOperator *S) { \
+ TRY_TO(WalkUpFromUnaryOperator(S)); \
+ TRY_TO(VisitUnary##NAME(S)); \
+ return false; \
+ } \
+ bool VisitUnary##NAME(UnaryOperator *S) { return false; }
+
+ UNARYOP_FALLBACK(PostInc) UNARYOP_FALLBACK(PostDec)
+ UNARYOP_FALLBACK(PreInc) UNARYOP_FALLBACK(PreDec)
+ UNARYOP_FALLBACK(AddrOf) UNARYOP_FALLBACK(Deref)
+
+ UNARYOP_FALLBACK(Plus) UNARYOP_FALLBACK(Minus)
+ UNARYOP_FALLBACK(Not) UNARYOP_FALLBACK(LNot)
+ UNARYOP_FALLBACK(Real) UNARYOP_FALLBACK(Imag)
+ UNARYOP_FALLBACK(Extension) UNARYOP_FALLBACK(OffsetOf)
+#undef UNARYOP_FALLBACK
+
+ // Define Traverse*(), WalkUpFrom*(), and Visit*() for binary
+ // 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) { \
+ TRY_TO(WalkUpFromBin##NAME(S)); \
+ TRY_TO(TraverseStmt(S->getLHS())); \
+ TRY_TO(TraverseStmt(S->getRHS())); \
+ return false; \
+ } \
+ bool WalkUpFromBin##NAME(BINOP_TYPE *S) { \
+ TRY_TO(WalkUpFrom##BINOP_TYPE(S)); \
+ TRY_TO(VisitBin##NAME(S)); \
+ return false; \
+ } \
+ bool VisitBin##NAME(BINOP_TYPE *S) { return false; }
+
+#define BINOP_FALLBACK(NAME) GENERAL_BINOP_FALLBACK(NAME, BinaryOperator)
+
BINOP_FALLBACK(PtrMemD) BINOP_FALLBACK(PtrMemI)
BINOP_FALLBACK(Mul) BINOP_FALLBACK(Div) BINOP_FALLBACK(Rem)
BINOP_FALLBACK(Add) BINOP_FALLBACK(Sub) BINOP_FALLBACK(Shl)
@@ -119,75 +219,83 @@
BINOP_FALLBACK(Assign)
BINOP_FALLBACK(Comma)
+
#undef BINOP_FALLBACK
- // If the implementation doesn't implement compound assignment operator
- // methods, fall back on VisitCompoundAssignOperator.
-#define CAO_FALLBACK(NAME) \
-bool VisitBin ## NAME(CompoundAssignOperator *S) { \
-DISPATCH(CompoundAssignOperator, CompoundAssignOperator, S); \
-}
+ // Define Traverse*(), WalkUpFrom*(), and Visit*() for compound
+ // assignment methods. Compound assignment operators are not
+ // classes in themselves (they're all opcodes in
+ // CompoundAssignOperator) but do have visitors.
+#define CAO_FALLBACK(NAME) GENERAL_BINOP_FALLBACK(NAME, CompoundAssignOperator)
+
CAO_FALLBACK(MulAssign) CAO_FALLBACK(DivAssign) CAO_FALLBACK(RemAssign)
CAO_FALLBACK(AddAssign) CAO_FALLBACK(SubAssign) CAO_FALLBACK(ShlAssign)
CAO_FALLBACK(ShrAssign) CAO_FALLBACK(AndAssign) CAO_FALLBACK(OrAssign)
CAO_FALLBACK(XorAssign)
+
#undef CAO_FALLBACK
+#undef GENERAL_BINOP_FALLBACK
- // If the implementation doesn't implement unary operator methods, fall back
- // on VisitUnaryOperator.
-#define UNARYOP_FALLBACK(NAME) \
-bool VisitUnary ## NAME(UnaryOperator *S) { \
-DISPATCH(UnaryOperator, UnaryOperator, S); \
-}
- UNARYOP_FALLBACK(PostInc) UNARYOP_FALLBACK(PostDec)
- UNARYOP_FALLBACK(PreInc) UNARYOP_FALLBACK(PreDec)
- UNARYOP_FALLBACK(AddrOf) UNARYOP_FALLBACK(Deref)
+ // ---- Methods on Types ----
+ // FIXME: revamp to take TypeLoc's rather than Types.
- UNARYOP_FALLBACK(Plus) UNARYOP_FALLBACK(Minus)
- UNARYOP_FALLBACK(Not) UNARYOP_FALLBACK(LNot)
- UNARYOP_FALLBACK(Real) UNARYOP_FALLBACK(Imag)
- UNARYOP_FALLBACK(Extension) UNARYOP_FALLBACK(OffsetOf)
-#undef UNARYOP_FALLBACK
+ // Declare Traverse*() for all concrete Type classes.
+#define ABSTRACT_TYPE(CLASS, BASE)
+#define TYPE(CLASS, BASE) \
+ bool Traverse##CLASS##Type(CLASS##Type *T);
+#include "clang/AST/TypeNodes.def"
+ // The above header #undefs ABSTRACT_TYPE and TYPE upon exit.
- /// \brief Basis for statement and expression visitation, which
- /// visits all of the substatements and subexpressions.
- ///
- /// The relation between Visit(Stmt *S) and this method is that
- /// the former dispatches to Visit*() based on S's dynamic type,
- /// which forwards the call up the inheritance chain until
- /// reaching VisitStmt(), which then calls Visit() on each
- /// substatement/subexpression.
- bool VisitStmt(Stmt *S);
-
- /// \brief Basis for type visitation, which by default does nothing.
- ///
- /// The relation between Visit(QualType T) and this method is
- /// that the former dispatches to Visit*Type(), which forwards the
- /// call up the inheritance chain until reaching VisitType().
- bool VisitType(Type *T);
-
-#define TYPE(Class, Base) \
- bool Visit##Class##Type(Class##Type *T);
+ // Define WalkUpFrom*() and empty Visit*() for all Type classes.
+ bool WalkUpFromType(Type *T) { return getDerived().VisitType(T); }
+ bool VisitType(Type *T) { return false; }
+#define TYPE(CLASS, BASE) \
+ bool WalkUpFrom##CLASS##Type(CLASS##Type *T) { \
+ TRY_TO(WalkUpFrom##BASE(T)); \
+ TRY_TO(Visit##CLASS##Type(T)); \
+ return false; \
+ } \
+ bool Visit##CLASS##Type(CLASS##Type *T) { return false; }
#include "clang/AST/TypeNodes.def"
- /// \brief Basis for declaration and definition visitation, which
- /// visits all of the subnodes.
- ///
- /// The relation between Visit(Decl *) and this method is that the
- /// former dispatches to Visit*Decl(), which forwards the call up
- /// the inheritance chain until reaching VisitDecl().
- bool VisitDecl(Decl *D);
+ // ---- Methods on Decls ----
-#define DECL(CLASS, BASE) \
- bool Visit##CLASS##Decl(CLASS##Decl *D) { \
- return getDerived().Visit##BASE(D); \
- }
+ // Declare Traverse*() for all concrete Decl classes.
+#define ABSTRACT_DECL(DECL)
+#define DECL(CLASS, BASE) \
+ bool Traverse##CLASS##Decl(CLASS##Decl *D);
#include "clang/AST/DeclNodes.inc"
+ // The above header #undefs ABSTRACT_DECL and DECL upon exit.
+ // Define WalkUpFrom*() and empty Visit*() for all Decl classes.
+ bool WalkUpFromDecl(Decl *D) { return getDerived().VisitDecl(D); }
+ bool VisitDecl(Decl *D) { return false; }
+#define DECL(CLASS, BASE) \
+ bool WalkUpFrom##CLASS##Decl(CLASS##Decl *D) { \
+ TRY_TO(WalkUpFrom##BASE(D)); \
+ TRY_TO(Visit##CLASS##Decl(D)); \
+ return false; \
+ } \
+ bool Visit##CLASS##Decl(CLASS##Decl *D) { return false; }
+#include "clang/AST/DeclNodes.inc"
+
+private:
+ // These are helper methods used by more than one Traverse* method.
+ bool TraverseTemplateParameterListHelper(TemplateParameterList *TPL);
+ bool TraverseTemplateArgumentLocsHelper(const TemplateArgumentLoc *TAL,
+ unsigned Count);
+ bool TraverseRecordHelper(RecordDecl *D);
+ bool TraverseCXXRecordHelper(CXXRecordDecl *D);
+ bool TraverseDeclaratorHelper(DeclaratorDecl *D);
+ bool TraverseFunctionHelper(FunctionDecl *D);
+ bool TraverseVarHelper(VarDecl *D);
};
+#define DISPATCH(NAME, CLASS, VAR) \
+ return getDerived().Traverse##NAME(static_cast<CLASS*>(VAR))
+
template<typename Derived>
-bool RecursiveASTVisitorImpl<Derived>::Visit(Stmt *S) {
+bool RecursiveASTVisitor<Derived>::TraverseStmt(Stmt *S) {
if (!S)
return false;
@@ -260,12 +368,12 @@
}
}
- // Top switch stmt: dispatch to VisitFooStmt for each FooStmt.
+ // 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(CLASS, CLASS, S);
+ case Stmt::CLASS##Class: DISPATCH(CLASS, CLASS, S);
#include "clang/AST/StmtNodes.inc"
}
@@ -273,14 +381,14 @@
}
template<typename Derived>
-bool RecursiveASTVisitorImpl<Derived>::Visit(QualType T) {
+bool RecursiveASTVisitor<Derived>::TraverseType(QualType T) {
if (T.isNull())
return false;
switch (T->getTypeClass()) {
-#define ABSTRACT_TYPE(Class, Base)
-#define TYPE(Class, Base) \
- case Type::Class: DISPATCH(Class##Type, Class##Type, T.getTypePtr());
+#define ABSTRACT_TYPE(CLASS, BASE)
+#define TYPE(CLASS, BASE) \
+ case Type::CLASS: DISPATCH(CLASS##Type, CLASS##Type, T.getTypePtr());
#include "clang/AST/TypeNodes.def"
}
@@ -288,25 +396,30 @@
}
template<typename Derived>
-bool RecursiveASTVisitorImpl<Derived>::Visit(Decl *D) {
+bool RecursiveASTVisitor<Derived>::TraverseDecl(Decl *D) {
if (!D)
return false;
switch (D->getKind()) {
#define ABSTRACT_DECL(DECL)
#define DECL(CLASS, BASE) \
- case Decl::CLASS: DISPATCH(CLASS##Decl, CLASS##Decl, D);
+ case Decl::CLASS: DISPATCH(CLASS##Decl, CLASS##Decl, D);
#include "clang/AST/DeclNodes.inc"
}
return false;
}
+#undef DISPATCH
+
template<typename Derived>
-bool RecursiveASTVisitorImpl<Derived>::VisitNestedNameSpecifier(
+bool RecursiveASTVisitor<Derived>::TraverseNestedNameSpecifier(
NestedNameSpecifier *NNS) {
+ if (!NNS)
+ return false;
+
if (NNS->getPrefix() &&
- getDerived().VisitNestedNameSpecifier(NNS->getPrefix()))
+ getDerived().TraverseNestedNameSpecifier(NNS->getPrefix()))
return true;
switch (NNS->getKind()) {
@@ -317,26 +430,26 @@
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate:
- return Visit(QualType(NNS->getAsType(), 0));
+ return getDerived().TraverseType(QualType(NNS->getAsType(), 0));
}
return false;
}
template<typename Derived>
-bool RecursiveASTVisitorImpl<Derived>::VisitTemplateName(TemplateName Template) {
+bool RecursiveASTVisitor<Derived>::TraverseTemplateName(TemplateName Template) {
if (DependentTemplateName *DTN = Template.getAsDependentTemplateName())
return DTN->getQualifier() &&
- getDerived().VisitNestedNameSpecifier(DTN->getQualifier());
+ getDerived().TraverseNestedNameSpecifier(DTN->getQualifier());
if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
- return getDerived().VisitNestedNameSpecifier(QTN->getQualifier());
+ return getDerived().TraverseNestedNameSpecifier(QTN->getQualifier());
return false;
}
template<typename Derived>
-bool RecursiveASTVisitorImpl<Derived>::VisitTemplateArgument(
+bool RecursiveASTVisitor<Derived>::TraverseTemplateArgument(
const TemplateArgument &Arg) {
switch (Arg.getKind()) {
case TemplateArgument::Null:
@@ -345,424 +458,829 @@
return false;
case TemplateArgument::Type:
- return Visit(Arg.getAsType());
+ return getDerived().TraverseType(Arg.getAsType());
case TemplateArgument::Template:
- return getDerived().VisitTemplateName(Arg.getAsTemplate());
+ return getDerived().TraverseTemplateName(Arg.getAsTemplate());
case TemplateArgument::Expression:
- return getDerived().Visit(Arg.getAsExpr());
+ return getDerived().TraverseStmt(Arg.getAsExpr());
case TemplateArgument::Pack:
- return getDerived().VisitTemplateArguments(Arg.pack_begin(),
- Arg.pack_size());
+ return getDerived().TraverseTemplateArguments(Arg.pack_begin(),
+ Arg.pack_size());
}
return false;
}
template<typename Derived>
-bool RecursiveASTVisitorImpl<Derived>::VisitTemplateArguments(
+bool RecursiveASTVisitor<Derived>::TraverseTemplateArguments(
const TemplateArgument *Args,
unsigned NumArgs) {
- for (unsigned I = 0; I != NumArgs; ++I)
- if (getDerived().VisitTemplateArgument(Args[I]))
- return true;
+ for (unsigned I = 0; I != NumArgs; ++I) {
+ TRY_TO(TraverseTemplateArgument(Args[I]));
+ }
return false;
}
-template<typename Derived>
-bool RecursiveASTVisitorImpl<Derived>::VisitStmt(Stmt *Node) {
- for (Stmt::child_iterator C = Node->child_begin(), CEnd = Node->child_end();
- C != CEnd; ++C) {
- if (Visit(*C))
- return true;
+// ----------------- Type traversal -----------------
+
+// This macro makes available a variable T, the passed-in type.
+#define DEF_TRAVERSE_TYPE(TYPE, CODE) \
+ template<typename Derived> \
+ bool RecursiveASTVisitor<Derived>::Traverse##TYPE (TYPE *T) { \
+ TRY_TO(WalkUpFrom##TYPE (T)); \
+ { CODE; } \
+ return false; \
}
- return false;
-}
+DEF_TRAVERSE_TYPE(BuiltinType, { })
-template<typename Derived>
-bool RecursiveASTVisitorImpl<Derived>::VisitType(Type *T) {
- return false;
-}
+DEF_TRAVERSE_TYPE(ComplexType, {
+ TRY_TO(TraverseType(T->getElementType()));
+ })
-template<typename Derived>
-bool RecursiveASTVisitorImpl<Derived>::VisitBuiltinType(BuiltinType *T) {
- return getDerived().VisitType(T);
-}
+DEF_TRAVERSE_TYPE(PointerType, {
+ TRY_TO(TraverseType(T->getPointeeType()));
+ })
-template<typename Derived>
-bool RecursiveASTVisitorImpl<Derived>::VisitComplexType(ComplexType *T) {
- if (Visit(T->getElementType()))
- return true;
+DEF_TRAVERSE_TYPE(BlockPointerType, {
+ TRY_TO(TraverseType(T->getPointeeType()));
+ })
- return getDerived().VisitType(T);
-}
+DEF_TRAVERSE_TYPE(LValueReferenceType, {
+ TRY_TO(TraverseType(T->getPointeeType()));
+ })
-template<typename Derived>
-bool RecursiveASTVisitorImpl<Derived>::VisitPointerType(PointerType *T) {
- if (Visit(T->getPointeeType()))
- return true;
+DEF_TRAVERSE_TYPE(RValueReferenceType, {
+ TRY_TO(TraverseType(T->getPointeeType()));
+ })
- return getDerived().VisitType(T);
-}
+DEF_TRAVERSE_TYPE(MemberPointerType, {
+ TRY_TO(TraverseType(QualType(T->getClass(), 0)));
+ TRY_TO(TraverseType(T->getPointeeType()));
+ })
-template<typename Derived>
-bool RecursiveASTVisitorImpl<Derived>::VisitBlockPointerType(
- BlockPointerType *T) {
- if (Visit(T->getPointeeType()))
- return true;
+DEF_TRAVERSE_TYPE(ConstantArrayType, {
+ TRY_TO(TraverseType(T->getElementType()));
+ })
- return getDerived().VisitType(T);
-}
+DEF_TRAVERSE_TYPE(IncompleteArrayType, {
+ TRY_TO(TraverseType(T->getElementType()));
+ })
-template<typename Derived>
-bool RecursiveASTVisitorImpl<Derived>::VisitReferenceType(ReferenceType *T) {
- if (Visit(T->getPointeeType()))
- return true;
+DEF_TRAVERSE_TYPE(VariableArrayType, {
+ TRY_TO(TraverseType(T->getElementType()));
+ TRY_TO(TraverseStmt(T->getSizeExpr()));
+ })
- return getDerived().VisitType(T);
-}
+DEF_TRAVERSE_TYPE(DependentSizedArrayType, {
+ TRY_TO(TraverseType(T->getElementType()));
+ if (T->getSizeExpr())
+ TRY_TO(TraverseStmt(T->getSizeExpr()));
+ })
-template<typename Derived>
-bool RecursiveASTVisitorImpl<Derived>::VisitLValueReferenceType(
- LValueReferenceType *T) {
- return getDerived().VisitReferenceType(T);
-}
+DEF_TRAVERSE_TYPE(DependentSizedExtVectorType, {
+ if (T->getSizeExpr())
+ TRY_TO(TraverseStmt(T->getSizeExpr()));
+ TRY_TO(TraverseType(T->getElementType()));
+ })
-template<typename Derived>
-bool RecursiveASTVisitorImpl<Derived>::VisitRValueReferenceType(
- RValueReferenceType *T) {
- return getDerived().VisitReferenceType(T);
-}
+DEF_TRAVERSE_TYPE(VectorType, {
+ TRY_TO(TraverseType(T->getElementType()));
+ })
-template<typename Derived>
-bool RecursiveASTVisitorImpl<Derived>::VisitMemberPointerType(
- MemberPointerType *T) {
- if (Visit(QualType(T->getClass(), 0)) || Visit(T->getPointeeType()))
- return true;
+DEF_TRAVERSE_TYPE(ExtVectorType, { })
- return getDerived().VisitType(T);
-}
+DEF_TRAVERSE_TYPE(FunctionNoProtoType, {
+ TRY_TO(TraverseType(T->getResultType()));
+ })
-template<typename Derived>
-bool RecursiveASTVisitorImpl<Derived>::VisitArrayType(ArrayType *T) {
- if (Visit(T->getElementType()))
- return true;
+DEF_TRAVERSE_TYPE(FunctionProtoType, {
+ TRY_TO(TraverseType(T->getResultType()));
- return getDerived().VisitType(T);
-}
+ for (FunctionProtoType::arg_type_iterator A = T->arg_type_begin(),
+ AEnd = T->arg_type_end();
+ A != AEnd; ++A) {
+ TRY_TO(TraverseType(*A));
+ }
-template<typename Derived>
-bool RecursiveASTVisitorImpl<Derived>::VisitConstantArrayType(
- ConstantArrayType *T) {
- return getDerived().VisitArrayType(T);
-}
+ for (FunctionProtoType::exception_iterator E = T->exception_begin(),
+ EEnd = T->exception_end();
+ E != EEnd; ++E) {
+ TRY_TO(TraverseType(*E));
+ }
+ })
-template<typename Derived>
-bool RecursiveASTVisitorImpl<Derived>::VisitIncompleteArrayType(
- IncompleteArrayType *T) {
- return getDerived().VisitArrayType(T);
-}
+DEF_TRAVERSE_TYPE(UnresolvedUsingType, { })
+DEF_TRAVERSE_TYPE(TypedefType, { })
-template<typename Derived>
-bool RecursiveASTVisitorImpl<Derived>::VisitVariableArrayType(
- VariableArrayType *T) {
- if (Visit(T->getSizeExpr()))
- return true;
+DEF_TRAVERSE_TYPE(TypeOfExprType, {
+ TRY_TO(TraverseStmt(T->getUnderlyingExpr()));
+ })
- return getDerived().VisitArrayType(T);
-}
+DEF_TRAVERSE_TYPE(TypeOfType, {
+ TRY_TO(TraverseType(T->getUnderlyingType()));
+ })
-template<typename Derived>
-bool RecursiveASTVisitorImpl<Derived>::VisitDependentSizedArrayType(
- DependentSizedArrayType *T) {
- if (T->getSizeExpr() && Visit(T->getSizeExpr()))
- return true;
+DEF_TRAVERSE_TYPE(DecltypeType, {
+ TRY_TO(TraverseStmt(T->getUnderlyingExpr()));
+ })
- return getDerived().VisitArrayType(T);
-}
+DEF_TRAVERSE_TYPE(RecordType, { })
+DEF_TRAVERSE_TYPE(EnumType, { })
+DEF_TRAVERSE_TYPE(TemplateTypeParmType, { })
+DEF_TRAVERSE_TYPE(SubstTemplateTypeParmType, { })
-template<typename Derived>
-bool RecursiveASTVisitorImpl<Derived>::VisitDependentSizedExtVectorType(
- DependentSizedExtVectorType *T) {
- if ((T->getSizeExpr() && Visit(T->getSizeExpr())) ||
- Visit(T->getElementType()))
- return true;
+DEF_TRAVERSE_TYPE(TemplateSpecializationType, {
+ TRY_TO(TraverseTemplateName(T->getTemplateName()));
+ TRY_TO(TraverseTemplateArguments(T->getArgs(), T->getNumArgs()));
+ })
- return getDerived().VisitType(T);
-}
+DEF_TRAVERSE_TYPE(InjectedClassNameType, { })
-template<typename Derived>
-bool RecursiveASTVisitorImpl<Derived>::VisitVectorType(VectorType *T) {
- if (Visit(T->getElementType()))
- return true;
+DEF_TRAVERSE_TYPE(ElaboratedType, {
+ if (T->getQualifier()) {
+ TRY_TO(TraverseNestedNameSpecifier(T->getQualifier()));
+ }
+ TRY_TO(TraverseType(T->getNamedType()));
+ })
- return getDerived().VisitType(T);
-}
+DEF_TRAVERSE_TYPE(DependentNameType, {
+ if (T->getQualifier()) {
+ TRY_TO(TraverseNestedNameSpecifier(T->getQualifier()));
+ }
-template<typename Derived>
-bool RecursiveASTVisitorImpl<Derived>::VisitExtVectorType(ExtVectorType *T) {
- return getDerived().VisitVectorType(T);
-}
+ if (T->getTemplateId()) {
+ TRY_TO(VisitTemplateSpecializationType(
+ const_cast<TemplateSpecializationType *>(T->getTemplateId())));
+ }
+ })
-template<typename Derived>
-bool RecursiveASTVisitorImpl<Derived>::VisitFunctionType(FunctionType *T) {
- if (Visit(T->getResultType()))
- return true;
+DEF_TRAVERSE_TYPE(ObjCInterfaceType, { })
- return getDerived().VisitType(T);
-}
+DEF_TRAVERSE_TYPE(ObjCObjectType, {
+ // We have to watch out here because an ObjCInterfaceType's base
+ // type is itself.
+ if (T->getBaseType().getTypePtr() != T)
+ TRY_TO(TraverseType(T->getBaseType()));
+ })
-template<typename Derived>
-bool RecursiveASTVisitorImpl<Derived>::VisitFunctionNoProtoType(
- FunctionNoProtoType *T) {
- return getDerived().VisitFunctionType(T);
-}
+DEF_TRAVERSE_TYPE(ObjCObjectPointerType, {
+ TRY_TO(TraverseType(T->getPointeeType()));
+ })
-template<typename Derived>
-bool RecursiveASTVisitorImpl<Derived>::VisitFunctionProtoType(
- FunctionProtoType *T) {
- for (FunctionProtoType::arg_type_iterator A = T->arg_type_begin(),
- AEnd = T->arg_type_end();
- A != AEnd; ++A) {
- if (Visit(*A))
- return true;
- }
+#undef DEF_TRAVERSE_TYPE
- for (FunctionProtoType::exception_iterator E = T->exception_begin(),
- EEnd = T->exception_end();
- E != EEnd; ++E) {
- if (Visit(*E))
- return true;
- }
+// ----------------- Decl traversal -----------------
+//
+// For a Decl, we automate (in the DEF_TRAVERSE_DECL macro) traversing
+// the children that come from the DeclContext associated with it.
+// Therefore each Traverse* only needs to worry about children other
+// than those.
- return getDerived().VisitFunctionType(T);
+// This macro makes available a variable D, the passed-in decl.
+#define DEF_TRAVERSE_DECL(DECL, CODE) \
+template<typename Derived> \
+bool RecursiveASTVisitor<Derived>::Traverse##DECL (DECL *D) { \
+ TRY_TO(WalkUpFrom##DECL (D)); \
+ { CODE; } \
+ if (DeclContext *DC = dyn_cast<DeclContext>(D)) { \
+ for (DeclContext::decl_iterator Child = DC->decls_begin(), \
+ ChildEnd = DC->decls_end(); \
+ Child != ChildEnd; ++Child) \
+ TRY_TO(TraverseDecl(*Child)); \
+ } \
+ return false; \
}
-template<typename Derived>
-bool RecursiveASTVisitorImpl<Derived>::VisitUnresolvedUsingType(
- UnresolvedUsingType *T) {
- return getDerived().VisitType(T);
-}
+DEF_TRAVERSE_DECL(BlockDecl, {
+ // We don't traverse nodes in param_begin()/param_end(), as they
+ // appear in decls_begin()/decls_end() and thus are handled by the
+ // DEF_TRAVERSE_DECL macro already.
+ TRY_TO(TraverseStmt(D->getBody()));
+ })
-template<typename Derived>
-bool RecursiveASTVisitorImpl<Derived>::VisitTypedefType(TypedefType *T) {
- return getDerived().VisitType(T);
-}
+DEF_TRAVERSE_DECL(FileScopeAsmDecl, {
+ TRY_TO(TraverseStmt(D->getAsmString()));
+ })
-template<typename Derived>
-bool RecursiveASTVisitorImpl<Derived>::VisitTypeOfExprType(TypeOfExprType *T) {
- if (Visit(T->getUnderlyingExpr()))
- return true;
+DEF_TRAVERSE_DECL(FriendDecl, {
+ TRY_TO(TraverseDecl(D->getFriendDecl()));
+ })
- return getDerived().VisitType(T);
-}
+DEF_TRAVERSE_DECL(FriendTemplateDecl, {
+ TRY_TO(TraverseDecl(D->getFriendDecl()));
+ for (unsigned I = 0, E = D->getNumTemplateParameters(); I < E; ++I) {
+ TemplateParameterList *TPL = D->getTemplateParameterList(I);
+ for (TemplateParameterList::iterator ITPL = TPL->begin(),
+ ETPL = TPL->end();
+ ITPL != ETPL; ++ITPL) {
+ TRY_TO(TraverseDecl(*ITPL));
+ }
+ }
+ })
-template<typename Derived>
-bool RecursiveASTVisitorImpl<Derived>::VisitTypeOfType(TypeOfType *T) {
- if (Visit(T->getUnderlyingType()))
- return true;
+DEF_TRAVERSE_DECL(LinkageSpecDecl, { })
- return getDerived().VisitType(T);
-}
+DEF_TRAVERSE_DECL(ObjCClassDecl, {
+ // FIXME: implement this
+ })
-template<typename Derived>
-bool RecursiveASTVisitorImpl<Derived>::VisitDecltypeType(DecltypeType *T) {
- if (Visit(T->getUnderlyingExpr()))
- return true;
+DEF_TRAVERSE_DECL(ObjCForwardProtocolDecl, {
+ // FIXME: implement this
+ })
- return getDerived().VisitType(T);
-}
+DEF_TRAVERSE_DECL(ObjCPropertyImplDecl, {
+ // FIXME: implement this
+ })
+DEF_TRAVERSE_DECL(StaticAssertDecl, {
+ TRY_TO(TraverseStmt(D->getAssertExpr()));
+ TRY_TO(TraverseStmt(D->getMessage()));
+ })
+
+DEF_TRAVERSE_DECL(TranslationUnitDecl, {
+ // Code in an unnamed namespace shows up automatically in
+ // decls_begin()/decls_end(). Thus we don't need to recurse on
+ // D->getAnonymousNamespace().
+ })
+
+DEF_TRAVERSE_DECL(NamespaceAliasDecl, {
+ // We shouldn't traverse an aliased namespace, since it will be
+ // defined (and, therefore, traversed) somewhere else.
+ //
+ // This return statement makes sure the traversal of nodes in
+ // decls_begin()/decls_end() (done in the DEF_TRAVERSE_DECL macro)
+ // is skipped - don't remove it.
+ return false;
+ })
+
+DEF_TRAVERSE_DECL(NamespaceDecl, {
+ // Code in an unnamed namespace shows up automatically in
+ // decls_begin()/decls_end(). Thus we don't need to recurse on
+ // D->getAnonymousNamespace().
+ })
+
+DEF_TRAVERSE_DECL(ObjCCompatibleAliasDecl, {
+ // FIXME: implement
+ })
+
+DEF_TRAVERSE_DECL(ObjCCategoryDecl, {
+ // FIXME: implement
+ })
+
+DEF_TRAVERSE_DECL(ObjCCategoryImplDecl, {
+ // FIXME: implement
+ })
+
+DEF_TRAVERSE_DECL(ObjCImplementationDecl, {
+ // FIXME: implement
+ })
+
+DEF_TRAVERSE_DECL(ObjCInterfaceDecl, {
+ // FIXME: implement
+ })
+
+DEF_TRAVERSE_DECL(ObjCProtocolDecl, {
+ // FIXME: implement
+ })
+
+DEF_TRAVERSE_DECL(ObjCMethodDecl, {
+ // FIXME: implement
+ })
+
+DEF_TRAVERSE_DECL(ObjCPropertyDecl, {
+ // FIXME: implement
+ })
+
+DEF_TRAVERSE_DECL(UsingDecl, {
+ TRY_TO(TraverseNestedNameSpecifier(D->getTargetNestedNameDecl()));
+ for (UsingDecl::shadow_iterator I = D->shadow_begin(), E = D->shadow_end();
+ I != E; ++I) {
+ TRY_TO(TraverseDecl(*I));
+ }
+ })
+
+DEF_TRAVERSE_DECL(UsingDirectiveDecl, {
+ TRY_TO(TraverseNestedNameSpecifier(D->getQualifier()));
+ })
+
+DEF_TRAVERSE_DECL(UsingShadowDecl, { })
+
+// A helper method for TemplateDecl's children.
template<typename Derived>
-bool RecursiveASTVisitorImpl<Derived>::VisitTagType(TagType *T) {
- return getDerived().VisitType(T);
+bool RecursiveASTVisitor<Derived>::TraverseTemplateParameterListHelper(
+ TemplateParameterList *TPL) {
+ if (TPL) {
+ for (TemplateParameterList::iterator I = TPL->begin(), E = TPL->end();
+ I != E; ++I) {
+ TRY_TO(TraverseDecl(*I));
+ }
+ }
+ return false;
}
+DEF_TRAVERSE_DECL(ClassTemplateDecl, {
+ TRY_TO(TraverseDecl(D->getTemplatedDecl()));
+ TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));
+ // We should not traverse the specializations/partial
+ // specializations. Those will show up in other contexts.
+ // getInstantiatedFromMemberTemplate() is just a link from a
+ // template instantiation back to the template from which it was
+ // instantiated, and thus should not be traversed either.
+ })
+
+DEF_TRAVERSE_DECL(FunctionTemplateDecl, {
+ TRY_TO(TraverseDecl(D->getTemplatedDecl()));
+ TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));
+ })
+
+DEF_TRAVERSE_DECL(TemplateTemplateParmDecl, {
+ // D is the "T" in something like
+ // template <template <typename> class T> class container { };
+ TRY_TO(TraverseDecl(D->getTemplatedDecl()));
+ // FIXME: pass along the full TemplateArgumentLoc
+ if (D->hasDefaultArgument()) {
+ TRY_TO(TraverseTemplateArgument(D->getDefaultArgument().getArgument()));
+ }
+ TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));
+ })
+
+DEF_TRAVERSE_DECL(TemplateTypeParmDecl, {
+ // D is the "T" in something like "template<typename T> class vector;"
+ if (D->hasDefaultArgument())
+ TRY_TO(TraverseType(D->getDefaultArgument()));
+ if (D->getTypeForDecl())
+ TRY_TO(TraverseType(QualType(D->getTypeForDecl(), 0)));
+ })
+
+DEF_TRAVERSE_DECL(TypedefDecl, {
+ // FIXME: I *think* this returns the right type (D's immediate typedef)
+ TRY_TO(TraverseType(D->getUnderlyingType()));
+ // We shouldn't traverse D->getTypeForDecl(); it's a result of
+ // declaring the typedef, not something that was written in the
+ // source.
+ })
+
+DEF_TRAVERSE_DECL(UnresolvedUsingTypenameDecl, {
+ // A dependent using declaration which was marked with 'typename'.
+ // template<class T> class A : public B<T> { using typename B<T>::foo; };
+ TRY_TO(TraverseNestedNameSpecifier(D->getTargetNestedNameSpecifier()));
+ // We shouldn't traverse D->getTypeForDecl(); it's a result of
+ // declaring the type, not something that was written in the
+ // source.
+ })
+
+DEF_TRAVERSE_DECL(EnumDecl, {
+ if (D->getTypeForDecl())
+ TRY_TO(TraverseType(QualType(D->getTypeForDecl(), 0)));
+
+ TRY_TO(TraverseNestedNameSpecifier(D->getQualifier()));
+ // The enumerators are already traversed by
+ // decls_begin()/decls_end().
+ })
+
+
+// Helper methods for RecordDecl and its children.
template<typename Derived>
-bool RecursiveASTVisitorImpl<Derived>::VisitRecordType(RecordType *T) {
- return getDerived().VisitTagType(T);
+bool RecursiveASTVisitor<Derived>::TraverseRecordHelper(
+ RecordDecl *D) {
+ // We shouldn't traverse D->getTypeForDecl(); it's a result of
+ // declaring the type, not something that was written in the source.
+ //
+ // The anonymous struct or union object is the variable or field
+ // whose type is the anonymous struct or union. We shouldn't
+ // traverse D->getAnonymousStructOrUnionObject(), as it's not
+ // something that is explicitly written in the source.
+ TRY_TO(TraverseNestedNameSpecifier(D->getQualifier()));
+ return false;
}
template<typename Derived>
-bool RecursiveASTVisitorImpl<Derived>::VisitEnumType(EnumType *T) {
- return getDerived().VisitType(T);
+bool RecursiveASTVisitor<Derived>::TraverseCXXRecordHelper(
+ CXXRecordDecl *D) {
+ if (TraverseRecordHelper(D))
+ return true;
+ if (D->hasDefinition()) {
+ for (CXXRecordDecl::base_class_iterator I = D->bases_begin(),
+ E = D->bases_end();
+ I != E; ++I) {
+ TRY_TO(TraverseType(I->getType()));
+ }
+ // We don't traverse the friends or the conversions, as they are
+ // already in decls_begin()/decls_end().
+ }
+ return false;
}
-template<typename Derived>
-bool RecursiveASTVisitorImpl<Derived>::VisitTemplateTypeParmType(
- TemplateTypeParmType *T) {
- return getDerived().VisitType(T);
+DEF_TRAVERSE_DECL(RecordDecl, {
+ TRY_TO(TraverseRecordHelper(D));
+ })
+
+DEF_TRAVERSE_DECL(CXXRecordDecl, {
+ TRY_TO(TraverseCXXRecordHelper(D));
+ })
+
+DEF_TRAVERSE_DECL(ClassTemplateSpecializationDecl, {
+ // FIXME: we probably want to traverse the TemplateArgumentLoc for
+ // explicitly-written specializations and instantiations, rather
+ // than the computed template arguments.
+ const TemplateArgumentList &TAL = D->getTemplateArgs();
+ for (unsigned I = 0; I < TAL.size(); ++I) {
+ TRY_TO(TraverseTemplateArgument(TAL.get(I)));
+ }
+ TRY_TO(TraverseCXXRecordHelper(D));
+ })
+
+template <typename Derived>
+bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLocsHelper(
+ const TemplateArgumentLoc *TAL, unsigned Count) {
+ for (unsigned I = 0; I < Count; ++I) {
+ // FIXME: pass along the loc information to this callback as well?
+ TRY_TO(TraverseTemplateArgument(TAL[I].getArgument()));
+ }
+ return false;
}
+DEF_TRAVERSE_DECL(ClassTemplatePartialSpecializationDecl, {
+ // The partial specialization.
+ TemplateParameterList *TPL = D->getTemplateParameters();
+ if (TPL) {
+ for (TemplateParameterList::iterator I = TPL->begin(), E = TPL->end();
+ I != E; ++I) {
+ TRY_TO(TraverseDecl(*I));
+ }
+ }
+ // The args that remains unspecialized.
+ TRY_TO(TraverseTemplateArgumentLocsHelper(
+ D->getTemplateArgsAsWritten(), D->getNumTemplateArgsAsWritten()));
+
+ // Don't need the ClassTemplatePartialSpecializationHelper, even
+ // though that's our parent class -- we already visit all the
+ // template args here.
+ TRY_TO(TraverseCXXRecordHelper(D));
+ })
+
+DEF_TRAVERSE_DECL(EnumConstantDecl, {
+ TRY_TO(TraverseStmt(D->getInitExpr()));
+ })
+
+DEF_TRAVERSE_DECL(UnresolvedUsingValueDecl, {
+ // Like UnresolvedUsingTypenameDecl, but without the 'typename':
+ // template <class T> Class A : public Base<T> { using Base<T>::foo; };
+ TRY_TO(TraverseNestedNameSpecifier(D->getTargetNestedNameSpecifier()));
+ })
+
template<typename Derived>
-bool RecursiveASTVisitorImpl<Derived>::VisitSubstTemplateTypeParmType(
- SubstTemplateTypeParmType *T) {
- return getDerived().VisitType(T);
+bool RecursiveASTVisitor<Derived>::TraverseDeclaratorHelper(DeclaratorDecl *D) {
+ TRY_TO(TraverseNestedNameSpecifier(D->getQualifier()));
+ if (D->getTypeSourceInfo())
+ TRY_TO(TraverseType(D->getTypeSourceInfo()->getType()));
+ return false;
}
-template<typename Derived>
-bool RecursiveASTVisitorImpl<Derived>::VisitTemplateSpecializationType(
- TemplateSpecializationType *T) {
- if (getDerived().VisitTemplateName(T->getTemplateName()) ||
- getDerived().VisitTemplateArguments(T->getArgs(), T->getNumArgs()))
- return true;
+DEF_TRAVERSE_DECL(FieldDecl, {
+ TRY_TO(TraverseDeclaratorHelper(D));
+ if (D->isBitField())
+ TRY_TO(TraverseStmt(D->getBitWidth()));
+ })
- return getDerived().VisitType(T);
-}
+DEF_TRAVERSE_DECL(ObjCAtDefsFieldDecl, {
+ TRY_TO(TraverseDeclaratorHelper(D));
+ if (D->isBitField())
+ TRY_TO(TraverseStmt(D->getBitWidth()));
+ // FIXME: implement the rest.
+ })
+DEF_TRAVERSE_DECL(ObjCIvarDecl, {
+ TRY_TO(TraverseDeclaratorHelper(D));
+ if (D->isBitField())
+ TRY_TO(TraverseStmt(D->getBitWidth()));
+ // FIXME: implement the rest.
+ })
+
template<typename Derived>
-bool RecursiveASTVisitorImpl<Derived>::VisitInjectedClassNameType(
- InjectedClassNameType *T) {
- return getDerived().VisitType(T);
+bool RecursiveASTVisitor<Derived>::TraverseFunctionHelper(FunctionDecl *D) {
+ // The function parameters will be traversed by
+ // decls_begin/decls_end. We don't traverse D->getResultType(), as
+ // it's part of the TypeSourceInfo for the function declaration.
+ TRY_TO(TraverseDeclaratorHelper(D));
+ if (D->isThisDeclarationADefinition()) {
+ TRY_TO(TraverseStmt(D->getBody()));
+ }
+ return false;
}
-template<typename Derived>
-bool RecursiveASTVisitorImpl<Derived>::VisitElaboratedType(ElaboratedType *T) {
- if (T->getQualifier() &&
- getDerived().VisitNestedNameSpecifier(T->getQualifier()))
- return true;
- if (Visit(T->getNamedType()))
- return true;
+DEF_TRAVERSE_DECL(FunctionDecl, {
+ TRY_TO(TraverseFunctionHelper(D));
+ })
- return getDerived().VisitType(T);
-}
+DEF_TRAVERSE_DECL(CXXMethodDecl, {
+ // FIXME: verify we don't need anything more than the superclass does.
+ // If we do, change 3 subclasses to call our helper method, instead.
+ TRY_TO(TraverseFunctionHelper(D));
+ })
-template<typename Derived>
-bool RecursiveASTVisitorImpl<Derived>::VisitDependentNameType(
- DependentNameType *T) {
- if (T->getQualifier() &&
- getDerived().VisitNestedNameSpecifier(T->getQualifier()))
- return true;
+DEF_TRAVERSE_DECL(CXXConstructorDecl, {
+ TRY_TO(TraverseFunctionHelper(D));
+ for (CXXConstructorDecl::init_iterator I = D->init_begin(),
+ E = D->init_end();
+ I != E; ++I) {
+ // FIXME: figure out how to recurse on the initializers
+ }
+ })
- if (T->getTemplateId() &&
- getDerived().VisitTemplateSpecializationType(
- const_cast<TemplateSpecializationType *>(T->getTemplateId())))
- return true;
+DEF_TRAVERSE_DECL(CXXConversionDecl, {
+ TRY_TO(TraverseFunctionHelper(D));
+ // FIXME: is this redundant with GetResultType in VisitFunctionDecl?
+ TRY_TO(TraverseType(D->getConversionType()));
+ })
- return getDerived().VisitType(T);
-}
+DEF_TRAVERSE_DECL(CXXDestructorDecl, {
+ TRY_TO(TraverseFunctionHelper(D));
+ })
template<typename Derived>
-bool RecursiveASTVisitorImpl<Derived>::VisitObjCInterfaceType(
- ObjCInterfaceType *T) {
- return getDerived().VisitObjCObjectType(T);
+bool RecursiveASTVisitor<Derived>::TraverseVarHelper(VarDecl *D) {
+ // FIXME: This often double-counts -- for instance, for all local
+ // vars, though not for global vars -- because the initializer is
+ // also captured when the var-decl is in a DeclStmt.
+ TRY_TO(TraverseStmt(D->getInit()));
+ return false;
}
-template<typename Derived>
-bool RecursiveASTVisitorImpl<Derived>::VisitObjCObjectType(ObjCObjectType *T) {
- // We have to watch out here because an ObjCInterfaceType's base
- // type is itself.
- if (T->getBaseType().getTypePtr() != T)
- if (Visit(T->getBaseType()))
- return true;
+DEF_TRAVERSE_DECL(VarDecl, {
+ // FIXME: This often double-counts -- for instance, for all local
+ // vars, though not for global vars -- because the initializer is
+ // also captured when the var-decl is in a DeclStmt.
+ TRY_TO(TraverseVarHelper(D));
+ })
- return getDerived().VisitType(T);
-}
+DEF_TRAVERSE_DECL(ImplicitParamDecl, {
+ TRY_TO(TraverseVarHelper(D));
+ })
-template<typename Derived>
-bool RecursiveASTVisitorImpl<Derived>::VisitObjCObjectPointerType(
- ObjCObjectPointerType *T) {
- if (Visit(T->getPointeeType()))
- return true;
+DEF_TRAVERSE_DECL(NonTypeTemplateParmDecl, {
+ // A non-type template parameter, e.g. "S" in template<int S> class Foo ...
+ TRY_TO(TraverseStmt(D->getDefaultArgument()));
+ TRY_TO(TraverseVarHelper(D));
+ })
- return getDerived().VisitType(T);
-}
+DEF_TRAVERSE_DECL(ParmVarDecl, {
+ if (D->hasDefaultArg() &&
+ D->hasUninstantiatedDefaultArg() &&
+ !D->hasUnparsedDefaultArg())
+ TRY_TO(TraverseStmt(D->getUninstantiatedDefaultArg()));
-template<typename Derived>
-bool RecursiveASTVisitorImpl<Derived>::VisitDecl(Decl *D) {
- if (DeclContext *DC = dyn_cast<DeclContext>(D)) {
- for (DeclContext::decl_iterator Child = DC->decls_begin(),
- ChildEnd = DC->decls_end();
- Child != ChildEnd; ++Child)
- if (Visit(*Child))
- return true;
+ if (D->hasDefaultArg() &&
+ !D->hasUninstantiatedDefaultArg() &&
+ !D->hasUnparsedDefaultArg())
+ TRY_TO(TraverseStmt(D->getDefaultArg()));
- return false;
- }
+ // FIXME: we should traverse the TypeSourceInfo, which is far
+ // better that traversing getOriginalType(), since the
+ // TypeSourceInfo describes the original type as written.
+ TRY_TO(TraverseVarHelper(D));
+ })
- return false;
+#undef DEF_TRAVERSE_DECL
+
+// ----------------- Stmt traversal -----------------
+//
+// For stmts, we automate (in the DEF_TRAVERSE_STMT macro) iterating
+// over the children defined in child_begin/child_end (every stmt
+// defines these, though sometimes the range is empty). Each
+// individual Traverse* method only needs to worry about children
+// other than those. To see what child_begin()/end() does for a given
+// class, see, e.g.,
+// http://clang.llvm.org/doxygen/Stmt_8cpp_source.html
+
+// 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) { \
+ TRY_TO(WalkUpFrom##STMT(S)); \
+ { CODE; } \
+ for (Stmt::child_iterator C = S->child_begin(), CEnd = S->child_end(); \
+ C != CEnd; ++C) { \
+ TRY_TO(TraverseStmt(*C)); \
+ } \
+ return false; \
}
-/// \brief A visitor that recursively walks the entire Clang AST.
-///
-/// Clients of this visitor should subclass the visitor (providing
-/// themselves as the template argument, using the curiously
-/// recurring template pattern) and override any of the Visit*
-/// methods (except Visit()) for declaration, type, statement,
-/// expression, or other AST nodes where the visitor should customize
-/// behavior. Returning "true" from one of these overridden functions
-/// will abort the entire traversal. An overridden Visit* method
-/// will not descend further into the AST for that node unless
-/// Base::Visit* is called.
-template<typename Derived>
-class RecursiveASTVisitor : public RecursiveASTVisitorImpl<Derived> {
- typedef RecursiveASTVisitorImpl<Derived> Impl;
-public:
- typedef RecursiveASTVisitor<Derived> Base;
+DEF_TRAVERSE_STMT(AsmStmt, {
+ TRY_TO(TraverseStmt(S->getAsmString()));
+ for (unsigned I = 0, E = S->getNumInputs(); I < E; ++I) {
+ TRY_TO(TraverseStmt(S->getInputConstraintLiteral(I)));
+ }
+ for (unsigned I = 0, E = S->getNumOutputs(); I < E; ++I) {
+ TRY_TO(TraverseStmt(S->getOutputConstraintLiteral(I)));
+ }
+ for (unsigned I = 0, E = S->getNumClobbers(); I < E; ++I) {
+ TRY_TO(TraverseStmt(S->getClobber(I)));
+ }
+ // child_begin()/end() iterates over inputExpr and outputExpr.
+ })
- bool VisitDeclaratorDecl(DeclaratorDecl *D);
- bool VisitFunctionDecl(FunctionDecl *D);
- bool VisitVarDecl(VarDecl *D);
- bool VisitBlockDecl(BlockDecl *D);
- bool VisitDeclStmt(DeclStmt *S);
- bool VisitFunctionType(FunctionType *F);
- bool VisitFunctionProtoType(FunctionProtoType *F);
-};
+DEF_TRAVERSE_STMT(CXXCatchStmt, {
+ // We don't traverse S->getCaughtType(), as we are already
+ // traversing the exception object, which has this type.
+ // child_begin()/end() iterates over the handler block.
+ })
-#define DEFINE_VISIT(Type, Name, Statement) \
- template<typename Derived> \
- bool RecursiveASTVisitor<Derived>::Visit ## Type (Type *Name) { \
- if (Impl::Visit ## Type (Name)) return true; \
- { Statement; } \
- return false; \
- }
+DEF_TRAVERSE_STMT(ForStmt, {
+ TRY_TO(TraverseDecl(S->getConditionVariable()));
+ // child_begin()/end() iterates over init, cond, inc, and body stmts.
+ })
-DEFINE_VISIT(DeclaratorDecl, D, {
- if (TypeSourceInfo *TInfo = D->getTypeSourceInfo())
- return this->Visit(TInfo->getType());
+DEF_TRAVERSE_STMT(IfStmt, {
+ TRY_TO(TraverseDecl(S->getConditionVariable()));
+ // child_begin()/end() iterates over cond, then, and else stmts.
})
-DEFINE_VISIT(FunctionDecl, D, {
- if (D->isThisDeclarationADefinition())
- return this->Visit(D->getBody());
+DEF_TRAVERSE_STMT(WhileStmt, {
+ TRY_TO(TraverseDecl(S->getConditionVariable()));
+ // child_begin()/end() iterates over cond, then, and else stmts.
})
-DEFINE_VISIT(VarDecl, D, return this->Visit(D->getInit()))
+// These non-expr stmts (most of them), do not need any action except
+// iterating over the children.
+DEF_TRAVERSE_STMT(BreakStmt, { })
+DEF_TRAVERSE_STMT(CompoundStmt, { })
+DEF_TRAVERSE_STMT(ContinueStmt, { })
+DEF_TRAVERSE_STMT(CXXTryStmt, { })
+DEF_TRAVERSE_STMT(DeclStmt, { })
+DEF_TRAVERSE_STMT(DoStmt, { })
+DEF_TRAVERSE_STMT(GotoStmt, { })
+DEF_TRAVERSE_STMT(IndirectGotoStmt, { })
+DEF_TRAVERSE_STMT(LabelStmt, { })
+DEF_TRAVERSE_STMT(NullStmt, { })
+DEF_TRAVERSE_STMT(ObjCAtCatchStmt, { })
+DEF_TRAVERSE_STMT(ObjCAtFinallyStmt, { })
+DEF_TRAVERSE_STMT(ObjCAtSynchronizedStmt, { })
+DEF_TRAVERSE_STMT(ObjCAtThrowStmt, { })
+DEF_TRAVERSE_STMT(ObjCAtTryStmt, { })
+DEF_TRAVERSE_STMT(ObjCForCollectionStmt, { })
+DEF_TRAVERSE_STMT(ReturnStmt, { })
+DEF_TRAVERSE_STMT(SwitchStmt, { })
+DEF_TRAVERSE_STMT(SwitchCase, { })
+DEF_TRAVERSE_STMT(CaseStmt, { })
+DEF_TRAVERSE_STMT(DefaultStmt, { })
-DEFINE_VISIT(BlockDecl, D, return this->Visit(D->getBody()))
-
-DEFINE_VISIT(DeclStmt, S, {
- for (DeclStmt::decl_iterator I = S->decl_begin(), E = S->decl_end();
- I != E; ++I) {
- if (this->Visit(*I))
- return true;
+DEF_TRAVERSE_STMT(CXXDependentScopeMemberExpr, {
+ if (S->hasExplicitTemplateArgs()) {
+ TRY_TO(TraverseTemplateArgumentLocsHelper(
+ S->getTemplateArgs(), S->getNumTemplateArgs()));
}
+ TRY_TO(TraverseNestedNameSpecifier(S->getQualifier()));
})
-// FunctionType is the common base class of FunctionNoProtoType (a
-// K&R-style function declaration that has no information about
-// its arguments) and FunctionProtoType.
-DEFINE_VISIT(FunctionType, F, return this->Visit(F->getResultType()))
+DEF_TRAVERSE_STMT(DeclRefExpr, {
+ TRY_TO(TraverseTemplateArgumentLocsHelper(
+ S->getTemplateArgs(), S->getNumTemplateArgs()));
+ // FIXME: Should we be recursing on the qualifier?
+ TRY_TO(TraverseNestedNameSpecifier(S->getQualifier()));
+ })
-DEFINE_VISIT(FunctionProtoType, F, {
- for (unsigned i = 0; i != F->getNumArgs(); ++i) {
- if (this->Visit(F->getArgType(i)))
- return true;
+DEF_TRAVERSE_STMT(DependentScopeDeclRefExpr, {
+ // FIXME: Should we be recursing on these two things?
+ if (S->hasExplicitTemplateArgs()) {
+ TRY_TO(TraverseTemplateArgumentLocsHelper(
+ S->getExplicitTemplateArgs().getTemplateArgs(),
+ S->getNumTemplateArgs()));
}
- for (unsigned i = 0; i != F->getNumExceptions(); ++i) {
- if (this->Visit(F->getExceptionType(i)))
- return true;
- }
+ TRY_TO(TraverseNestedNameSpecifier(S->getQualifier()));
})
-#undef DEFINE_VISIT
+DEF_TRAVERSE_STMT(MemberExpr, {
+ TRY_TO(TraverseTemplateArgumentLocsHelper(
+ S->getTemplateArgs(), S->getNumTemplateArgs()));
+ // FIXME: Should we be recursing on the qualifier?
+ TRY_TO(TraverseNestedNameSpecifier(S->getQualifier()));
+ })
-#undef DISPATCH
+DEF_TRAVERSE_STMT(ImplicitCastExpr, {
+ // We don't traverse the cast type, as it's not written in the
+ // source code.
+ })
+DEF_TRAVERSE_STMT(CStyleCastExpr, {
+ TRY_TO(TraverseType(S->getTypeAsWritten()));
+ })
+
+DEF_TRAVERSE_STMT(CXXFunctionalCastExpr, {
+ TRY_TO(TraverseType(S->getTypeAsWritten()));
+ })
+
+DEF_TRAVERSE_STMT(CXXConstCastExpr, {
+ TRY_TO(TraverseType(S->getTypeAsWritten()));
+ })
+
+DEF_TRAVERSE_STMT(CXXDynamicCastExpr, {
+ TRY_TO(TraverseType(S->getTypeAsWritten()));
+ })
+
+DEF_TRAVERSE_STMT(CXXReinterpretCastExpr, {
+ TRY_TO(TraverseType(S->getTypeAsWritten()));
+ })
+
+DEF_TRAVERSE_STMT(CXXStaticCastExpr, {
+ TRY_TO(TraverseType(S->getTypeAsWritten()));
+ })
+
+// These exprs (most of them), do not need any action except iterating
+// over the children.
+DEF_TRAVERSE_STMT(AddrLabelExpr, { })
+DEF_TRAVERSE_STMT(ArraySubscriptExpr, { })
+DEF_TRAVERSE_STMT(BlockDeclRefExpr, { })
+DEF_TRAVERSE_STMT(BlockExpr, { })
+DEF_TRAVERSE_STMT(ChooseExpr, { })
+DEF_TRAVERSE_STMT(CompoundLiteralExpr, { })
+DEF_TRAVERSE_STMT(CXXBindReferenceExpr, { })
+DEF_TRAVERSE_STMT(CXXBindTemporaryExpr, { })
+DEF_TRAVERSE_STMT(CXXBoolLiteralExpr, { })
+DEF_TRAVERSE_STMT(CXXDefaultArgExpr, { })
+DEF_TRAVERSE_STMT(CXXDeleteExpr, { })
+DEF_TRAVERSE_STMT(CXXExprWithTemporaries, { })
+DEF_TRAVERSE_STMT(CXXNewExpr, { })
+DEF_TRAVERSE_STMT(CXXNullPtrLiteralExpr, { })
+DEF_TRAVERSE_STMT(CXXPseudoDestructorExpr, { })
+DEF_TRAVERSE_STMT(CXXThisExpr, { })
+DEF_TRAVERSE_STMT(CXXThrowExpr, { })
+DEF_TRAVERSE_STMT(CXXTypeidExpr, { })
+DEF_TRAVERSE_STMT(CXXUnresolvedConstructExpr, { })
+DEF_TRAVERSE_STMT(CXXZeroInitValueExpr, { })
+DEF_TRAVERSE_STMT(DesignatedInitExpr, { })
+DEF_TRAVERSE_STMT(ExtVectorElementExpr, { })
+DEF_TRAVERSE_STMT(GNUNullExpr, { })
+DEF_TRAVERSE_STMT(ImplicitValueInitExpr, { })
+DEF_TRAVERSE_STMT(InitListExpr, { })
+DEF_TRAVERSE_STMT(ObjCEncodeExpr, { })
+DEF_TRAVERSE_STMT(ObjCImplicitSetterGetterRefExpr, { })
+DEF_TRAVERSE_STMT(ObjCIsaExpr, { })
+DEF_TRAVERSE_STMT(ObjCIvarRefExpr, { })
+DEF_TRAVERSE_STMT(ObjCMessageExpr, { })
+DEF_TRAVERSE_STMT(ObjCPropertyRefExpr, { })
+DEF_TRAVERSE_STMT(ObjCProtocolExpr, { })
+DEF_TRAVERSE_STMT(ObjCSelectorExpr, { })
+DEF_TRAVERSE_STMT(ObjCSuperExpr, { })
+DEF_TRAVERSE_STMT(OffsetOfExpr, { })
+DEF_TRAVERSE_STMT(ParenExpr, { })
+DEF_TRAVERSE_STMT(ParenListExpr, { })
+DEF_TRAVERSE_STMT(PredefinedExpr, { })
+DEF_TRAVERSE_STMT(ShuffleVectorExpr, { })
+DEF_TRAVERSE_STMT(SizeOfAlignOfExpr, { })
+DEF_TRAVERSE_STMT(StmtExpr, { })
+DEF_TRAVERSE_STMT(TypesCompatibleExpr, { })
+DEF_TRAVERSE_STMT(UnaryTypeTraitExpr, { })
+DEF_TRAVERSE_STMT(UnresolvedLookupExpr, { })
+DEF_TRAVERSE_STMT(UnresolvedMemberExpr, { })
+DEF_TRAVERSE_STMT(VAArgExpr, { })
+DEF_TRAVERSE_STMT(CXXConstructExpr, { })
+DEF_TRAVERSE_STMT(CXXTemporaryObjectExpr, { })
+DEF_TRAVERSE_STMT(CallExpr, { })
+DEF_TRAVERSE_STMT(CXXMemberCallExpr, { })
+DEF_TRAVERSE_STMT(CXXOperatorCallExpr, { })
+
+// These operators (all of them) do not need any action except
+// iterating over the children.
+DEF_TRAVERSE_STMT(ConditionalOperator, { })
+DEF_TRAVERSE_STMT(UnaryOperator, { })
+DEF_TRAVERSE_STMT(BinaryOperator, { })
+DEF_TRAVERSE_STMT(CompoundAssignOperator, { })
+
+// These literals (all of them) do not need any action.
+DEF_TRAVERSE_STMT(IntegerLiteral, { })
+DEF_TRAVERSE_STMT(CharacterLiteral, { })
+DEF_TRAVERSE_STMT(FloatingLiteral, { })
+DEF_TRAVERSE_STMT(ImaginaryLiteral, { })
+DEF_TRAVERSE_STMT(StringLiteral, { })
+DEF_TRAVERSE_STMT(ObjCStringLiteral, { })
+
+// 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
+// not sure if they own them -- or just seemed very complicated, or
+// had lots of sub-types to explore.
+//
+// VisitOverloadExpr and its children: recurse on template args? etc?
+
+// FIXME: go through all the stmts and exprs again, and see which of them
+// create new types, and recurse on the types (TypeLocs?) of those.
+// Candidates:
+// http://clang.llvm.org/doxygen/classclang_1_1CXXTypeidExpr.html
+// http://clang.llvm.org/doxygen/classclang_1_1SizeOfAlignOfExpr.html
+// http://clang.llvm.org/doxygen/classclang_1_1TypesCompatibleExpr.html
+// http://clang.llvm.org/doxygen/classclang_1_1CXXUnresolvedConstructExpr.html
+// Every class that has getQualifier.
+
+#undef DEF_TRAVERSE_STMT
+
+#undef TRY_TO
+
} // end namespace clang
#endif // LLVM_CLANG_AST_RECURSIVEASTVISITOR_H
« no previous file with comments | « no previous file | lib/Frontend/BoostConAction.cpp » ('j') | no next file with comments »

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b