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