summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/RecursiveASTVisitor.h19
-rw-r--r--unittests/Tooling/RecursiveASTVisitorTest.cpp25
2 files changed, 42 insertions, 2 deletions
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h
index 09ac476696..6af9e55b83 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -244,7 +244,15 @@ public:
///
/// \returns false if the visitation was terminated early, true otherwise.
bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaExpr::Capture *C);
-
+
+ /// \brief Recursively visit the body of a lambda expression.
+ ///
+ /// This provides a hook for visitors that need more context when visiting
+ /// \c LE->getBody().
+ ///
+ /// \returns false if the visitation was terminated early, true otherwise.
+ bool TraverseLambdaBody(LambdaExpr *LE);
+
// ---- Methods on Stmts ----
// Declare Traverse*() for all concrete Stmt classes.
@@ -809,6 +817,13 @@ bool RecursiveASTVisitor<Derived>::TraverseLambdaCapture(
return true;
}
+template<typename Derived>
+bool RecursiveASTVisitor<Derived>::TraverseLambdaBody(LambdaExpr *LE) {
+ TRY_TO(TraverseStmt(LE->getBody()));
+ return true;
+}
+
+
// ----------------- Type traversal -----------------
// This macro makes available a variable T, the passed-in type.
@@ -2153,7 +2168,7 @@ bool RecursiveASTVisitor<Derived>::TraverseLambdaExpr(LambdaExpr *S) {
}
}
- TRY_TO(TraverseStmt(S->getBody()));
+ TRY_TO(TraverseLambdaBody(S));
return true;
}
diff --git a/unittests/Tooling/RecursiveASTVisitorTest.cpp b/unittests/Tooling/RecursiveASTVisitorTest.cpp
index 2d226fddfc..c97ee0c8c4 100644
--- a/unittests/Tooling/RecursiveASTVisitorTest.cpp
+++ b/unittests/Tooling/RecursiveASTVisitorTest.cpp
@@ -9,6 +9,8 @@
#include "TestVisitor.h"
+#include <stack>
+
namespace clang {
class TypeLocVisitor : public ExpectedLocationVisitor<TypeLocVisitor> {
@@ -82,9 +84,25 @@ public:
class LambdaExprVisitor : public ExpectedLocationVisitor<LambdaExprVisitor> {
public:
bool VisitLambdaExpr(LambdaExpr *Lambda) {
+ PendingBodies.push(Lambda);
Match("", Lambda->getIntroducerRange().getBegin());
return true;
}
+ /// For each call to VisitLambdaExpr, we expect a subsequent call (with
+ /// proper nesting) to TraverseLambdaBody.
+ bool TraverseLambdaBody(LambdaExpr *Lambda) {
+ EXPECT_FALSE(PendingBodies.empty());
+ EXPECT_EQ(PendingBodies.top(), Lambda);
+ PendingBodies.pop();
+ return TraverseStmt(Lambda->getBody());
+ }
+ /// Determine whether TraverseLambdaBody has been called for every call to
+ /// VisitLambdaExpr.
+ bool allBodiesHaveBeenTraversed() const {
+ return PendingBodies.empty();
+ }
+private:
+ std::stack<LambdaExpr *> PendingBodies;
};
class TemplateArgumentLocTraverser
@@ -478,4 +496,11 @@ TEST(RecursiveASTVisitor, VisitsLambdaExpr) {
LambdaExprVisitor::Lang_CXX11));
}
+TEST(RecursiveASTVisitor, TraverseLambdaBodyCanBeOverridden) {
+ LambdaExprVisitor Visitor;
+ EXPECT_TRUE(Visitor.runOver("void f() { []{ return; }(); }",
+ LambdaExprVisitor::Lang_CXX11));
+ EXPECT_TRUE(Visitor.allBodiesHaveBeenTraversed());
+}
+
} // end namespace clang