1*67e74705SXin Li //===- unittest/Tooling/RecursiveASTVisitorTest.cpp -----------------------===//
2*67e74705SXin Li //
3*67e74705SXin Li // The LLVM Compiler Infrastructure
4*67e74705SXin Li //
5*67e74705SXin Li // This file is distributed under the University of Illinois Open Source
6*67e74705SXin Li // License. See LICENSE.TXT for details.
7*67e74705SXin Li //
8*67e74705SXin Li //===----------------------------------------------------------------------===//
9*67e74705SXin Li
10*67e74705SXin Li #include "TestVisitor.h"
11*67e74705SXin Li #include <stack>
12*67e74705SXin Li
13*67e74705SXin Li using namespace clang;
14*67e74705SXin Li
15*67e74705SXin Li namespace {
16*67e74705SXin Li
17*67e74705SXin Li class LambdaExprVisitor : public ExpectedLocationVisitor<LambdaExprVisitor> {
18*67e74705SXin Li public:
VisitLambdaExpr(LambdaExpr * Lambda)19*67e74705SXin Li bool VisitLambdaExpr(LambdaExpr *Lambda) {
20*67e74705SXin Li PendingBodies.push(Lambda);
21*67e74705SXin Li Match("", Lambda->getIntroducerRange().getBegin());
22*67e74705SXin Li return true;
23*67e74705SXin Li }
24*67e74705SXin Li /// For each call to VisitLambdaExpr, we expect a subsequent call (with
25*67e74705SXin Li /// proper nesting) to TraverseLambdaBody.
TraverseLambdaBody(LambdaExpr * Lambda)26*67e74705SXin Li bool TraverseLambdaBody(LambdaExpr *Lambda) {
27*67e74705SXin Li EXPECT_FALSE(PendingBodies.empty());
28*67e74705SXin Li EXPECT_EQ(PendingBodies.top(), Lambda);
29*67e74705SXin Li PendingBodies.pop();
30*67e74705SXin Li return TraverseStmt(Lambda->getBody());
31*67e74705SXin Li }
32*67e74705SXin Li /// Determine whether TraverseLambdaBody has been called for every call to
33*67e74705SXin Li /// VisitLambdaExpr.
allBodiesHaveBeenTraversed() const34*67e74705SXin Li bool allBodiesHaveBeenTraversed() const {
35*67e74705SXin Li return PendingBodies.empty();
36*67e74705SXin Li }
37*67e74705SXin Li private:
38*67e74705SXin Li std::stack<LambdaExpr *> PendingBodies;
39*67e74705SXin Li };
40*67e74705SXin Li
TEST(RecursiveASTVisitor,VisitsLambdaExpr)41*67e74705SXin Li TEST(RecursiveASTVisitor, VisitsLambdaExpr) {
42*67e74705SXin Li LambdaExprVisitor Visitor;
43*67e74705SXin Li Visitor.ExpectMatch("", 1, 12);
44*67e74705SXin Li EXPECT_TRUE(Visitor.runOver("void f() { []{ return; }(); }",
45*67e74705SXin Li LambdaExprVisitor::Lang_CXX11));
46*67e74705SXin Li }
47*67e74705SXin Li
TEST(RecursiveASTVisitor,TraverseLambdaBodyCanBeOverridden)48*67e74705SXin Li TEST(RecursiveASTVisitor, TraverseLambdaBodyCanBeOverridden) {
49*67e74705SXin Li LambdaExprVisitor Visitor;
50*67e74705SXin Li EXPECT_TRUE(Visitor.runOver("void f() { []{ return; }(); }",
51*67e74705SXin Li LambdaExprVisitor::Lang_CXX11));
52*67e74705SXin Li EXPECT_TRUE(Visitor.allBodiesHaveBeenTraversed());
53*67e74705SXin Li }
54*67e74705SXin Li
55*67e74705SXin Li // Matches the (optional) capture-default of a lambda-introducer.
56*67e74705SXin Li class LambdaDefaultCaptureVisitor
57*67e74705SXin Li : public ExpectedLocationVisitor<LambdaDefaultCaptureVisitor> {
58*67e74705SXin Li public:
VisitLambdaExpr(LambdaExpr * Lambda)59*67e74705SXin Li bool VisitLambdaExpr(LambdaExpr *Lambda) {
60*67e74705SXin Li if (Lambda->getCaptureDefault() != LCD_None) {
61*67e74705SXin Li Match("", Lambda->getCaptureDefaultLoc());
62*67e74705SXin Li }
63*67e74705SXin Li return true;
64*67e74705SXin Li }
65*67e74705SXin Li };
66*67e74705SXin Li
TEST(RecursiveASTVisitor,HasCaptureDefaultLoc)67*67e74705SXin Li TEST(RecursiveASTVisitor, HasCaptureDefaultLoc) {
68*67e74705SXin Li LambdaDefaultCaptureVisitor Visitor;
69*67e74705SXin Li Visitor.ExpectMatch("", 1, 20);
70*67e74705SXin Li EXPECT_TRUE(Visitor.runOver("void f() { int a; [=]{a;}; }",
71*67e74705SXin Li LambdaDefaultCaptureVisitor::Lang_CXX11));
72*67e74705SXin Li }
73*67e74705SXin Li
74*67e74705SXin Li // Checks for lambda classes that are not marked as implicitly-generated.
75*67e74705SXin Li // (There should be none.)
76*67e74705SXin Li class ClassVisitor : public ExpectedLocationVisitor<ClassVisitor> {
77*67e74705SXin Li public:
ClassVisitor()78*67e74705SXin Li ClassVisitor() : SawNonImplicitLambdaClass(false) {}
VisitCXXRecordDecl(CXXRecordDecl * record)79*67e74705SXin Li bool VisitCXXRecordDecl(CXXRecordDecl* record) {
80*67e74705SXin Li if (record->isLambda() && !record->isImplicit())
81*67e74705SXin Li SawNonImplicitLambdaClass = true;
82*67e74705SXin Li return true;
83*67e74705SXin Li }
84*67e74705SXin Li
sawOnlyImplicitLambdaClasses() const85*67e74705SXin Li bool sawOnlyImplicitLambdaClasses() const {
86*67e74705SXin Li return !SawNonImplicitLambdaClass;
87*67e74705SXin Li }
88*67e74705SXin Li
89*67e74705SXin Li private:
90*67e74705SXin Li bool SawNonImplicitLambdaClass;
91*67e74705SXin Li };
92*67e74705SXin Li
TEST(RecursiveASTVisitor,LambdaClosureTypesAreImplicit)93*67e74705SXin Li TEST(RecursiveASTVisitor, LambdaClosureTypesAreImplicit) {
94*67e74705SXin Li ClassVisitor Visitor;
95*67e74705SXin Li EXPECT_TRUE(Visitor.runOver("auto lambda = []{};", ClassVisitor::Lang_CXX11));
96*67e74705SXin Li EXPECT_TRUE(Visitor.sawOnlyImplicitLambdaClasses());
97*67e74705SXin Li }
98*67e74705SXin Li
99*67e74705SXin Li
100*67e74705SXin Li // Check to ensure that attributes and expressions within them are being
101*67e74705SXin Li // visited.
102*67e74705SXin Li class AttrVisitor : public ExpectedLocationVisitor<AttrVisitor> {
103*67e74705SXin Li public:
VisitMemberExpr(MemberExpr * ME)104*67e74705SXin Li bool VisitMemberExpr(MemberExpr *ME) {
105*67e74705SXin Li Match(ME->getMemberDecl()->getNameAsString(), ME->getLocStart());
106*67e74705SXin Li return true;
107*67e74705SXin Li }
VisitAttr(Attr * A)108*67e74705SXin Li bool VisitAttr(Attr *A) {
109*67e74705SXin Li Match("Attr", A->getLocation());
110*67e74705SXin Li return true;
111*67e74705SXin Li }
VisitGuardedByAttr(GuardedByAttr * A)112*67e74705SXin Li bool VisitGuardedByAttr(GuardedByAttr *A) {
113*67e74705SXin Li Match("guarded_by", A->getLocation());
114*67e74705SXin Li return true;
115*67e74705SXin Li }
116*67e74705SXin Li };
117*67e74705SXin Li
118*67e74705SXin Li
TEST(RecursiveASTVisitor,AttributesAreVisited)119*67e74705SXin Li TEST(RecursiveASTVisitor, AttributesAreVisited) {
120*67e74705SXin Li AttrVisitor Visitor;
121*67e74705SXin Li Visitor.ExpectMatch("Attr", 4, 24);
122*67e74705SXin Li Visitor.ExpectMatch("guarded_by", 4, 24);
123*67e74705SXin Li Visitor.ExpectMatch("mu1", 4, 35);
124*67e74705SXin Li Visitor.ExpectMatch("Attr", 5, 29);
125*67e74705SXin Li Visitor.ExpectMatch("mu1", 5, 54);
126*67e74705SXin Li Visitor.ExpectMatch("mu2", 5, 59);
127*67e74705SXin Li EXPECT_TRUE(Visitor.runOver(
128*67e74705SXin Li "class Foo {\n"
129*67e74705SXin Li " int mu1;\n"
130*67e74705SXin Li " int mu2;\n"
131*67e74705SXin Li " int a __attribute__((guarded_by(mu1)));\n"
132*67e74705SXin Li " void bar() __attribute__((exclusive_locks_required(mu1, mu2)));\n"
133*67e74705SXin Li "};\n"));
134*67e74705SXin Li }
135*67e74705SXin Li
136*67e74705SXin Li // Check to ensure that VarDecls are visited.
137*67e74705SXin Li class VarDeclVisitor : public ExpectedLocationVisitor<VarDeclVisitor> {
138*67e74705SXin Li public:
VisitVarDecl(VarDecl * VD)139*67e74705SXin Li bool VisitVarDecl(VarDecl *VD) {
140*67e74705SXin Li Match(VD->getNameAsString(), VD->getLocStart());
141*67e74705SXin Li return true;
142*67e74705SXin Li }
143*67e74705SXin Li };
144*67e74705SXin Li
TEST(RecursiveASTVisitor,ArrayInitializersAreVisited)145*67e74705SXin Li TEST(RecursiveASTVisitor, ArrayInitializersAreVisited) {
146*67e74705SXin Li VarDeclVisitor Visitor;
147*67e74705SXin Li Visitor.ExpectMatch("__i0", 1, 8);
148*67e74705SXin Li EXPECT_TRUE(
149*67e74705SXin Li Visitor.runOver("struct MyClass {\n"
150*67e74705SXin Li " int c[1];\n"
151*67e74705SXin Li " static MyClass Create() { return MyClass(); }\n"
152*67e74705SXin Li "};\n"));
153*67e74705SXin Li }
154*67e74705SXin Li
155*67e74705SXin Li } // end anonymous namespace
156