Clang Project

clang_source_code/unittests/Tooling/RecursiveASTVisitorTests/LambdaExpr.cpp
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
12using namespace clang;
13
14namespace {
15
16class LambdaExprVisitor : public ExpectedLocationVisitor<LambdaExprVisitor> {
17public:
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
43private:
44  std::stack<Stmt *> PendingBodies;
45  std::stack<Decl *> PendingClasses;
46};
47
48TEST(RecursiveASTVisitor, VisitsLambdaExpr) {
49  LambdaExprVisitor Visitor;
50  Visitor.ExpectMatch(""112);
51  EXPECT_TRUE(Visitor.runOver("void f() { []{ return; }(); }",
52                              LambdaExprVisitor::Lang_CXX11));
53  EXPECT_TRUE(Visitor.allBodiesHaveBeenTraversed());
54  EXPECT_FALSE(Visitor.allClassesHaveBeenTraversed());
55}
56
57TEST(RecursiveASTVisitor, LambdaInLambda) {
58  LambdaExprVisitor Visitor;
59  Visitor.ExpectMatch(""112);
60  Visitor.ExpectMatch(""116);
61  EXPECT_TRUE(Visitor.runOver("void f() { []{ []{ return; }; }(); }",
62                              LambdaExprVisitor::Lang_CXX11));
63  EXPECT_TRUE(Visitor.allBodiesHaveBeenTraversed());
64  EXPECT_FALSE(Visitor.allClassesHaveBeenTraversed());
65}
66
67TEST(RecursiveASTVisitor, TopLevelLambda) {
68  LambdaExprVisitor Visitor;
69  Visitor.VisitImplicitCode = true;
70  Visitor.ExpectMatch(""110);
71  Visitor.ExpectMatch(""114);
72  EXPECT_TRUE(Visitor.runOver("auto x = []{ [] {}; };",
73                              LambdaExprVisitor::Lang_CXX11));
74  EXPECT_TRUE(Visitor.allBodiesHaveBeenTraversed());
75  EXPECT_TRUE(Visitor.allClassesHaveBeenTraversed());
76}
77
78TEST(RecursiveASTVisitor, VisitsLambdaExprAndImplicitClass) {
79  LambdaExprVisitor Visitor;
80  Visitor.VisitImplicitCode = true;
81  Visitor.ExpectMatch(""112);
82  EXPECT_TRUE(Visitor.runOver("void f() { []{ return; }(); }",
83                              LambdaExprVisitor::Lang_CXX11));
84  EXPECT_TRUE(Visitor.allBodiesHaveBeenTraversed());
85  EXPECT_TRUE(Visitor.allClassesHaveBeenTraversed());
86}
87
88TEST(RecursiveASTVisitor, VisitsAttributedLambdaExpr) {
89  LambdaExprVisitor Visitor;
90  Visitor.ExpectMatch(""112);
91  EXPECT_TRUE(Visitor.runOver(
92      "void f() { [] () __attribute__ (( fastcall )) { return; }(); }",
93      LambdaExprVisitor::Lang_CXX14));
94}
95
96// end anonymous namespace
97