xref: /llvm-project/clang/unittests/Tooling/RecursiveASTVisitorTests/LambdaExpr.cpp (revision 4e600751d2f7e8e7b85a71b7128b68444bdde91b)
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(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