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