• 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 
12 namespace clang {
13 
14 class TypeLocVisitor : public ExpectedLocationVisitor<TypeLocVisitor> {
15 public:
VisitTypeLoc(TypeLoc TypeLocation)16   bool VisitTypeLoc(TypeLoc TypeLocation) {
17     Match(TypeLocation.getType().getAsString(), TypeLocation.getBeginLoc());
18     return true;
19   }
20 };
21 
22 class DeclRefExprVisitor : public ExpectedLocationVisitor<DeclRefExprVisitor> {
23 public:
VisitDeclRefExpr(DeclRefExpr * Reference)24   bool VisitDeclRefExpr(DeclRefExpr *Reference) {
25     Match(Reference->getNameInfo().getAsString(), Reference->getLocation());
26     return true;
27   }
28 };
29 
30 class VarDeclVisitor : public ExpectedLocationVisitor<VarDeclVisitor> {
31 public:
VisitVarDecl(VarDecl * Variable)32  bool VisitVarDecl(VarDecl *Variable) {
33    Match(Variable->getNameAsString(), Variable->getLocStart());
34    return true;
35  }
36 };
37 
38 class CXXMemberCallVisitor
39   : public ExpectedLocationVisitor<CXXMemberCallVisitor> {
40 public:
VisitCXXMemberCallExpr(CXXMemberCallExpr * Call)41   bool VisitCXXMemberCallExpr(CXXMemberCallExpr *Call) {
42     Match(Call->getMethodDecl()->getQualifiedNameAsString(),
43           Call->getLocStart());
44     return true;
45   }
46 };
47 
48 class NamedDeclVisitor
49   : public ExpectedLocationVisitor<NamedDeclVisitor> {
50 public:
VisitNamedDecl(NamedDecl * Decl)51   bool VisitNamedDecl(NamedDecl *Decl) {
52     std::string NameWithTemplateArgs;
53     Decl->getNameForDiagnostic(NameWithTemplateArgs,
54                                Decl->getASTContext().getPrintingPolicy(),
55                                true);
56     Match(NameWithTemplateArgs, Decl->getLocation());
57     return true;
58   }
59 };
60 
61 class CXXOperatorCallExprTraverser
62   : public ExpectedLocationVisitor<CXXOperatorCallExprTraverser> {
63 public:
64   // Use Traverse, not Visit, to check that data recursion optimization isn't
65   // bypassing the call of this function.
TraverseCXXOperatorCallExpr(CXXOperatorCallExpr * CE)66   bool TraverseCXXOperatorCallExpr(CXXOperatorCallExpr *CE) {
67     Match(getOperatorSpelling(CE->getOperator()), CE->getExprLoc());
68     return ExpectedLocationVisitor<CXXOperatorCallExprTraverser>::
69         TraverseCXXOperatorCallExpr(CE);
70   }
71 };
72 
73 class ParenExprVisitor : public ExpectedLocationVisitor<ParenExprVisitor> {
74 public:
VisitParenExpr(ParenExpr * Parens)75   bool VisitParenExpr(ParenExpr *Parens) {
76     Match("", Parens->getExprLoc());
77     return true;
78   }
79 };
80 
81 class TemplateArgumentLocTraverser
82   : public ExpectedLocationVisitor<TemplateArgumentLocTraverser> {
83 public:
TraverseTemplateArgumentLoc(const TemplateArgumentLoc & ArgLoc)84   bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc) {
85     std::string ArgStr;
86     llvm::raw_string_ostream Stream(ArgStr);
87     const TemplateArgument &Arg = ArgLoc.getArgument();
88 
89     Arg.print(Context->getPrintingPolicy(), Stream);
90     Match(Stream.str(), ArgLoc.getLocation());
91     return ExpectedLocationVisitor<TemplateArgumentLocTraverser>::
92       TraverseTemplateArgumentLoc(ArgLoc);
93   }
94 };
95 
96 class CXXBoolLiteralExprVisitor
97   : public ExpectedLocationVisitor<CXXBoolLiteralExprVisitor> {
98 public:
VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr * BE)99   bool VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *BE) {
100     if (BE->getValue())
101       Match("true", BE->getLocation());
102     else
103       Match("false", BE->getLocation());
104     return true;
105   }
106 };
107 
TEST(RecursiveASTVisitor,VisitsBaseClassDeclarations)108 TEST(RecursiveASTVisitor, VisitsBaseClassDeclarations) {
109   TypeLocVisitor Visitor;
110   Visitor.ExpectMatch("class X", 1, 30);
111   EXPECT_TRUE(Visitor.runOver("class X {}; class Y : public X {};"));
112 }
113 
TEST(RecursiveASTVisitor,VisitsCXXBaseSpecifiersOfForwardDeclaredClass)114 TEST(RecursiveASTVisitor, VisitsCXXBaseSpecifiersOfForwardDeclaredClass) {
115   TypeLocVisitor Visitor;
116   Visitor.ExpectMatch("class X", 3, 18);
117   EXPECT_TRUE(Visitor.runOver(
118     "class Y;\n"
119     "class X {};\n"
120     "class Y : public X {};"));
121 }
122 
TEST(RecursiveASTVisitor,VisitsCXXBaseSpecifiersWithIncompleteInnerClass)123 TEST(RecursiveASTVisitor, VisitsCXXBaseSpecifiersWithIncompleteInnerClass) {
124   TypeLocVisitor Visitor;
125   Visitor.ExpectMatch("class X", 2, 18);
126   EXPECT_TRUE(Visitor.runOver(
127     "class X {};\n"
128     "class Y : public X { class Z; };"));
129 }
130 
TEST(RecursiveASTVisitor,VisitsCXXBaseSpecifiersOfSelfReferentialType)131 TEST(RecursiveASTVisitor, VisitsCXXBaseSpecifiersOfSelfReferentialType) {
132   TypeLocVisitor Visitor;
133   Visitor.ExpectMatch("X<class Y>", 2, 18);
134   EXPECT_TRUE(Visitor.runOver(
135     "template<typename T> class X {};\n"
136     "class Y : public X<Y> {};"));
137 }
138 
TEST(RecursiveASTVisitor,VisitsBaseClassTemplateArguments)139 TEST(RecursiveASTVisitor, VisitsBaseClassTemplateArguments) {
140   DeclRefExprVisitor Visitor;
141   Visitor.ExpectMatch("x", 2, 3);
142   EXPECT_TRUE(Visitor.runOver(
143     "void x(); template <void (*T)()> class X {};\nX<x> y;"));
144 }
145 
TEST(RecursiveASTVisitor,VisitsCXXForRangeStmtRange)146 TEST(RecursiveASTVisitor, VisitsCXXForRangeStmtRange) {
147   DeclRefExprVisitor Visitor;
148   Visitor.ExpectMatch("x", 2, 25);
149   Visitor.ExpectMatch("x", 2, 30);
150   EXPECT_TRUE(Visitor.runOver(
151     "int x[5];\n"
152     "void f() { for (int i : x) { x[0] = 1; } }"));
153 }
154 
TEST(RecursiveASTVisitor,VisitsCXXForRangeStmtLoopVariable)155 TEST(RecursiveASTVisitor, VisitsCXXForRangeStmtLoopVariable) {
156   VarDeclVisitor Visitor;
157   Visitor.ExpectMatch("i", 2, 17);
158   EXPECT_TRUE(Visitor.runOver(
159     "int x[5];\n"
160     "void f() { for (int i : x) {} }"));
161 }
162 
TEST(RecursiveASTVisitor,VisitsCallExpr)163 TEST(RecursiveASTVisitor, VisitsCallExpr) {
164   DeclRefExprVisitor Visitor;
165   Visitor.ExpectMatch("x", 1, 22);
166   EXPECT_TRUE(Visitor.runOver(
167     "void x(); void y() { x(); }"));
168 }
169 
TEST(RecursiveASTVisitor,VisitsCallInTemplateInstantiation)170 TEST(RecursiveASTVisitor, VisitsCallInTemplateInstantiation) {
171   CXXMemberCallVisitor Visitor;
172   Visitor.ExpectMatch("Y::x", 3, 3);
173   EXPECT_TRUE(Visitor.runOver(
174     "struct Y { void x(); };\n"
175     "template<typename T> void y(T t) {\n"
176     "  t.x();\n"
177     "}\n"
178     "void foo() { y<Y>(Y()); }"));
179 }
180 
TEST(RecursiveASTVisitor,VisitsCallInNestedFunctionTemplateInstantiation)181 TEST(RecursiveASTVisitor, VisitsCallInNestedFunctionTemplateInstantiation) {
182   CXXMemberCallVisitor Visitor;
183   Visitor.ExpectMatch("Y::x", 4, 5);
184   EXPECT_TRUE(Visitor.runOver(
185     "struct Y { void x(); };\n"
186     "template<typename T> struct Z {\n"
187     "  template<typename U> static void f() {\n"
188     "    T().x();\n"
189     "  }\n"
190     "};\n"
191     "void foo() { Z<Y>::f<int>(); }"));
192 }
193 
TEST(RecursiveASTVisitor,VisitsCallInNestedClassTemplateInstantiation)194 TEST(RecursiveASTVisitor, VisitsCallInNestedClassTemplateInstantiation) {
195   CXXMemberCallVisitor Visitor;
196   Visitor.ExpectMatch("A::x", 5, 7);
197   EXPECT_TRUE(Visitor.runOver(
198     "template <typename T1> struct X {\n"
199     "  template <typename T2> struct Y {\n"
200     "    void f() {\n"
201     "      T2 y;\n"
202     "      y.x();\n"
203     "    }\n"
204     "  };\n"
205     "};\n"
206     "struct A { void x(); };\n"
207     "int main() {\n"
208     "  (new X<A>::Y<A>())->f();\n"
209     "}"));
210 }
211 
212 /* FIXME: According to Richard Smith this is a bug in the AST.
213 TEST(RecursiveASTVisitor, VisitsBaseClassTemplateArgumentsInInstantiation) {
214   DeclRefExprVisitor Visitor;
215   Visitor.ExpectMatch("x", 3, 43);
216   EXPECT_TRUE(Visitor.runOver(
217     "template <typename T> void x();\n"
218     "template <void (*T)()> class X {};\n"
219     "template <typename T> class Y : public X< x<T> > {};\n"
220     "Y<int> y;"));
221 }
222 */
223 
TEST(RecursiveASTVisitor,VisitsCallInPartialTemplateSpecialization)224 TEST(RecursiveASTVisitor, VisitsCallInPartialTemplateSpecialization) {
225   CXXMemberCallVisitor Visitor;
226   Visitor.ExpectMatch("A::x", 6, 20);
227   EXPECT_TRUE(Visitor.runOver(
228     "template <typename T1> struct X {\n"
229     "  template <typename T2, bool B> struct Y { void g(); };\n"
230     "};\n"
231     "template <typename T1> template <typename T2>\n"
232     "struct X<T1>::Y<T2, true> {\n"
233     "  void f() { T2 y; y.x(); }\n"
234     "};\n"
235     "struct A { void x(); };\n"
236     "int main() {\n"
237     "  (new X<A>::Y<A, true>())->f();\n"
238     "}\n"));
239 }
240 
TEST(RecursiveASTVisitor,VisitsExplicitTemplateSpecialization)241 TEST(RecursiveASTVisitor, VisitsExplicitTemplateSpecialization) {
242   CXXMemberCallVisitor Visitor;
243   Visitor.ExpectMatch("A::f", 4, 5);
244   EXPECT_TRUE(Visitor.runOver(
245     "struct A {\n"
246     "  void f() const {}\n"
247     "  template<class T> void g(const T& t) const {\n"
248     "    t.f();\n"
249     "  }\n"
250     "};\n"
251     "template void A::g(const A& a) const;\n"));
252 }
253 
TEST(RecursiveASTVisitor,VisitsPartialTemplateSpecialization)254 TEST(RecursiveASTVisitor, VisitsPartialTemplateSpecialization) {
255   // From cfe-commits/Week-of-Mon-20100830/033998.html
256   // Contrary to the approach suggested in that email, we visit all
257   // specializations when we visit the primary template.  Visiting them when we
258   // visit the associated specialization is problematic for specializations of
259   // template members of class templates.
260   NamedDeclVisitor Visitor;
261   Visitor.ExpectMatch("A<bool>", 1, 26);
262   Visitor.ExpectMatch("A<char *>", 2, 26);
263   EXPECT_TRUE(Visitor.runOver(
264     "template <class T> class A {};\n"
265     "template <class T> class A<T*> {};\n"
266     "A<bool> ab;\n"
267     "A<char*> acp;\n"));
268 }
269 
TEST(RecursiveASTVisitor,VisitsUndefinedClassTemplateSpecialization)270 TEST(RecursiveASTVisitor, VisitsUndefinedClassTemplateSpecialization) {
271   NamedDeclVisitor Visitor;
272   Visitor.ExpectMatch("A<int>", 1, 29);
273   EXPECT_TRUE(Visitor.runOver(
274     "template<typename T> struct A;\n"
275     "A<int> *p;\n"));
276 }
277 
TEST(RecursiveASTVisitor,VisitsNestedUndefinedClassTemplateSpecialization)278 TEST(RecursiveASTVisitor, VisitsNestedUndefinedClassTemplateSpecialization) {
279   NamedDeclVisitor Visitor;
280   Visitor.ExpectMatch("A<int>::B<char>", 2, 31);
281   EXPECT_TRUE(Visitor.runOver(
282     "template<typename T> struct A {\n"
283     "  template<typename U> struct B;\n"
284     "};\n"
285     "A<int>::B<char> *p;\n"));
286 }
287 
TEST(RecursiveASTVisitor,VisitsUndefinedFunctionTemplateSpecialization)288 TEST(RecursiveASTVisitor, VisitsUndefinedFunctionTemplateSpecialization) {
289   NamedDeclVisitor Visitor;
290   Visitor.ExpectMatch("A<int>", 1, 26);
291   EXPECT_TRUE(Visitor.runOver(
292     "template<typename T> int A();\n"
293     "int k = A<int>();\n"));
294 }
295 
TEST(RecursiveASTVisitor,VisitsNestedUndefinedFunctionTemplateSpecialization)296 TEST(RecursiveASTVisitor, VisitsNestedUndefinedFunctionTemplateSpecialization) {
297   NamedDeclVisitor Visitor;
298   Visitor.ExpectMatch("A<int>::B<char>", 2, 35);
299   EXPECT_TRUE(Visitor.runOver(
300     "template<typename T> struct A {\n"
301     "  template<typename U> static int B();\n"
302     "};\n"
303     "int k = A<int>::B<char>();\n"));
304 }
305 
TEST(RecursiveASTVisitor,NoRecursionInSelfFriend)306 TEST(RecursiveASTVisitor, NoRecursionInSelfFriend) {
307   // From cfe-commits/Week-of-Mon-20100830/033977.html
308   NamedDeclVisitor Visitor;
309   Visitor.ExpectMatch("vector_iterator<int>", 2, 7);
310   EXPECT_TRUE(Visitor.runOver(
311     "template<typename Container>\n"
312     "class vector_iterator {\n"
313     "    template <typename C> friend class vector_iterator;\n"
314     "};\n"
315     "vector_iterator<int> it_int;\n"));
316 }
317 
TEST(RecursiveASTVisitor,TraversesOverloadedOperator)318 TEST(RecursiveASTVisitor, TraversesOverloadedOperator) {
319   CXXOperatorCallExprTraverser Visitor;
320   Visitor.ExpectMatch("()", 4, 9);
321   EXPECT_TRUE(Visitor.runOver(
322     "struct A {\n"
323     "  int operator()();\n"
324     "} a;\n"
325     "int k = a();\n"));
326 }
327 
TEST(RecursiveASTVisitor,VisitsParensDuringDataRecursion)328 TEST(RecursiveASTVisitor, VisitsParensDuringDataRecursion) {
329   ParenExprVisitor Visitor;
330   Visitor.ExpectMatch("", 1, 9);
331   EXPECT_TRUE(Visitor.runOver("int k = (4) + 9;\n"));
332 }
333 
TEST(RecursiveASTVisitor,VisitsClassTemplateNonTypeParmDefaultArgument)334 TEST(RecursiveASTVisitor, VisitsClassTemplateNonTypeParmDefaultArgument) {
335   CXXBoolLiteralExprVisitor Visitor;
336   Visitor.ExpectMatch("true", 2, 19);
337   EXPECT_TRUE(Visitor.runOver(
338     "template<bool B> class X;\n"
339     "template<bool B = true> class Y;\n"
340     "template<bool B> class Y {};\n"));
341 }
342 
TEST(RecursiveASTVisitor,VisitsClassTemplateTypeParmDefaultArgument)343 TEST(RecursiveASTVisitor, VisitsClassTemplateTypeParmDefaultArgument) {
344   TypeLocVisitor Visitor;
345   Visitor.ExpectMatch("class X", 2, 23);
346   EXPECT_TRUE(Visitor.runOver(
347     "class X;\n"
348     "template<typename T = X> class Y;\n"
349     "template<typename T> class Y {};\n"));
350 }
351 
TEST(RecursiveASTVisitor,VisitsClassTemplateTemplateParmDefaultArgument)352 TEST(RecursiveASTVisitor, VisitsClassTemplateTemplateParmDefaultArgument) {
353   TemplateArgumentLocTraverser Visitor;
354   Visitor.ExpectMatch("X", 2, 40);
355   EXPECT_TRUE(Visitor.runOver(
356     "template<typename T> class X;\n"
357     "template<template <typename> class T = X> class Y;\n"
358     "template<template <typename> class T> class Y {};\n"));
359 }
360 
361 // A visitor that visits implicit declarations and matches constructors.
362 class ImplicitCtorVisitor
363     : public ExpectedLocationVisitor<ImplicitCtorVisitor> {
364 public:
shouldVisitImplicitCode() const365   bool shouldVisitImplicitCode() const { return true; }
366 
VisitCXXConstructorDecl(CXXConstructorDecl * Ctor)367   bool VisitCXXConstructorDecl(CXXConstructorDecl* Ctor) {
368     if (Ctor->isImplicit()) {  // Was not written in source code
369       if (const CXXRecordDecl* Class = Ctor->getParent()) {
370         Match(Class->getName(), Ctor->getLocation());
371       }
372     }
373     return true;
374   }
375 };
376 
TEST(RecursiveASTVisitor,VisitsImplicitCopyConstructors)377 TEST(RecursiveASTVisitor, VisitsImplicitCopyConstructors) {
378   ImplicitCtorVisitor Visitor;
379   Visitor.ExpectMatch("Simple", 2, 8);
380   // Note: Clang lazily instantiates implicit declarations, so we need
381   // to use them in order to force them to appear in the AST.
382   EXPECT_TRUE(Visitor.runOver(
383       "struct WithCtor { WithCtor(); }; \n"
384       "struct Simple { Simple(); WithCtor w; }; \n"
385       "int main() { Simple s; Simple t(s); }\n"));
386 }
387 
388 /// \brief A visitor that optionally includes implicit code and matches
389 /// CXXConstructExpr.
390 ///
391 /// The name recorded for the match is the name of the class whose constructor
392 /// is invoked by the CXXConstructExpr, not the name of the class whose
393 /// constructor the CXXConstructExpr is contained in.
394 class ConstructExprVisitor
395     : public ExpectedLocationVisitor<ConstructExprVisitor> {
396 public:
ConstructExprVisitor()397   ConstructExprVisitor() : ShouldVisitImplicitCode(false) {}
398 
shouldVisitImplicitCode() const399   bool shouldVisitImplicitCode() const { return ShouldVisitImplicitCode; }
400 
setShouldVisitImplicitCode(bool NewValue)401   void setShouldVisitImplicitCode(bool NewValue) {
402     ShouldVisitImplicitCode = NewValue;
403   }
404 
VisitCXXConstructExpr(CXXConstructExpr * Expr)405   bool VisitCXXConstructExpr(CXXConstructExpr* Expr) {
406     if (const CXXConstructorDecl* Ctor = Expr->getConstructor()) {
407       if (const CXXRecordDecl* Class = Ctor->getParent()) {
408         Match(Class->getName(), Expr->getLocation());
409       }
410     }
411     return true;
412   }
413 
414  private:
415   bool ShouldVisitImplicitCode;
416 };
417 
TEST(RecursiveASTVisitor,CanVisitImplicitMemberInitializations)418 TEST(RecursiveASTVisitor, CanVisitImplicitMemberInitializations) {
419   ConstructExprVisitor Visitor;
420   Visitor.setShouldVisitImplicitCode(true);
421   Visitor.ExpectMatch("WithCtor", 2, 8);
422   // Simple has a constructor that implicitly initializes 'w'.  Test
423   // that a visitor that visits implicit code visits that initialization.
424   // Note: Clang lazily instantiates implicit declarations, so we need
425   // to use them in order to force them to appear in the AST.
426   EXPECT_TRUE(Visitor.runOver(
427       "struct WithCtor { WithCtor(); }; \n"
428       "struct Simple { WithCtor w; }; \n"
429       "int main() { Simple s; }\n"));
430 }
431 
432 // The same as CanVisitImplicitMemberInitializations, but checking that the
433 // visits are omitted when the visitor does not include implicit code.
TEST(RecursiveASTVisitor,CanSkipImplicitMemberInitializations)434 TEST(RecursiveASTVisitor, CanSkipImplicitMemberInitializations) {
435   ConstructExprVisitor Visitor;
436   Visitor.setShouldVisitImplicitCode(false);
437   Visitor.DisallowMatch("WithCtor", 2, 8);
438   // Simple has a constructor that implicitly initializes 'w'.  Test
439   // that a visitor that skips implicit code skips that initialization.
440   // Note: Clang lazily instantiates implicit declarations, so we need
441   // to use them in order to force them to appear in the AST.
442   EXPECT_TRUE(Visitor.runOver(
443       "struct WithCtor { WithCtor(); }; \n"
444       "struct Simple { WithCtor w; }; \n"
445       "int main() { Simple s; }\n"));
446 }
447 
TEST(RecursiveASTVisitor,VisitsExtension)448 TEST(RecursiveASTVisitor, VisitsExtension) {
449   DeclRefExprVisitor Visitor;
450   Visitor.ExpectMatch("s", 1, 24);
451   EXPECT_TRUE(Visitor.runOver(
452     "int s = __extension__ (s);\n"));
453 }
454 
TEST(RecursiveASTVisitor,VisitsCompoundLiteralType)455 TEST(RecursiveASTVisitor, VisitsCompoundLiteralType) {
456   TypeLocVisitor Visitor;
457   Visitor.ExpectMatch("struct S", 1, 26);
458   EXPECT_TRUE(Visitor.runOver(
459       "int f() { return (struct S { int a; }){.a = 0}.a; }",
460       TypeLocVisitor::Lang_C));
461 }
462 
463 } // end namespace clang
464