summaryrefslogtreecommitdiffstats
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.h180
1 files changed, 100 insertions, 80 deletions
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h
index f1b5171..2e56a48 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -148,10 +148,15 @@ public:
/// TypeLocs.
bool shouldWalkTypesOfTypeLocs() const { return true; }
+ /// \brief Return whether this visitor should recurse into implicit
+ /// 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);
+ return isa<BinaryOperator>(S) || isa<UnaryOperator>(S) ||
+ isa<CaseStmt>(S) || isa<CXXOperatorCallExpr>(S);
}
/// \brief Recursively visit a statement or expression, by
@@ -392,8 +397,8 @@ public:
private:
// These are helper methods used by more than one Traverse* method.
bool TraverseTemplateParameterListHelper(TemplateParameterList *TPL);
- bool TraverseClassInstantiations(ClassTemplateDecl* D, Decl *Pattern);
- bool TraverseFunctionInstantiations(FunctionTemplateDecl* D) ;
+ bool TraverseClassInstantiations(ClassTemplateDecl *D);
+ bool TraverseFunctionInstantiations(FunctionTemplateDecl *D) ;
bool TraverseTemplateArgumentLocsHelper(const TemplateArgumentLoc *TAL,
unsigned Count);
bool TraverseArrayTypeLocHelper(ArrayTypeLoc TL);
@@ -404,18 +409,14 @@ private:
bool TraverseFunctionHelper(FunctionDecl *D);
bool TraverseVarHelper(VarDecl *D);
- bool Walk(Stmt *S);
-
struct EnqueueJob {
Stmt *S;
Stmt::child_iterator StmtIt;
- EnqueueJob(Stmt *S) : S(S), StmtIt() {
- if (Expr *E = dyn_cast_or_null<Expr>(S))
- S = E->IgnoreParens();
- }
+ EnqueueJob(Stmt *S) : S(S), StmtIt() {}
};
bool dataTraverse(Stmt *S);
+ bool dataTraverseNode(Stmt *S, bool &EnqueueChildren);
};
template<typename Derived>
@@ -434,7 +435,12 @@ bool RecursiveASTVisitor<Derived>::dataTraverse(Stmt *S) {
if (getDerived().shouldUseDataRecursionFor(CurrS)) {
if (job.StmtIt == Stmt::child_iterator()) {
- if (!Walk(CurrS)) return false;
+ bool EnqueueChildren = true;
+ if (!dataTraverseNode(CurrS, EnqueueChildren)) return false;
+ if (!EnqueueChildren) {
+ Queue.pop_back();
+ continue;
+ }
job.StmtIt = CurrS->child_begin();
} else {
++job.StmtIt;
@@ -455,10 +461,25 @@ bool RecursiveASTVisitor<Derived>::dataTraverse(Stmt *S) {
}
template<typename Derived>
-bool RecursiveASTVisitor<Derived>::Walk(Stmt *S) {
-
+bool RecursiveASTVisitor<Derived>::dataTraverseNode(Stmt *S,
+ bool &EnqueueChildren) {
+
+// The cast for DISPATCH_WALK is needed for older versions of g++, but causes
+// problems for MSVC. So we'll skip the cast entirely for MSVC.
+#if defined(_MSC_VER)
+ #define GCC_CAST(CLASS)
+#else
+ #define GCC_CAST(CLASS) (bool (RecursiveASTVisitor::*)(CLASS*))
+#endif
+
+ // 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) \
- return getDerived().WalkUpFrom##NAME(static_cast<CLASS*>(VAR));
+ if (&RecursiveASTVisitor::Traverse##NAME == \
+ GCC_CAST(CLASS)&Derived::Traverse##NAME) \
+ 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()) {
@@ -495,6 +516,7 @@ bool RecursiveASTVisitor<Derived>::Walk(Stmt *S) {
}
#undef DISPATCH_WALK
+#undef GCC_CAST
return true;
}
@@ -591,10 +613,9 @@ bool RecursiveASTVisitor<Derived>::TraverseDecl(Decl *D) {
if (!D)
return true;
- // As a syntax visitor, we want to ignore declarations for
- // implicitly-defined declarations (ones not typed explicitly by the
- // user).
- if (D->isImplicit())
+ // As a syntax visitor, by default we want to ignore declarations for
+ // implicit declarations (ones not typed explicitly by the user).
+ if (!getDerived().shouldVisitImplicitCode() && D->isImplicit())
return true;
switch (D->getKind()) {
@@ -1231,7 +1252,8 @@ bool RecursiveASTVisitor<Derived>::Traverse##DECL (DECL *D) { \
DEF_TRAVERSE_DECL(AccessSpecDecl, { })
DEF_TRAVERSE_DECL(BlockDecl, {
- TRY_TO(TraverseTypeLoc(D->getSignatureAsWritten()->getTypeLoc()));
+ if (TypeSourceInfo *TInfo = D->getSignatureAsWritten())
+ TRY_TO(TraverseTypeLoc(TInfo->getTypeLoc()));
TRY_TO(TraverseStmt(D->getBody()));
// This return statement makes sure the traversal of nodes in
// decls_begin()/decls_end() (done in the DEF_TRAVERSE_DECL macro)
@@ -1269,7 +1291,13 @@ DEF_TRAVERSE_DECL(FriendTemplateDecl, {
})
DEF_TRAVERSE_DECL(ClassScopeFunctionSpecializationDecl, {
- TRY_TO(TraverseDecl(D->getSpecialization()));
+ TRY_TO(TraverseDecl(D->getSpecialization()));
+
+ if (D->hasExplicitTemplateArgs()) {
+ const TemplateArgumentListInfo& args = D->templateArgs();
+ TRY_TO(TraverseTemplateArgumentLocsHelper(
+ args.getArgumentArray(), args.size()));
+ }
})
DEF_TRAVERSE_DECL(LinkageSpecDecl, { })
@@ -1377,35 +1405,20 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateParameterListHelper(
}
// A helper method for traversing the implicit instantiations of a
-// class.
+// class template.
template<typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseClassInstantiations(
- ClassTemplateDecl* D, Decl *Pattern) {
- assert(isa<ClassTemplateDecl>(Pattern) ||
- isa<ClassTemplatePartialSpecializationDecl>(Pattern));
-
+ ClassTemplateDecl *D) {
ClassTemplateDecl::spec_iterator end = D->spec_end();
for (ClassTemplateDecl::spec_iterator it = D->spec_begin(); it != end; ++it) {
ClassTemplateSpecializationDecl* SD = *it;
switch (SD->getSpecializationKind()) {
// Visit the implicit instantiations with the requested pattern.
- case TSK_ImplicitInstantiation: {
- llvm::PointerUnion<ClassTemplateDecl *,
- ClassTemplatePartialSpecializationDecl *> U
- = SD->getInstantiatedFrom();
-
- bool ShouldVisit;
- if (U.is<ClassTemplateDecl*>())
- ShouldVisit = (U.get<ClassTemplateDecl*>() == Pattern);
- else
- ShouldVisit
- = (U.get<ClassTemplatePartialSpecializationDecl*>() == Pattern);
-
- if (ShouldVisit)
- TRY_TO(TraverseDecl(SD));
+ case TSK_Undeclared:
+ case TSK_ImplicitInstantiation:
+ TRY_TO(TraverseDecl(SD));
break;
- }
// We don't need to do anything on an explicit instantiation
// or explicit specialization because there will be an explicit
@@ -1414,11 +1427,6 @@ bool RecursiveASTVisitor<Derived>::TraverseClassInstantiations(
case TSK_ExplicitInstantiationDefinition:
case TSK_ExplicitSpecialization:
break;
-
- // We don't need to do anything for an uninstantiated
- // specialization.
- case TSK_Undeclared:
- break;
}
}
@@ -1433,12 +1441,12 @@ DEF_TRAVERSE_DECL(ClassTemplateDecl, {
// By default, we do not traverse the instantiations of
// class templates since they do not appear in the user code. The
// following code optionally traverses them.
- if (getDerived().shouldVisitTemplateInstantiations()) {
- // If this is the definition of the primary template, visit
- // instantiations which were formed from this pattern.
- if (D->isThisDeclarationADefinition())
- TRY_TO(TraverseClassInstantiations(D, D));
- }
+ //
+ // We only traverse the class instantiations when we see the canonical
+ // declaration of the template, to ensure we only visit them once.
+ if (getDerived().shouldVisitTemplateInstantiations() &&
+ D == D->getCanonicalDecl())
+ TRY_TO(TraverseClassInstantiations(D));
// Note that getInstantiatedFromMemberTemplate() is just a link
// from a template instantiation back to the template from which
@@ -1449,24 +1457,25 @@ DEF_TRAVERSE_DECL(ClassTemplateDecl, {
// function while skipping its specializations.
template<typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseFunctionInstantiations(
- FunctionTemplateDecl* D) {
+ FunctionTemplateDecl *D) {
FunctionTemplateDecl::spec_iterator end = D->spec_end();
for (FunctionTemplateDecl::spec_iterator it = D->spec_begin(); it != end;
++it) {
FunctionDecl* FD = *it;
switch (FD->getTemplateSpecializationKind()) {
+ case TSK_Undeclared:
case TSK_ImplicitInstantiation:
// We don't know what kind of FunctionDecl this is.
TRY_TO(TraverseDecl(FD));
break;
- // No need to visit explicit instantiations, we'll find the node
- // eventually.
+ // FIXME: For now traverse explicit instantiations here. Change that
+ // once they are represented as dedicated nodes in the AST.
case TSK_ExplicitInstantiationDeclaration:
case TSK_ExplicitInstantiationDefinition:
+ TRY_TO(TraverseDecl(FD));
break;
- case TSK_Undeclared: // Declaration of the template definition.
case TSK_ExplicitSpecialization:
break;
}
@@ -1480,26 +1489,21 @@ DEF_TRAVERSE_DECL(FunctionTemplateDecl, {
TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));
// By default, we do not traverse the instantiations of
- // function templates since they do not apprear in the user code. The
+ // function templates since they do not appear in the user code. The
// following code optionally traverses them.
- if (getDerived().shouldVisitTemplateInstantiations()) {
- // Explicit function specializations will be traversed from the
- // context of their declaration. There is therefore no need to
- // traverse them for here.
- //
- // In addition, we only traverse the function instantiations when
- // the function template is a function template definition.
- if (D->isThisDeclarationADefinition()) {
- TRY_TO(TraverseFunctionInstantiations(D));
- }
- }
+ //
+ // We only traverse the function instantiations when we see the canonical
+ // declaration of the template, to ensure we only visit them once.
+ if (getDerived().shouldVisitTemplateInstantiations() &&
+ D == D->getCanonicalDecl())
+ TRY_TO(TraverseFunctionInstantiations(D));
})
DEF_TRAVERSE_DECL(TemplateTemplateParmDecl, {
// D is the "T" in something like
// template <template <typename> class T> class container { };
TRY_TO(TraverseDecl(D->getTemplatedDecl()));
- if (D->hasDefaultArgument()) {
+ if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) {
TRY_TO(TraverseTemplateArgumentLoc(D->getDefaultArgument()));
}
TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));
@@ -1509,7 +1513,7 @@ DEF_TRAVERSE_DECL(TemplateTypeParmDecl, {
// D is the "T" in something like "template<typename T> class vector;"
if (D->getTypeForDecl())
TRY_TO(TraverseType(QualType(D->getTypeForDecl(), 0)));
- if (D->hasDefaultArgument())
+ if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited())
TRY_TO(TraverseTypeLoc(D->getDefaultArgumentInfo()->getTypeLoc()));
})
@@ -1567,7 +1571,7 @@ bool RecursiveASTVisitor<Derived>::TraverseCXXRecordHelper(
CXXRecordDecl *D) {
if (!TraverseRecordHelper(D))
return false;
- if (D->hasDefinition()) {
+ if (D->isCompleteDefinition()) {
for (CXXRecordDecl::base_class_iterator I = D->bases_begin(),
E = D->bases_end();
I != E; ++I) {
@@ -1634,11 +1638,7 @@ DEF_TRAVERSE_DECL(ClassTemplatePartialSpecializationDecl, {
// template args here.
TRY_TO(TraverseCXXRecordHelper(D));
- // If we're visiting instantiations, visit the instantiations of
- // this template now.
- if (getDerived().shouldVisitTemplateInstantiations() &&
- D->isThisDeclarationADefinition())
- TRY_TO(TraverseClassInstantiations(D->getSpecializedTemplate(), D));
+ // Instantiations will have been visited with the primary template.
})
DEF_TRAVERSE_DECL(EnumConstantDecl, {
@@ -1714,7 +1714,9 @@ bool RecursiveASTVisitor<Derived>::TraverseFunctionHelper(FunctionDecl *D) {
// FunctionNoProtoType or FunctionProtoType, or a typedef. This
// also covers the return type and the function parameters,
// including exception specifications.
- TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc()));
+ if (clang::TypeSourceInfo *TSI = D->getTypeSourceInfo()) {
+ TRY_TO(TraverseTypeLoc(TSI->getTypeLoc()));
+ }
if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(D)) {
// Constructor initializers.
@@ -1767,7 +1769,8 @@ template<typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseVarHelper(VarDecl *D) {
TRY_TO(TraverseDeclaratorHelper(D));
// Default params are taken care of when we traverse the ParmVarDecl.
- if (!isa<ParmVarDecl>(D))
+ if (!isa<ParmVarDecl>(D) &&
+ (!D->isCXXForRangeDecl() || getDerived().shouldVisitImplicitCode()))
TRY_TO(TraverseStmt(D->getInit()));
return true;
}
@@ -1783,7 +1786,8 @@ DEF_TRAVERSE_DECL(ImplicitParamDecl, {
DEF_TRAVERSE_DECL(NonTypeTemplateParmDecl, {
// A non-type template parameter, e.g. "S" in template<int S> class Foo ...
TRY_TO(TraverseDeclaratorHelper(D));
- TRY_TO(TraverseStmt(D->getDefaultArgument()));
+ if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited())
+ TRY_TO(TraverseStmt(D->getDefaultArgument()));
})
DEF_TRAVERSE_DECL(ParmVarDecl, {
@@ -1837,6 +1841,11 @@ DEF_TRAVERSE_STMT(AsmStmt, {
// children() iterates over inputExpr and outputExpr.
})
+DEF_TRAVERSE_STMT(MSAsmStmt, {
+ // FIXME: MS Asm doesn't currently parse Constraints, Clobbers, etc. Once
+ // added this needs to be implemented.
+ })
+
DEF_TRAVERSE_STMT(CXXCatchStmt, {
TRY_TO(TraverseDecl(S->getExceptionDecl()));
// children() iterates over the handler block.
@@ -1879,7 +1888,15 @@ DEF_TRAVERSE_STMT(ObjCAtThrowStmt, { })
DEF_TRAVERSE_STMT(ObjCAtTryStmt, { })
DEF_TRAVERSE_STMT(ObjCForCollectionStmt, { })
DEF_TRAVERSE_STMT(ObjCAutoreleasePoolStmt, { })
-DEF_TRAVERSE_STMT(CXXForRangeStmt, { })
+DEF_TRAVERSE_STMT(CXXForRangeStmt, {
+ if (!getDerived().shouldVisitImplicitCode()) {
+ TRY_TO(TraverseStmt(S->getLoopVarStmt()));
+ TRY_TO(TraverseStmt(S->getRangeInit()));
+ TRY_TO(TraverseStmt(S->getBody()));
+ // Visit everything else only if shouldVisitImplicitCode().
+ return true;
+ }
+})
DEF_TRAVERSE_STMT(MSDependentExistsStmt, {
TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
TRY_TO(TraverseDeclarationNameInfo(S->getNameInfo()));
@@ -2146,7 +2163,10 @@ DEF_TRAVERSE_STMT(ExtVectorElementExpr, { })
DEF_TRAVERSE_STMT(GNUNullExpr, { })
DEF_TRAVERSE_STMT(ImplicitValueInitExpr, { })
DEF_TRAVERSE_STMT(ObjCBoolLiteralExpr, { })
-DEF_TRAVERSE_STMT(ObjCEncodeExpr, { })
+DEF_TRAVERSE_STMT(ObjCEncodeExpr, {
+ if (TypeSourceInfo *TInfo = S->getEncodedTypeSourceInfo())
+ TRY_TO(TraverseTypeLoc(TInfo->getTypeLoc()));
+})
DEF_TRAVERSE_STMT(ObjCIsaExpr, { })
DEF_TRAVERSE_STMT(ObjCIvarRefExpr, { })
DEF_TRAVERSE_STMT(ObjCMessageExpr, { })
@@ -2209,7 +2229,7 @@ DEF_TRAVERSE_STMT(FloatingLiteral, { })
DEF_TRAVERSE_STMT(ImaginaryLiteral, { })
DEF_TRAVERSE_STMT(StringLiteral, { })
DEF_TRAVERSE_STMT(ObjCStringLiteral, { })
-DEF_TRAVERSE_STMT(ObjCNumericLiteral, { })
+DEF_TRAVERSE_STMT(ObjCBoxedExpr, { })
DEF_TRAVERSE_STMT(ObjCArrayLiteral, { })
DEF_TRAVERSE_STMT(ObjCDictionaryLiteral, { })
OpenPOWER on IntegriCloud