1 | //===- unittest/Tooling/RecursiveASTVisitorTests/LambdaExpr.cpp -----------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "TestVisitor.h" |
10 | #include "llvm/TargetParser/Host.h" |
11 | #include <stack> |
12 | |
13 | using namespace clang; |
14 | |
15 | namespace { |
16 | |
17 | class LambdaExprVisitor : public ExpectedLocationVisitor { |
18 | public: |
19 | LambdaExprVisitor() { ShouldVisitImplicitCode = false; } |
20 | |
21 | bool VisitLambdaExpr(LambdaExpr *Lambda) override { |
22 | PendingBodies.push(x: Lambda->getBody()); |
23 | PendingClasses.push(Lambda->getLambdaClass()); |
24 | Match("" , Lambda->getIntroducerRange().getBegin()); |
25 | return true; |
26 | } |
27 | /// For each call to VisitLambdaExpr, we expect a subsequent call to visit |
28 | /// the body (and maybe the lambda class, which is implicit). |
29 | bool VisitStmt(Stmt *S) override { |
30 | if (!PendingBodies.empty() && S == PendingBodies.top()) |
31 | PendingBodies.pop(); |
32 | return true; |
33 | } |
34 | bool VisitDecl(Decl *D) override { |
35 | if (!PendingClasses.empty() && D == PendingClasses.top()) |
36 | PendingClasses.pop(); |
37 | return true; |
38 | } |
39 | /// Determine whether parts of lambdas (VisitLambdaExpr) were later traversed. |
40 | bool allBodiesHaveBeenTraversed() const { return PendingBodies.empty(); } |
41 | bool allClassesHaveBeenTraversed() const { return PendingClasses.empty(); } |
42 | |
43 | private: |
44 | std::stack<Stmt *> PendingBodies; |
45 | std::stack<Decl *> PendingClasses; |
46 | }; |
47 | |
48 | TEST(RecursiveASTVisitor, VisitsLambdaExpr) { |
49 | LambdaExprVisitor Visitor; |
50 | Visitor.ExpectMatch("" , 1, 12); |
51 | EXPECT_TRUE(Visitor.runOver("void f() { []{ return; }(); }" , |
52 | LambdaExprVisitor::Lang_CXX11)); |
53 | EXPECT_TRUE(Visitor.allBodiesHaveBeenTraversed()); |
54 | EXPECT_FALSE(Visitor.allClassesHaveBeenTraversed()); |
55 | } |
56 | |
57 | TEST(RecursiveASTVisitor, LambdaInLambda) { |
58 | LambdaExprVisitor Visitor; |
59 | Visitor.ExpectMatch("" , 1, 12); |
60 | Visitor.ExpectMatch("" , 1, 16); |
61 | EXPECT_TRUE(Visitor.runOver("void f() { []{ []{ return; }; }(); }" , |
62 | LambdaExprVisitor::Lang_CXX11)); |
63 | EXPECT_TRUE(Visitor.allBodiesHaveBeenTraversed()); |
64 | EXPECT_FALSE(Visitor.allClassesHaveBeenTraversed()); |
65 | } |
66 | |
67 | TEST(RecursiveASTVisitor, TopLevelLambda) { |
68 | LambdaExprVisitor Visitor; |
69 | Visitor.ShouldVisitImplicitCode = true; |
70 | Visitor.ExpectMatch("" , 1, 10); |
71 | Visitor.ExpectMatch("" , 1, 14); |
72 | EXPECT_TRUE(Visitor.runOver("auto x = []{ [] {}; };" , |
73 | LambdaExprVisitor::Lang_CXX11)); |
74 | EXPECT_TRUE(Visitor.allBodiesHaveBeenTraversed()); |
75 | EXPECT_TRUE(Visitor.allClassesHaveBeenTraversed()); |
76 | } |
77 | |
78 | TEST(RecursiveASTVisitor, VisitsLambdaExprAndImplicitClass) { |
79 | LambdaExprVisitor Visitor; |
80 | Visitor.ShouldVisitImplicitCode = true; |
81 | Visitor.ExpectMatch("" , 1, 12); |
82 | EXPECT_TRUE(Visitor.runOver("void f() { []{ return; }(); }" , |
83 | LambdaExprVisitor::Lang_CXX11)); |
84 | EXPECT_TRUE(Visitor.allBodiesHaveBeenTraversed()); |
85 | EXPECT_TRUE(Visitor.allClassesHaveBeenTraversed()); |
86 | } |
87 | |
88 | TEST(RecursiveASTVisitor, VisitsAttributedLambdaExpr) { |
89 | if (llvm::Triple(llvm::sys::getDefaultTargetTriple()).isPS()) |
90 | GTEST_SKIP(); // PS4/PS5 do not support fastcall. |
91 | LambdaExprVisitor Visitor; |
92 | Visitor.ExpectMatch("" , 1, 12); |
93 | EXPECT_TRUE(Visitor.runOver( |
94 | "void f() { [] () __attribute__ (( fastcall )) { return; }(); }" , |
95 | LambdaExprVisitor::Lang_CXX14)); |
96 | } |
97 | |
98 | } // end anonymous namespace |
99 | |