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