aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/RecursiveASTVisitor.h18
-rw-r--r--unittests/Tooling/RecursiveASTVisitorTest.cpp26
2 files changed, 38 insertions, 6 deletions
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h
index de042cafb6..2014f07152 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -149,8 +149,8 @@ public:
bool shouldWalkTypesOfTypeLocs() const { return true; }
/// \brief Return whether this visitor should recurse into implicit
- /// declarations, e.g., implicit constructors and destructors.
- bool shouldVisitImplicitDeclarations() const { return false; }
+ /// 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.
@@ -607,7 +607,7 @@ bool RecursiveASTVisitor<Derived>::TraverseDecl(Decl *D) {
// As a syntax visitor, by default we want to ignore declarations for
// implicit declarations (ones not typed explicitly by the user).
- if (!getDerived().shouldVisitImplicitDeclarations() && D->isImplicit())
+ if (!getDerived().shouldVisitImplicitCode() && D->isImplicit())
return true;
switch (D->getKind()) {
@@ -1755,7 +1755,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() || shouldVisitImplicitCode()))
TRY_TO(TraverseStmt(D->getInit()));
return true;
}
@@ -1873,7 +1874,14 @@ 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 (!shouldVisitImplicitCode()) {
+ TRY_TO(TraverseStmt(S->getLoopVarStmt()));
+ TRY_TO(TraverseStmt(S->getRangeInit()));
+ // Visit everything else only if shouldVisitImplicitCode().
+ return true;
+ }
+})
DEF_TRAVERSE_STMT(MSDependentExistsStmt, {
TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
TRY_TO(TraverseDeclarationNameInfo(S->getNameInfo()));
diff --git a/unittests/Tooling/RecursiveASTVisitorTest.cpp b/unittests/Tooling/RecursiveASTVisitorTest.cpp
index 52b3987bc8..9d693095d7 100644
--- a/unittests/Tooling/RecursiveASTVisitorTest.cpp
+++ b/unittests/Tooling/RecursiveASTVisitorTest.cpp
@@ -142,6 +142,14 @@ public:
}
};
+class VarDeclVisitor : public ExpectedLocationVisitor<VarDeclVisitor> {
+public:
+ bool VisitVarDecl(VarDecl *Variable) {
+ Match(Variable->getNameAsString(), Variable->getLocStart());
+ return true;
+ }
+};
+
class CXXMemberCallVisitor
: public ExpectedLocationVisitor<CXXMemberCallVisitor> {
public:
@@ -250,6 +258,22 @@ TEST(RecursiveASTVisitor, VisitsBaseClassTemplateArguments) {
"void x(); template <void (*T)()> class X {};\nX<x> y;"));
}
+TEST(RecursiveASTVisitor, VisitsCXXForRangeStmtRange) {
+ DeclRefExprVisitor Visitor;
+ Visitor.ExpectMatch("x", 2, 25);
+ EXPECT_TRUE(Visitor.runOver(
+ "int x[5];\n"
+ "void f() { for (int i : x) {} }"));
+}
+
+TEST(RecursiveASTVisitor, VisitsCXXForRangeStmtLoopVariable) {
+ VarDeclVisitor Visitor;
+ Visitor.ExpectMatch("i", 2, 17);
+ EXPECT_TRUE(Visitor.runOver(
+ "int x[5];\n"
+ "void f() { for (int i : x) {} }"));
+}
+
TEST(RecursiveASTVisitor, VisitsCallExpr) {
DeclRefExprVisitor Visitor;
Visitor.ExpectMatch("x", 1, 22);
@@ -452,7 +476,7 @@ TEST(RecursiveASTVisitor, VisitsClassTemplateTemplateParmDefaultArgument) {
class ImplicitCtorVisitor
: public ExpectedLocationVisitor<ImplicitCtorVisitor> {
public:
- bool shouldVisitImplicitDeclarations() const { return true; }
+ bool shouldVisitImplicitCode() const { return true; }
bool VisitCXXConstructorDecl(CXXConstructorDecl* Ctor) {
if (Ctor->isImplicit()) { // Was not written in source code