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: 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). 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("", 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 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 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 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 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