• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 = []{};", ClassVisitor::Lang_CXX11));
96   EXPECT_TRUE(Visitor.sawOnlyImplicitLambdaClasses());
97 }
98 
99 
100 // Check to ensure that attributes and expressions within them are being
101 // visited.
102 class AttrVisitor : public ExpectedLocationVisitor<AttrVisitor> {
103 public:
VisitMemberExpr(MemberExpr * ME)104   bool VisitMemberExpr(MemberExpr *ME) {
105     Match(ME->getMemberDecl()->getNameAsString(), ME->getLocStart());
106     return true;
107   }
VisitAttr(Attr * A)108   bool VisitAttr(Attr *A) {
109     Match("Attr", A->getLocation());
110     return true;
111   }
VisitGuardedByAttr(GuardedByAttr * A)112   bool VisitGuardedByAttr(GuardedByAttr *A) {
113     Match("guarded_by", A->getLocation());
114     return true;
115   }
116 };
117 
118 
TEST(RecursiveASTVisitor,AttributesAreVisited)119 TEST(RecursiveASTVisitor, AttributesAreVisited) {
120   AttrVisitor Visitor;
121   Visitor.ExpectMatch("Attr", 4, 24);
122   Visitor.ExpectMatch("guarded_by", 4, 24);
123   Visitor.ExpectMatch("mu1",  4, 35);
124   Visitor.ExpectMatch("Attr", 5, 29);
125   Visitor.ExpectMatch("mu1",  5, 54);
126   Visitor.ExpectMatch("mu2",  5, 59);
127   EXPECT_TRUE(Visitor.runOver(
128     "class Foo {\n"
129     "  int mu1;\n"
130     "  int mu2;\n"
131     "  int a __attribute__((guarded_by(mu1)));\n"
132     "  void bar() __attribute__((exclusive_locks_required(mu1, mu2)));\n"
133     "};\n"));
134 }
135 
136 // Check to ensure that VarDecls are visited.
137 class VarDeclVisitor : public ExpectedLocationVisitor<VarDeclVisitor> {
138 public:
VisitVarDecl(VarDecl * VD)139   bool VisitVarDecl(VarDecl *VD) {
140     Match(VD->getNameAsString(), VD->getLocStart());
141     return true;
142   }
143 };
144 
TEST(RecursiveASTVisitor,ArrayInitializersAreVisited)145 TEST(RecursiveASTVisitor, ArrayInitializersAreVisited) {
146   VarDeclVisitor Visitor;
147   Visitor.ExpectMatch("__i0", 1, 8);
148   EXPECT_TRUE(
149       Visitor.runOver("struct MyClass {\n"
150                       "  int c[1];\n"
151                       "  static MyClass Create() { return MyClass(); }\n"
152                       "};\n"));
153 }
154 
155 } // end anonymous namespace
156