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