///
/// \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.
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.
}
}
- TRY_TO(TraverseStmt(S->getBody()));
+ TRY_TO(TraverseLambdaBody(S));
return true;
}
#include "TestVisitor.h"
+#include <stack>
+
namespace clang {
class TypeLocVisitor : public ExpectedLocationVisitor<TypeLocVisitor> {
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
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