• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===- unittest/Tooling/RecursiveASTVisitorTestExprVisitor.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 ParenExprVisitor : public ExpectedLocationVisitor<ParenExprVisitor> {
18 public:
VisitParenExpr(ParenExpr * Parens)19   bool VisitParenExpr(ParenExpr *Parens) {
20     Match("", Parens->getExprLoc());
21     return true;
22   }
23 };
24 
TEST(RecursiveASTVisitor,VisitsParensDuringDataRecursion)25 TEST(RecursiveASTVisitor, VisitsParensDuringDataRecursion) {
26   ParenExprVisitor Visitor;
27   Visitor.ExpectMatch("", 1, 9);
28   EXPECT_TRUE(Visitor.runOver("int k = (4) + 9;\n"));
29 }
30 
31 class TemplateArgumentLocTraverser
32   : public ExpectedLocationVisitor<TemplateArgumentLocTraverser> {
33 public:
TraverseTemplateArgumentLoc(const TemplateArgumentLoc & ArgLoc)34   bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc) {
35     std::string ArgStr;
36     llvm::raw_string_ostream Stream(ArgStr);
37     const TemplateArgument &Arg = ArgLoc.getArgument();
38 
39     Arg.print(Context->getPrintingPolicy(), Stream);
40     Match(Stream.str(), ArgLoc.getLocation());
41     return ExpectedLocationVisitor<TemplateArgumentLocTraverser>::
42       TraverseTemplateArgumentLoc(ArgLoc);
43   }
44 };
45 
TEST(RecursiveASTVisitor,VisitsClassTemplateTemplateParmDefaultArgument)46 TEST(RecursiveASTVisitor, VisitsClassTemplateTemplateParmDefaultArgument) {
47   TemplateArgumentLocTraverser Visitor;
48   Visitor.ExpectMatch("X", 2, 40);
49   EXPECT_TRUE(Visitor.runOver(
50     "template<typename T> class X;\n"
51     "template<template <typename> class T = X> class Y;\n"
52     "template<template <typename> class T> class Y {};\n"));
53 }
54 
55 class CXXBoolLiteralExprVisitor
56   : public ExpectedLocationVisitor<CXXBoolLiteralExprVisitor> {
57 public:
VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr * BE)58   bool VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *BE) {
59     if (BE->getValue())
60       Match("true", BE->getLocation());
61     else
62       Match("false", BE->getLocation());
63     return true;
64   }
65 };
66 
TEST(RecursiveASTVisitor,VisitsClassTemplateNonTypeParmDefaultArgument)67 TEST(RecursiveASTVisitor, VisitsClassTemplateNonTypeParmDefaultArgument) {
68   CXXBoolLiteralExprVisitor Visitor;
69   Visitor.ExpectMatch("true", 2, 19);
70   EXPECT_TRUE(Visitor.runOver(
71     "template<bool B> class X;\n"
72     "template<bool B = true> class Y;\n"
73     "template<bool B> class Y {};\n"));
74 }
75 
76 // A visitor that visits implicit declarations and matches constructors.
77 class ImplicitCtorVisitor
78     : public ExpectedLocationVisitor<ImplicitCtorVisitor> {
79 public:
shouldVisitImplicitCode() const80   bool shouldVisitImplicitCode() const { return true; }
81 
VisitCXXConstructorDecl(CXXConstructorDecl * Ctor)82   bool VisitCXXConstructorDecl(CXXConstructorDecl* Ctor) {
83     if (Ctor->isImplicit()) {  // Was not written in source code
84       if (const CXXRecordDecl* Class = Ctor->getParent()) {
85         Match(Class->getName(), Ctor->getLocation());
86       }
87     }
88     return true;
89   }
90 };
91 
TEST(RecursiveASTVisitor,VisitsImplicitCopyConstructors)92 TEST(RecursiveASTVisitor, VisitsImplicitCopyConstructors) {
93   ImplicitCtorVisitor Visitor;
94   Visitor.ExpectMatch("Simple", 2, 8);
95   // Note: Clang lazily instantiates implicit declarations, so we need
96   // to use them in order to force them to appear in the AST.
97   EXPECT_TRUE(Visitor.runOver(
98       "struct WithCtor { WithCtor(); }; \n"
99       "struct Simple { Simple(); WithCtor w; }; \n"
100       "int main() { Simple s; Simple t(s); }\n"));
101 }
102 
103 /// \brief A visitor that optionally includes implicit code and matches
104 /// CXXConstructExpr.
105 ///
106 /// The name recorded for the match is the name of the class whose constructor
107 /// is invoked by the CXXConstructExpr, not the name of the class whose
108 /// constructor the CXXConstructExpr is contained in.
109 class ConstructExprVisitor
110     : public ExpectedLocationVisitor<ConstructExprVisitor> {
111 public:
ConstructExprVisitor()112   ConstructExprVisitor() : ShouldVisitImplicitCode(false) {}
113 
shouldVisitImplicitCode() const114   bool shouldVisitImplicitCode() const { return ShouldVisitImplicitCode; }
115 
setShouldVisitImplicitCode(bool NewValue)116   void setShouldVisitImplicitCode(bool NewValue) {
117     ShouldVisitImplicitCode = NewValue;
118   }
119 
VisitCXXConstructExpr(CXXConstructExpr * Expr)120   bool VisitCXXConstructExpr(CXXConstructExpr* Expr) {
121     if (const CXXConstructorDecl* Ctor = Expr->getConstructor()) {
122       if (const CXXRecordDecl* Class = Ctor->getParent()) {
123         Match(Class->getName(), Expr->getLocation());
124       }
125     }
126     return true;
127   }
128 
129  private:
130   bool ShouldVisitImplicitCode;
131 };
132 
TEST(RecursiveASTVisitor,CanVisitImplicitMemberInitializations)133 TEST(RecursiveASTVisitor, CanVisitImplicitMemberInitializations) {
134   ConstructExprVisitor Visitor;
135   Visitor.setShouldVisitImplicitCode(true);
136   Visitor.ExpectMatch("WithCtor", 2, 8);
137   // Simple has a constructor that implicitly initializes 'w'.  Test
138   // that a visitor that visits implicit code visits that initialization.
139   // Note: Clang lazily instantiates implicit declarations, so we need
140   // to use them in order to force them to appear in the AST.
141   EXPECT_TRUE(Visitor.runOver(
142       "struct WithCtor { WithCtor(); }; \n"
143       "struct Simple { WithCtor w; }; \n"
144       "int main() { Simple s; }\n"));
145 }
146 
147 // The same as CanVisitImplicitMemberInitializations, but checking that the
148 // visits are omitted when the visitor does not include implicit code.
TEST(RecursiveASTVisitor,CanSkipImplicitMemberInitializations)149 TEST(RecursiveASTVisitor, CanSkipImplicitMemberInitializations) {
150   ConstructExprVisitor Visitor;
151   Visitor.setShouldVisitImplicitCode(false);
152   Visitor.DisallowMatch("WithCtor", 2, 8);
153   // Simple has a constructor that implicitly initializes 'w'.  Test
154   // that a visitor that skips implicit code skips that initialization.
155   // Note: Clang lazily instantiates implicit declarations, so we need
156   // to use them in order to force them to appear in the AST.
157   EXPECT_TRUE(Visitor.runOver(
158       "struct WithCtor { WithCtor(); }; \n"
159       "struct Simple { WithCtor w; }; \n"
160       "int main() { Simple s; }\n"));
161 }
162 
163 class DeclRefExprVisitor : public ExpectedLocationVisitor<DeclRefExprVisitor> {
164 public:
VisitDeclRefExpr(DeclRefExpr * Reference)165   bool VisitDeclRefExpr(DeclRefExpr *Reference) {
166     Match(Reference->getNameInfo().getAsString(), Reference->getLocation());
167     return true;
168   }
169 };
170 
TEST(RecursiveASTVisitor,VisitsBaseClassTemplateArguments)171 TEST(RecursiveASTVisitor, VisitsBaseClassTemplateArguments) {
172   DeclRefExprVisitor Visitor;
173   Visitor.ExpectMatch("x", 2, 3);
174   EXPECT_TRUE(Visitor.runOver(
175     "void x(); template <void (*T)()> class X {};\nX<x> y;"));
176 }
177 
TEST(RecursiveASTVisitor,VisitsCXXForRangeStmtRange)178 TEST(RecursiveASTVisitor, VisitsCXXForRangeStmtRange) {
179   DeclRefExprVisitor Visitor;
180   Visitor.ExpectMatch("x", 2, 25);
181   Visitor.ExpectMatch("x", 2, 30);
182   EXPECT_TRUE(Visitor.runOver(
183     "int x[5];\n"
184     "void f() { for (int i : x) { x[0] = 1; } }",
185     DeclRefExprVisitor::Lang_CXX11));
186 }
187 
TEST(RecursiveASTVisitor,VisitsCallExpr)188 TEST(RecursiveASTVisitor, VisitsCallExpr) {
189   DeclRefExprVisitor Visitor;
190   Visitor.ExpectMatch("x", 1, 22);
191   EXPECT_TRUE(Visitor.runOver(
192     "void x(); void y() { x(); }"));
193 }
194 
195 /* FIXME: According to Richard Smith this is a bug in the AST.
196 TEST(RecursiveASTVisitor, VisitsBaseClassTemplateArgumentsInInstantiation) {
197   DeclRefExprVisitor Visitor;
198   Visitor.ExpectMatch("x", 3, 43);
199   EXPECT_TRUE(Visitor.runOver(
200     "template <typename T> void x();\n"
201     "template <void (*T)()> class X {};\n"
202     "template <typename T> class Y : public X< x<T> > {};\n"
203     "Y<int> y;"));
204 }
205 */
206 
TEST(RecursiveASTVisitor,VisitsExtension)207 TEST(RecursiveASTVisitor, VisitsExtension) {
208   DeclRefExprVisitor Visitor;
209   Visitor.ExpectMatch("s", 1, 24);
210   EXPECT_TRUE(Visitor.runOver(
211     "int s = __extension__ (s);\n"));
212 }
213 
TEST(RecursiveASTVisitor,VisitsCopyExprOfBlockDeclCapture)214 TEST(RecursiveASTVisitor, VisitsCopyExprOfBlockDeclCapture) {
215   DeclRefExprVisitor Visitor;
216   Visitor.ExpectMatch("x", 3, 24);
217   EXPECT_TRUE(Visitor.runOver("void f(int(^)(int)); \n"
218                               "void g() { \n"
219                               "  f([&](int x){ return x; }); \n"
220                               "}",
221                               DeclRefExprVisitor::Lang_OBJCXX11));
222 }
223 
224 } // end anonymous namespace
225