LambdaExpr.cpp
3.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
//===- unittest/Tooling/RecursiveASTVisitorTests/LambdaExpr.cpp -----------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#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) {
if (llvm::Triple(llvm::sys::getDefaultTargetTriple()).isPS4())
return; // PS4 does not support fastcall.
LambdaExprVisitor Visitor;
Visitor.ExpectMatch("", 1, 12);
EXPECT_TRUE(Visitor.runOver(
"void f() { [] () __attribute__ (( fastcall )) { return; }(); }",
LambdaExprVisitor::Lang_CXX14));
}
} // end anonymous namespace