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 <stack>
11 
12 using namespace clang;
13 
14 namespace {
15 
16 class LambdaExprVisitor : public ExpectedLocationVisitor<LambdaExprVisitor> {
17 public:
18   bool VisitLambdaExpr(LambdaExpr *Lambda) {
19     PendingBodies.push(Lambda->getBody());
20     PendingClasses.push(Lambda->getLambdaClass());
21     Match("", Lambda->getIntroducerRange().getBegin());
22     return true;
23   }
24   /// For each call to VisitLambdaExpr, we expect a subsequent call to visit
25   /// the body (and maybe the lambda class, which is implicit).
26   bool VisitStmt(Stmt *S) {
27     if (!PendingBodies.empty() && S == PendingBodies.top())
28       PendingBodies.pop();
29     return true;
30   }
31   bool VisitDecl(Decl *D) {
32     if (!PendingClasses.empty() && D == PendingClasses.top())
33       PendingClasses.pop();
34     return true;
35   }
36   /// Determine whether parts of lambdas (VisitLambdaExpr) were later traversed.
37   bool allBodiesHaveBeenTraversed() const { return PendingBodies.empty(); }
38   bool allClassesHaveBeenTraversed() const { return PendingClasses.empty(); }
39 
40   bool VisitImplicitCode = false;
41   bool shouldVisitImplicitCode() const { return VisitImplicitCode; }
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.VisitImplicitCode = 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.VisitImplicitCode = 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()).isPS4())
90     return; // PS4 does 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