
Summary: Prior to r351069, lambda classes were traversed or not depending on the {Function, Class, Namespace, TU} DeclContext containing them. If it was a function (common case) they were not traversed. If it was a namespace or TU (top-level lambda) they were traversed as part of that DeclContext traversal. r351069 "fixed" RAV to traverse these as part of the LambdaExpr, which is the right place. But top-level lambdas are now traversed twice. We fix that as blocks and block captures were apparently fixed in the past. Maybe it would be nicer to avoid adding the lambda classes to the DeclContext in the first place, but I can't work out the implications of that. Reviewers: bkramer, klimek Subscribers: cfe-commits Differential Revision: https://reviews.llvm.org/D56665 llvm-svn: 351075
98 lines
3.3 KiB
C++
98 lines
3.3 KiB
C++
//===- unittest/Tooling/RecursiveASTVisitorTests/LambdaExpr.cpp -----------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "TestVisitor.h"
|
|
#include <stack>
|
|
|
|
using namespace clang;
|
|
|
|
namespace {
|
|
|
|
class LambdaExprVisitor : public ExpectedLocationVisitor<LambdaExprVisitor> {
|
|
public:
|
|
bool VisitLambdaExpr(LambdaExpr *Lambda) {
|
|
PendingBodies.push(Lambda->getBody());
|
|
PendingClasses.push(Lambda->getLambdaClass());
|
|
Match("", Lambda->getIntroducerRange().getBegin());
|
|
return true;
|
|
}
|
|
/// For each call to VisitLambdaExpr, we expect a subsequent call to visit
|
|
/// the body (and maybe the lambda class, which is implicit).
|
|
bool VisitStmt(Stmt *S) {
|
|
if (!PendingBodies.empty() && S == PendingBodies.top())
|
|
PendingBodies.pop();
|
|
return true;
|
|
}
|
|
bool VisitDecl(Decl *D) {
|
|
if (!PendingClasses.empty() && D == PendingClasses.top())
|
|
PendingClasses.pop();
|
|
return true;
|
|
}
|
|
/// Determine whether parts of lambdas (VisitLambdaExpr) were later traversed.
|
|
bool allBodiesHaveBeenTraversed() const { return PendingBodies.empty(); }
|
|
bool allClassesHaveBeenTraversed() const { return PendingClasses.empty(); }
|
|
|
|
bool VisitImplicitCode = false;
|
|
bool shouldVisitImplicitCode() const { return VisitImplicitCode; }
|
|
|
|
private:
|
|
std::stack<Stmt *> PendingBodies;
|
|
std::stack<Decl *> PendingClasses;
|
|
};
|
|
|
|
TEST(RecursiveASTVisitor, VisitsLambdaExpr) {
|
|
LambdaExprVisitor Visitor;
|
|
Visitor.ExpectMatch("", 1, 12);
|
|
EXPECT_TRUE(Visitor.runOver("void f() { []{ return; }(); }",
|
|
LambdaExprVisitor::Lang_CXX11));
|
|
EXPECT_TRUE(Visitor.allBodiesHaveBeenTraversed());
|
|
EXPECT_FALSE(Visitor.allClassesHaveBeenTraversed());
|
|
}
|
|
|
|
TEST(RecursiveASTVisitor, LambdaInLambda) {
|
|
LambdaExprVisitor Visitor;
|
|
Visitor.ExpectMatch("", 1, 12);
|
|
Visitor.ExpectMatch("", 1, 16);
|
|
EXPECT_TRUE(Visitor.runOver("void f() { []{ []{ return; }; }(); }",
|
|
LambdaExprVisitor::Lang_CXX11));
|
|
EXPECT_TRUE(Visitor.allBodiesHaveBeenTraversed());
|
|
EXPECT_FALSE(Visitor.allClassesHaveBeenTraversed());
|
|
}
|
|
|
|
TEST(RecursiveASTVisitor, TopLevelLambda) {
|
|
LambdaExprVisitor Visitor;
|
|
Visitor.VisitImplicitCode = true;
|
|
Visitor.ExpectMatch("", 1, 10);
|
|
Visitor.ExpectMatch("", 1, 14);
|
|
EXPECT_TRUE(Visitor.runOver("auto x = []{ [] {}; };",
|
|
LambdaExprVisitor::Lang_CXX11));
|
|
EXPECT_TRUE(Visitor.allBodiesHaveBeenTraversed());
|
|
EXPECT_TRUE(Visitor.allClassesHaveBeenTraversed());
|
|
}
|
|
|
|
TEST(RecursiveASTVisitor, VisitsLambdaExprAndImplicitClass) {
|
|
LambdaExprVisitor Visitor;
|
|
Visitor.VisitImplicitCode = true;
|
|
Visitor.ExpectMatch("", 1, 12);
|
|
EXPECT_TRUE(Visitor.runOver("void f() { []{ return; }(); }",
|
|
LambdaExprVisitor::Lang_CXX11));
|
|
EXPECT_TRUE(Visitor.allBodiesHaveBeenTraversed());
|
|
EXPECT_TRUE(Visitor.allClassesHaveBeenTraversed());
|
|
}
|
|
|
|
TEST(RecursiveASTVisitor, VisitsAttributedLambdaExpr) {
|
|
LambdaExprVisitor Visitor;
|
|
Visitor.ExpectMatch("", 1, 12);
|
|
EXPECT_TRUE(Visitor.runOver(
|
|
"void f() { [] () __attribute__ (( fastcall )) { return; }(); }",
|
|
LambdaExprVisitor::Lang_CXX14));
|
|
}
|
|
|
|
} // end anonymous namespace
|