summaryrefslogtreecommitdiffstats
path: root/unittests/Tooling/RecursiveASTVisitorTests/LambdaExpr.cpp
blob: d3a3eba15d166e9e94d566b81d653e2f9f8f4a7a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
//===- unittest/Tooling/RecursiveASTVisitorTests/LambdaExpr.cpp -----------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "TestVisitor.h"
#include <stack>

using namespace clang;

namespace {

class LambdaExprVisitor : public ExpectedLocationVisitor<LambdaExprVisitor> {
public:
  bool VisitLambdaExpr(LambdaExpr *Lambda) {
    PendingBodies.push(Lambda->getBody());
    PendingClasses.push(Lambda->getLambdaClass());
    Match("", Lambda->getIntroducerRange().getBegin());
    return true;
  }
  /// For each call to VisitLambdaExpr, we expect a subsequent call to visit
  /// the body (and maybe the lambda class, which is implicit).
  bool VisitStmt(Stmt *S) {
    if (!PendingBodies.empty() && S == PendingBodies.top())
      PendingBodies.pop();
    return true;
  }
  bool VisitDecl(Decl *D) {
    if (!PendingClasses.empty() && D == PendingClasses.top())
      PendingClasses.pop();
    return true;
  }
  /// Determine whether parts of lambdas (VisitLambdaExpr) were later traversed.
  bool allBodiesHaveBeenTraversed() const { return PendingBodies.empty(); }
  bool allClassesHaveBeenTraversed() const { return PendingClasses.empty(); }

  bool VisitImplicitCode = false;
  bool shouldVisitImplicitCode() const { return VisitImplicitCode; }

private:
  std::stack<Stmt *> PendingBodies;
  std::stack<Decl *> PendingClasses;
};

TEST(RecursiveASTVisitor, VisitsLambdaExpr) {
  LambdaExprVisitor Visitor;
  Visitor.ExpectMatch("", 1, 12);
  EXPECT_TRUE(Visitor.runOver("void f() { []{ return; }(); }",
                              LambdaExprVisitor::Lang_CXX11));
  EXPECT_TRUE(Visitor.allBodiesHaveBeenTraversed());
  EXPECT_FALSE(Visitor.allClassesHaveBeenTraversed());
}

TEST(RecursiveASTVisitor, LambdaInLambda) {
  LambdaExprVisitor Visitor;
  Visitor.ExpectMatch("", 1, 12);
  Visitor.ExpectMatch("", 1, 16);
  EXPECT_TRUE(Visitor.runOver("void f() { []{ []{ return; }; }(); }",
                              LambdaExprVisitor::Lang_CXX11));
  EXPECT_TRUE(Visitor.allBodiesHaveBeenTraversed());
  EXPECT_FALSE(Visitor.allClassesHaveBeenTraversed());
}

TEST(RecursiveASTVisitor, TopLevelLambda) {
  LambdaExprVisitor Visitor;
  Visitor.VisitImplicitCode = true;
  Visitor.ExpectMatch("", 1, 10);
  Visitor.ExpectMatch("", 1, 14);
  EXPECT_TRUE(Visitor.runOver("auto x = []{ [] {}; };",
                              LambdaExprVisitor::Lang_CXX11));
  EXPECT_TRUE(Visitor.allBodiesHaveBeenTraversed());
  EXPECT_TRUE(Visitor.allClassesHaveBeenTraversed());
}

TEST(RecursiveASTVisitor, VisitsLambdaExprAndImplicitClass) {
  LambdaExprVisitor Visitor;
  Visitor.VisitImplicitCode = true;
  Visitor.ExpectMatch("", 1, 12);
  EXPECT_TRUE(Visitor.runOver("void f() { []{ return; }(); }",
                              LambdaExprVisitor::Lang_CXX11));
  EXPECT_TRUE(Visitor.allBodiesHaveBeenTraversed());
  EXPECT_TRUE(Visitor.allClassesHaveBeenTraversed());
}

TEST(RecursiveASTVisitor, VisitsAttributedLambdaExpr) {
  LambdaExprVisitor Visitor;
  Visitor.ExpectMatch("", 1, 12);
  EXPECT_TRUE(Visitor.runOver(
      "void f() { [] () __attribute__ (( fastcall )) { return; }(); }",
      LambdaExprVisitor::Lang_CXX14));
}

} // end anonymous namespace