diff options
-rw-r--r-- | include/clang/AST/RecursiveASTVisitor.h | 18 | ||||
-rw-r--r-- | unittests/Tooling/RecursiveASTVisitorTest.cpp | 26 |
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 |