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<LambdaExprVisitor> { |
18 | public: |
19 | bool VisitLambdaExpr(LambdaExpr *Lambda) { |
20 | PendingBodies.push(x: Lambda->getBody()); |
21 | PendingClasses.push(Lambda->getLambdaClass()); |
22 | Match(Name: "" , Location: Lambda->getIntroducerRange().getBegin()); |
23 | return true; |
24 | } |
25 | /// For each call to VisitLambdaExpr, we expect a subsequent call to visit |
26 | /// the body (and maybe the lambda class, which is implicit). |
27 | bool VisitStmt(Stmt *S) { |
28 | if (!PendingBodies.empty() && S == PendingBodies.top()) |
29 | PendingBodies.pop(); |
30 | return true; |
31 | } |
32 | bool VisitDecl(Decl *D) { |
33 | if (!PendingClasses.empty() && D == PendingClasses.top()) |
34 | PendingClasses.pop(); |
35 | return true; |
36 | } |
37 | /// Determine whether parts of lambdas (VisitLambdaExpr) were later traversed. |
38 | bool allBodiesHaveBeenTraversed() const { return PendingBodies.empty(); } |
39 | bool allClassesHaveBeenTraversed() const { return PendingClasses.empty(); } |
40 | |
41 | bool VisitImplicitCode = false; |
42 | bool shouldVisitImplicitCode() const { return VisitImplicitCode; } |
43 | |
44 | private: |
45 | std::stack<Stmt *> PendingBodies; |
46 | std::stack<Decl *> PendingClasses; |
47 | }; |
48 | |
49 | TEST(RecursiveASTVisitor, VisitsLambdaExpr) { |
50 | LambdaExprVisitor Visitor; |
51 | Visitor.ExpectMatch(Match: "" , Line: 1, Column: 12); |
52 | EXPECT_TRUE(Visitor.runOver("void f() { []{ return; }(); }" , |
53 | LambdaExprVisitor::Lang_CXX11)); |
54 | EXPECT_TRUE(Visitor.allBodiesHaveBeenTraversed()); |
55 | EXPECT_FALSE(Visitor.allClassesHaveBeenTraversed()); |
56 | } |
57 | |
58 | TEST(RecursiveASTVisitor, LambdaInLambda) { |
59 | LambdaExprVisitor Visitor; |
60 | Visitor.ExpectMatch(Match: "" , Line: 1, Column: 12); |
61 | Visitor.ExpectMatch(Match: "" , Line: 1, Column: 16); |
62 | EXPECT_TRUE(Visitor.runOver("void f() { []{ []{ return; }; }(); }" , |
63 | LambdaExprVisitor::Lang_CXX11)); |
64 | EXPECT_TRUE(Visitor.allBodiesHaveBeenTraversed()); |
65 | EXPECT_FALSE(Visitor.allClassesHaveBeenTraversed()); |
66 | } |
67 | |
68 | TEST(RecursiveASTVisitor, TopLevelLambda) { |
69 | LambdaExprVisitor Visitor; |
70 | Visitor.VisitImplicitCode = true; |
71 | Visitor.ExpectMatch(Match: "" , Line: 1, Column: 10); |
72 | Visitor.ExpectMatch(Match: "" , Line: 1, Column: 14); |
73 | EXPECT_TRUE(Visitor.runOver("auto x = []{ [] {}; };" , |
74 | LambdaExprVisitor::Lang_CXX11)); |
75 | EXPECT_TRUE(Visitor.allBodiesHaveBeenTraversed()); |
76 | EXPECT_TRUE(Visitor.allClassesHaveBeenTraversed()); |
77 | } |
78 | |
79 | TEST(RecursiveASTVisitor, VisitsLambdaExprAndImplicitClass) { |
80 | LambdaExprVisitor Visitor; |
81 | Visitor.VisitImplicitCode = true; |
82 | Visitor.ExpectMatch(Match: "" , Line: 1, Column: 12); |
83 | EXPECT_TRUE(Visitor.runOver("void f() { []{ return; }(); }" , |
84 | LambdaExprVisitor::Lang_CXX11)); |
85 | EXPECT_TRUE(Visitor.allBodiesHaveBeenTraversed()); |
86 | EXPECT_TRUE(Visitor.allClassesHaveBeenTraversed()); |
87 | } |
88 | |
89 | TEST(RecursiveASTVisitor, VisitsAttributedLambdaExpr) { |
90 | if (llvm::Triple(llvm::sys::getDefaultTargetTriple()).isPS()) |
91 | GTEST_SKIP(); // PS4/PS5 do not support fastcall. |
92 | LambdaExprVisitor Visitor; |
93 | Visitor.ExpectMatch(Match: "" , Line: 1, Column: 12); |
94 | EXPECT_TRUE(Visitor.runOver( |
95 | "void f() { [] () __attribute__ (( fastcall )) { return; }(); }" , |
96 | LambdaExprVisitor::Lang_CXX14)); |
97 | } |
98 | |
99 | } // end anonymous namespace |
100 | |