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/Support/Host.h"
11 #include <stack>
12 
13 using namespace clang;
14 
15 namespace {
16 
17 class LambdaExprVisitor : public ExpectedLocationVisitor<LambdaExprVisitor> {
18 public:
VisitLambdaExpr(LambdaExpr * Lambda)19   bool VisitLambdaExpr(LambdaExpr *Lambda) {
20     PendingBodies.push(Lambda->getBody());
21     PendingClasses.push(Lambda->getLambdaClass());
22     Match("", 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).
VisitStmt(Stmt * S)27   bool VisitStmt(Stmt *S) {
28     if (!PendingBodies.empty() && S == PendingBodies.top())
29       PendingBodies.pop();
30     return true;
31   }
VisitDecl(Decl * D)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.
allBodiesHaveBeenTraversed() const38   bool allBodiesHaveBeenTraversed() const { return PendingBodies.empty(); }
allClassesHaveBeenTraversed() const39   bool allClassesHaveBeenTraversed() const { return PendingClasses.empty(); }
40 
41   bool VisitImplicitCode = false;
shouldVisitImplicitCode() const42   bool shouldVisitImplicitCode() const { return VisitImplicitCode; }
43 
44 private:
45   std::stack<Stmt *> PendingBodies;
46   std::stack<Decl *> PendingClasses;
47 };
48 
TEST(RecursiveASTVisitor,VisitsLambdaExpr)49 TEST(RecursiveASTVisitor, VisitsLambdaExpr) {
50   LambdaExprVisitor Visitor;
51   Visitor.ExpectMatch("", 1, 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 
TEST(RecursiveASTVisitor,LambdaInLambda)58 TEST(RecursiveASTVisitor, LambdaInLambda) {
59   LambdaExprVisitor Visitor;
60   Visitor.ExpectMatch("", 1, 12);
61   Visitor.ExpectMatch("", 1, 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 
TEST(RecursiveASTVisitor,TopLevelLambda)68 TEST(RecursiveASTVisitor, TopLevelLambda) {
69   LambdaExprVisitor Visitor;
70   Visitor.VisitImplicitCode = true;
71   Visitor.ExpectMatch("", 1, 10);
72   Visitor.ExpectMatch("", 1, 14);
73   EXPECT_TRUE(Visitor.runOver("auto x = []{ [] {}; };",
74                               LambdaExprVisitor::Lang_CXX11));
75   EXPECT_TRUE(Visitor.allBodiesHaveBeenTraversed());
76   EXPECT_TRUE(Visitor.allClassesHaveBeenTraversed());
77 }
78 
TEST(RecursiveASTVisitor,VisitsLambdaExprAndImplicitClass)79 TEST(RecursiveASTVisitor, VisitsLambdaExprAndImplicitClass) {
80   LambdaExprVisitor Visitor;
81   Visitor.VisitImplicitCode = true;
82   Visitor.ExpectMatch("", 1, 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 
TEST(RecursiveASTVisitor,VisitsAttributedLambdaExpr)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("", 1, 12);
94   EXPECT_TRUE(Visitor.runOver(
95       "void f() { [] () __attribute__ (( fastcall )) { return; }(); }",
96       LambdaExprVisitor::Lang_CXX14));
97 }
98 
99 } // end anonymous namespace
100