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