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