diff options
-rw-r--r-- | include/clang/AST/RecursiveASTVisitor.h | 27 | ||||
-rw-r--r-- | tools/libclang/IndexBody.cpp | 6 | ||||
-rw-r--r-- | unittests/Tooling/RecursiveASTVisitorTest.cpp | 36 |
3 files changed, 54 insertions, 15 deletions
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index 93363b1715..8a6e85f226 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -405,18 +405,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> @@ -435,7 +431,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; @@ -456,10 +457,18 @@ bool RecursiveASTVisitor<Derived>::dataTraverse(Stmt *S) { } template<typename Derived> -bool RecursiveASTVisitor<Derived>::Walk(Stmt *S) { +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). + // The cast here is necessary to work around a bug in old versions of g++. #define DISPATCH_WALK(NAME, CLASS, VAR) \ - return getDerived().WalkUpFrom##NAME(static_cast<CLASS*>(VAR)); + if (&RecursiveASTVisitor::Traverse##NAME == \ + (bool (RecursiveASTVisitor::*)(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()) { diff --git a/tools/libclang/IndexBody.cpp b/tools/libclang/IndexBody.cpp index 239dde21bd..e975a6d1be 100644 --- a/tools/libclang/IndexBody.cpp +++ b/tools/libclang/IndexBody.cpp @@ -117,12 +117,6 @@ public: return true; } - bool TraverseCXXOperatorCallExpr(CXXOperatorCallExpr *E) { - if (E->getOperatorLoc().isInvalid()) - return true; // implicit. - return base::TraverseCXXOperatorCallExpr(E); - } - bool VisitDeclStmt(DeclStmt *S) { if (IndexCtx.shouldIndexFunctionLocalSymbols()) IndexCtx.indexDeclGroupRef(S->getDeclGroup()); diff --git a/unittests/Tooling/RecursiveASTVisitorTest.cpp b/unittests/Tooling/RecursiveASTVisitorTest.cpp index d4fda73ccb..953817e61f 100644 --- a/unittests/Tooling/RecursiveASTVisitorTest.cpp +++ b/unittests/Tooling/RecursiveASTVisitorTest.cpp @@ -165,6 +165,26 @@ public: } }; +class CXXOperatorCallExprTraverser + : public ExpectedLocationVisitor<CXXOperatorCallExprTraverser> { +public: + // Use Traverse, not Visit, to check that data recursion optimization isn't + // bypassing the call of this function. + bool TraverseCXXOperatorCallExpr(CXXOperatorCallExpr *CE) { + Match(getOperatorSpelling(CE->getOperator()), CE->getExprLoc()); + return ExpectedLocationVisitor<CXXOperatorCallExprTraverser>:: + TraverseCXXOperatorCallExpr(CE); + } +}; + +class ParenExprVisitor : public ExpectedLocationVisitor<ParenExprVisitor> { +public: + bool VisitParenExpr(ParenExpr *Parens) { + Match("", Parens->getExprLoc()); + return true; + } +}; + TEST(RecursiveASTVisitor, VisitsBaseClassDeclarations) { TypeLocVisitor Visitor; Visitor.ExpectMatch("class X", 1, 30); @@ -345,4 +365,20 @@ TEST(RecursiveASTVisitor, NoRecursionInSelfFriend) { "vector_iterator<int> it_int;\n")); } +TEST(RecursiveASTVisitor, TraversesOverloadedOperator) { + CXXOperatorCallExprTraverser Visitor; + Visitor.ExpectMatch("()", 4, 9); + EXPECT_TRUE(Visitor.runOver( + "struct A {\n" + " int operator()();\n" + "} a;\n" + "int k = a();\n")); +} + +TEST(RecursiveASTVisitor, VisitsParensDuringDataRecursion) { + ParenExprVisitor Visitor; + Visitor.ExpectMatch("", 1, 9); + EXPECT_TRUE(Visitor.runOver("int k = (4) + 9;\n")); +} + } // end namespace clang |