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
13using namespace clang;
14
15namespace {
16
17class TypeLocVisitor : public ExpectedLocationVisitor<TypeLocVisitor> {
18public:
19  bool VisitTypeLoc(TypeLoc TypeLocation) {
20    Match(TypeLocation.getType().getAsString(), TypeLocation.getBeginLoc());
21    return true;
22  }
23};
24
25class DeclRefExprVisitor : public ExpectedLocationVisitor<DeclRefExprVisitor> {
26public:
27  bool VisitDeclRefExpr(DeclRefExpr *Reference) {
28    Match(Reference->getNameInfo().getAsString(), Reference->getLocation());
29    return true;
30  }
31};
32
33class VarDeclVisitor : public ExpectedLocationVisitor<VarDeclVisitor> {
34public:
35 bool VisitVarDecl(VarDecl *Variable) {
36   Match(Variable->getNameAsString(), Variable->getLocStart());
37   return true;
38 }
39};
40
41class ParmVarDeclVisitorForImplicitCode :
42  public ExpectedLocationVisitor<ParmVarDeclVisitorForImplicitCode> {
43public:
44  bool shouldVisitImplicitCode() const { return true; }
45
46  bool VisitParmVarDecl(ParmVarDecl *ParamVar) {
47    Match(ParamVar->getNameAsString(), ParamVar->getLocStart());
48    return true;
49  }
50};
51
52class CXXMemberCallVisitor
53  : public ExpectedLocationVisitor<CXXMemberCallVisitor> {
54public:
55  bool VisitCXXMemberCallExpr(CXXMemberCallExpr *Call) {
56    Match(Call->getMethodDecl()->getQualifiedNameAsString(),
57          Call->getLocStart());
58    return true;
59  }
60};
61
62class NamedDeclVisitor
63  : public ExpectedLocationVisitor<NamedDeclVisitor> {
64public:
65  bool VisitNamedDecl(NamedDecl *Decl) {
66    std::string NameWithTemplateArgs;
67    llvm::raw_string_ostream OS(NameWithTemplateArgs);
68    Decl->getNameForDiagnostic(OS,
69                               Decl->getASTContext().getPrintingPolicy(),
70                               true);
71    Match(OS.str(), Decl->getLocation());
72    return true;
73  }
74};
75
76class CXXOperatorCallExprTraverser
77  : public ExpectedLocationVisitor<CXXOperatorCallExprTraverser> {
78public:
79  // Use Traverse, not Visit, to check that data recursion optimization isn't
80  // bypassing the call of this function.
81  bool TraverseCXXOperatorCallExpr(CXXOperatorCallExpr *CE) {
82    Match(getOperatorSpelling(CE->getOperator()), CE->getExprLoc());
83    return ExpectedLocationVisitor<CXXOperatorCallExprTraverser>::
84        TraverseCXXOperatorCallExpr(CE);
85  }
86};
87
88class ParenExprVisitor : public ExpectedLocationVisitor<ParenExprVisitor> {
89public:
90  bool VisitParenExpr(ParenExpr *Parens) {
91    Match("", Parens->getExprLoc());
92    return true;
93  }
94};
95
96class LambdaExprVisitor : public ExpectedLocationVisitor<LambdaExprVisitor> {
97public:
98  bool VisitLambdaExpr(LambdaExpr *Lambda) {
99    PendingBodies.push(Lambda);
100    Match("", Lambda->getIntroducerRange().getBegin());
101    return true;
102  }
103  /// For each call to VisitLambdaExpr, we expect a subsequent call (with
104  /// proper nesting) to TraverseLambdaBody.
105  bool TraverseLambdaBody(LambdaExpr *Lambda) {
106    EXPECT_FALSE(PendingBodies.empty());
107    EXPECT_EQ(PendingBodies.top(), Lambda);
108    PendingBodies.pop();
109    return TraverseStmt(Lambda->getBody());
110  }
111  /// Determine whether TraverseLambdaBody has been called for every call to
112  /// VisitLambdaExpr.
113  bool allBodiesHaveBeenTraversed() const {
114    return PendingBodies.empty();
115  }
116private:
117  std::stack<LambdaExpr *> PendingBodies;
118};
119
120// Matches the (optional) capture-default of a lambda-introducer.
121class LambdaDefaultCaptureVisitor
122  : public ExpectedLocationVisitor<LambdaDefaultCaptureVisitor> {
123public:
124  bool VisitLambdaExpr(LambdaExpr *Lambda) {
125    if (Lambda->getCaptureDefault() != LCD_None) {
126      Match("", Lambda->getCaptureDefaultLoc());
127    }
128    return true;
129  }
130};
131
132class TemplateArgumentLocTraverser
133  : public ExpectedLocationVisitor<TemplateArgumentLocTraverser> {
134public:
135  bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc) {
136    std::string ArgStr;
137    llvm::raw_string_ostream Stream(ArgStr);
138    const TemplateArgument &Arg = ArgLoc.getArgument();
139
140    Arg.print(Context->getPrintingPolicy(), Stream);
141    Match(Stream.str(), ArgLoc.getLocation());
142    return ExpectedLocationVisitor<TemplateArgumentLocTraverser>::
143      TraverseTemplateArgumentLoc(ArgLoc);
144  }
145};
146
147class CXXBoolLiteralExprVisitor
148  : public ExpectedLocationVisitor<CXXBoolLiteralExprVisitor> {
149public:
150  bool VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *BE) {
151    if (BE->getValue())
152      Match("true", BE->getLocation());
153    else
154      Match("false", BE->getLocation());
155    return true;
156  }
157};
158
159// Test RAV visits parameter variable declaration of the implicit
160// copy assignment operator and implicit copy constructor.
161TEST(RecursiveASTVisitor, VisitsParmVarDeclForImplicitCode) {
162  ParmVarDeclVisitorForImplicitCode Visitor;
163  // Match parameter variable name of implicit copy assignment operator and
164  // implicit copy constructor.
165  // This parameter name does not have a valid IdentifierInfo, and shares
166  // same SourceLocation with its class declaration, so we match an empty name
167  // with the class' source location.
168  Visitor.ExpectMatch("", 1, 7);
169  Visitor.ExpectMatch("", 3, 7);
170  EXPECT_TRUE(Visitor.runOver(
171    "class X {};\n"
172    "void foo(X a, X b) {a = b;}\n"
173    "class Y {};\n"
174    "void bar(Y a) {Y b = a;}"));
175}
176
177TEST(RecursiveASTVisitor, VisitsBaseClassDeclarations) {
178  TypeLocVisitor Visitor;
179  Visitor.ExpectMatch("class X", 1, 30);
180  EXPECT_TRUE(Visitor.runOver("class X {}; class Y : public X {};"));
181}
182
183TEST(RecursiveASTVisitor, VisitsCXXBaseSpecifiersOfForwardDeclaredClass) {
184  TypeLocVisitor Visitor;
185  Visitor.ExpectMatch("class X", 3, 18);
186  EXPECT_TRUE(Visitor.runOver(
187    "class Y;\n"
188    "class X {};\n"
189    "class Y : public X {};"));
190}
191
192TEST(RecursiveASTVisitor, VisitsCXXBaseSpecifiersWithIncompleteInnerClass) {
193  TypeLocVisitor Visitor;
194  Visitor.ExpectMatch("class X", 2, 18);
195  EXPECT_TRUE(Visitor.runOver(
196    "class X {};\n"
197    "class Y : public X { class Z; };"));
198}
199
200TEST(RecursiveASTVisitor, VisitsCXXBaseSpecifiersOfSelfReferentialType) {
201  TypeLocVisitor Visitor;
202  Visitor.ExpectMatch("X<class Y>", 2, 18);
203  EXPECT_TRUE(Visitor.runOver(
204    "template<typename T> class X {};\n"
205    "class Y : public X<Y> {};"));
206}
207
208TEST(RecursiveASTVisitor, VisitsBaseClassTemplateArguments) {
209  DeclRefExprVisitor Visitor;
210  Visitor.ExpectMatch("x", 2, 3);
211  EXPECT_TRUE(Visitor.runOver(
212    "void x(); template <void (*T)()> class X {};\nX<x> y;"));
213}
214
215TEST(RecursiveASTVisitor, VisitsCXXForRangeStmtRange) {
216  DeclRefExprVisitor Visitor;
217  Visitor.ExpectMatch("x", 2, 25);
218  Visitor.ExpectMatch("x", 2, 30);
219  EXPECT_TRUE(Visitor.runOver(
220    "int x[5];\n"
221    "void f() { for (int i : x) { x[0] = 1; } }",
222    DeclRefExprVisitor::Lang_CXX11));
223}
224
225TEST(RecursiveASTVisitor, VisitsCXXForRangeStmtLoopVariable) {
226  VarDeclVisitor Visitor;
227  Visitor.ExpectMatch("i", 2, 17);
228  EXPECT_TRUE(Visitor.runOver(
229    "int x[5];\n"
230    "void f() { for (int i : x) {} }",
231    VarDeclVisitor::Lang_CXX11));
232}
233
234TEST(RecursiveASTVisitor, VisitsCallExpr) {
235  DeclRefExprVisitor Visitor;
236  Visitor.ExpectMatch("x", 1, 22);
237  EXPECT_TRUE(Visitor.runOver(
238    "void x(); void y() { x(); }"));
239}
240
241TEST(RecursiveASTVisitor, VisitsCallInTemplateInstantiation) {
242  CXXMemberCallVisitor Visitor;
243  Visitor.ExpectMatch("Y::x", 3, 3);
244  EXPECT_TRUE(Visitor.runOver(
245    "struct Y { void x(); };\n"
246    "template<typename T> void y(T t) {\n"
247    "  t.x();\n"
248    "}\n"
249    "void foo() { y<Y>(Y()); }"));
250}
251
252TEST(RecursiveASTVisitor, VisitsCallInNestedFunctionTemplateInstantiation) {
253  CXXMemberCallVisitor Visitor;
254  Visitor.ExpectMatch("Y::x", 4, 5);
255  EXPECT_TRUE(Visitor.runOver(
256    "struct Y { void x(); };\n"
257    "template<typename T> struct Z {\n"
258    "  template<typename U> static void f() {\n"
259    "    T().x();\n"
260    "  }\n"
261    "};\n"
262    "void foo() { Z<Y>::f<int>(); }"));
263}
264
265TEST(RecursiveASTVisitor, VisitsCallInNestedClassTemplateInstantiation) {
266  CXXMemberCallVisitor Visitor;
267  Visitor.ExpectMatch("A::x", 5, 7);
268  EXPECT_TRUE(Visitor.runOver(
269    "template <typename T1> struct X {\n"
270    "  template <typename T2> struct Y {\n"
271    "    void f() {\n"
272    "      T2 y;\n"
273    "      y.x();\n"
274    "    }\n"
275    "  };\n"
276    "};\n"
277    "struct A { void x(); };\n"
278    "int main() {\n"
279    "  (new X<A>::Y<A>())->f();\n"
280    "}"));
281}
282
283/* FIXME: According to Richard Smith this is a bug in the AST.
284TEST(RecursiveASTVisitor, VisitsBaseClassTemplateArgumentsInInstantiation) {
285  DeclRefExprVisitor Visitor;
286  Visitor.ExpectMatch("x", 3, 43);
287  EXPECT_TRUE(Visitor.runOver(
288    "template <typename T> void x();\n"
289    "template <void (*T)()> class X {};\n"
290    "template <typename T> class Y : public X< x<T> > {};\n"
291    "Y<int> y;"));
292}
293*/
294
295TEST(RecursiveASTVisitor, VisitsCallInPartialTemplateSpecialization) {
296  CXXMemberCallVisitor Visitor;
297  Visitor.ExpectMatch("A::x", 6, 20);
298  EXPECT_TRUE(Visitor.runOver(
299    "template <typename T1> struct X {\n"
300    "  template <typename T2, bool B> struct Y { void g(); };\n"
301    "};\n"
302    "template <typename T1> template <typename T2>\n"
303    "struct X<T1>::Y<T2, true> {\n"
304    "  void f() { T2 y; y.x(); }\n"
305    "};\n"
306    "struct A { void x(); };\n"
307    "int main() {\n"
308    "  (new X<A>::Y<A, true>())->f();\n"
309    "}\n"));
310}
311
312TEST(RecursiveASTVisitor, VisitsExplicitTemplateSpecialization) {
313  CXXMemberCallVisitor Visitor;
314  Visitor.ExpectMatch("A::f", 4, 5);
315  EXPECT_TRUE(Visitor.runOver(
316    "struct A {\n"
317    "  void f() const {}\n"
318    "  template<class T> void g(const T& t) const {\n"
319    "    t.f();\n"
320    "  }\n"
321    "};\n"
322    "template void A::g(const A& a) const;\n"));
323}
324
325TEST(RecursiveASTVisitor, VisitsPartialTemplateSpecialization) {
326  // From cfe-commits/Week-of-Mon-20100830/033998.html
327  // Contrary to the approach suggested in that email, we visit all
328  // specializations when we visit the primary template.  Visiting them when we
329  // visit the associated specialization is problematic for specializations of
330  // template members of class templates.
331  NamedDeclVisitor Visitor;
332  Visitor.ExpectMatch("A<bool>", 1, 26);
333  Visitor.ExpectMatch("A<char *>", 2, 26);
334  EXPECT_TRUE(Visitor.runOver(
335    "template <class T> class A {};\n"
336    "template <class T> class A<T*> {};\n"
337    "A<bool> ab;\n"
338    "A<char*> acp;\n"));
339}
340
341TEST(RecursiveASTVisitor, VisitsUndefinedClassTemplateSpecialization) {
342  NamedDeclVisitor Visitor;
343  Visitor.ExpectMatch("A<int>", 1, 29);
344  EXPECT_TRUE(Visitor.runOver(
345    "template<typename T> struct A;\n"
346    "A<int> *p;\n"));
347}
348
349TEST(RecursiveASTVisitor, VisitsNestedUndefinedClassTemplateSpecialization) {
350  NamedDeclVisitor Visitor;
351  Visitor.ExpectMatch("A<int>::B<char>", 2, 31);
352  EXPECT_TRUE(Visitor.runOver(
353    "template<typename T> struct A {\n"
354    "  template<typename U> struct B;\n"
355    "};\n"
356    "A<int>::B<char> *p;\n"));
357}
358
359TEST(RecursiveASTVisitor, VisitsUndefinedFunctionTemplateSpecialization) {
360  NamedDeclVisitor Visitor;
361  Visitor.ExpectMatch("A<int>", 1, 26);
362  EXPECT_TRUE(Visitor.runOver(
363    "template<typename T> int A();\n"
364    "int k = A<int>();\n"));
365}
366
367TEST(RecursiveASTVisitor, VisitsNestedUndefinedFunctionTemplateSpecialization) {
368  NamedDeclVisitor Visitor;
369  Visitor.ExpectMatch("A<int>::B<char>", 2, 35);
370  EXPECT_TRUE(Visitor.runOver(
371    "template<typename T> struct A {\n"
372    "  template<typename U> static int B();\n"
373    "};\n"
374    "int k = A<int>::B<char>();\n"));
375}
376
377TEST(RecursiveASTVisitor, NoRecursionInSelfFriend) {
378  // From cfe-commits/Week-of-Mon-20100830/033977.html
379  NamedDeclVisitor Visitor;
380  Visitor.ExpectMatch("vector_iterator<int>", 2, 7);
381  EXPECT_TRUE(Visitor.runOver(
382    "template<typename Container>\n"
383    "class vector_iterator {\n"
384    "    template <typename C> friend class vector_iterator;\n"
385    "};\n"
386    "vector_iterator<int> it_int;\n"));
387}
388
389TEST(RecursiveASTVisitor, TraversesOverloadedOperator) {
390  CXXOperatorCallExprTraverser Visitor;
391  Visitor.ExpectMatch("()", 4, 9);
392  EXPECT_TRUE(Visitor.runOver(
393    "struct A {\n"
394    "  int operator()();\n"
395    "} a;\n"
396    "int k = a();\n"));
397}
398
399TEST(RecursiveASTVisitor, VisitsParensDuringDataRecursion) {
400  ParenExprVisitor Visitor;
401  Visitor.ExpectMatch("", 1, 9);
402  EXPECT_TRUE(Visitor.runOver("int k = (4) + 9;\n"));
403}
404
405TEST(RecursiveASTVisitor, VisitsClassTemplateNonTypeParmDefaultArgument) {
406  CXXBoolLiteralExprVisitor Visitor;
407  Visitor.ExpectMatch("true", 2, 19);
408  EXPECT_TRUE(Visitor.runOver(
409    "template<bool B> class X;\n"
410    "template<bool B = true> class Y;\n"
411    "template<bool B> class Y {};\n"));
412}
413
414TEST(RecursiveASTVisitor, VisitsClassTemplateTypeParmDefaultArgument) {
415  TypeLocVisitor Visitor;
416  Visitor.ExpectMatch("class X", 2, 23);
417  EXPECT_TRUE(Visitor.runOver(
418    "class X;\n"
419    "template<typename T = X> class Y;\n"
420    "template<typename T> class Y {};\n"));
421}
422
423TEST(RecursiveASTVisitor, VisitsClassTemplateTemplateParmDefaultArgument) {
424  TemplateArgumentLocTraverser Visitor;
425  Visitor.ExpectMatch("X", 2, 40);
426  EXPECT_TRUE(Visitor.runOver(
427    "template<typename T> class X;\n"
428    "template<template <typename> class T = X> class Y;\n"
429    "template<template <typename> class T> class Y {};\n"));
430}
431
432// A visitor that visits implicit declarations and matches constructors.
433class ImplicitCtorVisitor
434    : public ExpectedLocationVisitor<ImplicitCtorVisitor> {
435public:
436  bool shouldVisitImplicitCode() const { return true; }
437
438  bool VisitCXXConstructorDecl(CXXConstructorDecl* Ctor) {
439    if (Ctor->isImplicit()) {  // Was not written in source code
440      if (const CXXRecordDecl* Class = Ctor->getParent()) {
441        Match(Class->getName(), Ctor->getLocation());
442      }
443    }
444    return true;
445  }
446};
447
448TEST(RecursiveASTVisitor, VisitsImplicitCopyConstructors) {
449  ImplicitCtorVisitor Visitor;
450  Visitor.ExpectMatch("Simple", 2, 8);
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 { Simple(); WithCtor w; }; \n"
456      "int main() { Simple s; Simple t(s); }\n"));
457}
458
459/// \brief A visitor that optionally includes implicit code and matches
460/// CXXConstructExpr.
461///
462/// The name recorded for the match is the name of the class whose constructor
463/// is invoked by the CXXConstructExpr, not the name of the class whose
464/// constructor the CXXConstructExpr is contained in.
465class ConstructExprVisitor
466    : public ExpectedLocationVisitor<ConstructExprVisitor> {
467public:
468  ConstructExprVisitor() : ShouldVisitImplicitCode(false) {}
469
470  bool shouldVisitImplicitCode() const { return ShouldVisitImplicitCode; }
471
472  void setShouldVisitImplicitCode(bool NewValue) {
473    ShouldVisitImplicitCode = NewValue;
474  }
475
476  bool VisitCXXConstructExpr(CXXConstructExpr* Expr) {
477    if (const CXXConstructorDecl* Ctor = Expr->getConstructor()) {
478      if (const CXXRecordDecl* Class = Ctor->getParent()) {
479        Match(Class->getName(), Expr->getLocation());
480      }
481    }
482    return true;
483  }
484
485 private:
486  bool ShouldVisitImplicitCode;
487};
488
489TEST(RecursiveASTVisitor, CanVisitImplicitMemberInitializations) {
490  ConstructExprVisitor Visitor;
491  Visitor.setShouldVisitImplicitCode(true);
492  Visitor.ExpectMatch("WithCtor", 2, 8);
493  // Simple has a constructor that implicitly initializes 'w'.  Test
494  // that a visitor that visits implicit code visits that initialization.
495  // Note: Clang lazily instantiates implicit declarations, so we need
496  // to use them in order to force them to appear in the AST.
497  EXPECT_TRUE(Visitor.runOver(
498      "struct WithCtor { WithCtor(); }; \n"
499      "struct Simple { WithCtor w; }; \n"
500      "int main() { Simple s; }\n"));
501}
502
503// The same as CanVisitImplicitMemberInitializations, but checking that the
504// visits are omitted when the visitor does not include implicit code.
505TEST(RecursiveASTVisitor, CanSkipImplicitMemberInitializations) {
506  ConstructExprVisitor Visitor;
507  Visitor.setShouldVisitImplicitCode(false);
508  Visitor.DisallowMatch("WithCtor", 2, 8);
509  // Simple has a constructor that implicitly initializes 'w'.  Test
510  // that a visitor that skips implicit code skips that initialization.
511  // Note: Clang lazily instantiates implicit declarations, so we need
512  // to use them in order to force them to appear in the AST.
513  EXPECT_TRUE(Visitor.runOver(
514      "struct WithCtor { WithCtor(); }; \n"
515      "struct Simple { WithCtor w; }; \n"
516      "int main() { Simple s; }\n"));
517}
518
519TEST(RecursiveASTVisitor, VisitsExtension) {
520  DeclRefExprVisitor Visitor;
521  Visitor.ExpectMatch("s", 1, 24);
522  EXPECT_TRUE(Visitor.runOver(
523    "int s = __extension__ (s);\n"));
524}
525
526TEST(RecursiveASTVisitor, VisitsCompoundLiteralType) {
527  TypeLocVisitor Visitor;
528  Visitor.ExpectMatch("struct S", 1, 26);
529  EXPECT_TRUE(Visitor.runOver(
530      "int f() { return (struct S { int a; }){.a = 0}.a; }",
531      TypeLocVisitor::Lang_C));
532}
533
534TEST(RecursiveASTVisitor, VisitsObjCPropertyType) {
535  TypeLocVisitor Visitor;
536  Visitor.ExpectMatch("NSNumber", 2, 33);
537  EXPECT_TRUE(Visitor.runOver(
538      "@class NSNumber; \n"
539      "@interface A @property (retain) NSNumber *x; @end\n",
540      TypeLocVisitor::Lang_OBJC));
541}
542
543TEST(RecursiveASTVisitor, VisitsLambdaExpr) {
544  LambdaExprVisitor Visitor;
545  Visitor.ExpectMatch("", 1, 12);
546  EXPECT_TRUE(Visitor.runOver("void f() { []{ return; }(); }",
547			      LambdaExprVisitor::Lang_CXX11));
548}
549
550TEST(RecursiveASTVisitor, TraverseLambdaBodyCanBeOverridden) {
551  LambdaExprVisitor Visitor;
552  EXPECT_TRUE(Visitor.runOver("void f() { []{ return; }(); }",
553			      LambdaExprVisitor::Lang_CXX11));
554  EXPECT_TRUE(Visitor.allBodiesHaveBeenTraversed());
555}
556
557TEST(RecursiveASTVisitor, HasCaptureDefaultLoc) {
558  LambdaDefaultCaptureVisitor Visitor;
559  Visitor.ExpectMatch("", 1, 20);
560  EXPECT_TRUE(Visitor.runOver("void f() { int a; [=]{a;}; }",
561                              LambdaDefaultCaptureVisitor::Lang_CXX11));
562}
563
564TEST(RecursiveASTVisitor, VisitsCopyExprOfBlockDeclCapture) {
565  DeclRefExprVisitor Visitor;
566  Visitor.ExpectMatch("x", 3, 24);
567  EXPECT_TRUE(Visitor.runOver("void f(int(^)(int)); \n"
568                              "void g() { \n"
569                              "  f([&](int x){ return x; }); \n"
570                              "}",
571                              DeclRefExprVisitor::Lang_OBJCXX11));
572}
573
574// Checks for lambda classes that are not marked as implicitly-generated.
575// (There should be none.)
576class ClassVisitor : public ExpectedLocationVisitor<ClassVisitor> {
577public:
578  ClassVisitor() : SawNonImplicitLambdaClass(false) {}
579  bool VisitCXXRecordDecl(CXXRecordDecl* record) {
580    if (record->isLambda() && !record->isImplicit())
581      SawNonImplicitLambdaClass = true;
582    return true;
583  }
584
585  bool sawOnlyImplicitLambdaClasses() const {
586    return !SawNonImplicitLambdaClass;
587  }
588
589private:
590  bool SawNonImplicitLambdaClass;
591};
592
593TEST(RecursiveASTVisitor, LambdaClosureTypesAreImplicit) {
594  ClassVisitor Visitor;
595  EXPECT_TRUE(Visitor.runOver("auto lambda = []{};",
596			      ClassVisitor::Lang_CXX11));
597  EXPECT_TRUE(Visitor.sawOnlyImplicitLambdaClasses());
598}
599
600
601
602// Check to ensure that attributes and expressions within them are being
603// visited.
604class AttrVisitor : public ExpectedLocationVisitor<AttrVisitor> {
605public:
606  bool VisitMemberExpr(MemberExpr *ME) {
607    Match(ME->getMemberDecl()->getNameAsString(), ME->getLocStart());
608    return true;
609  }
610  bool VisitAttr(Attr *A) {
611    Match("Attr", A->getLocation());
612    return true;
613  }
614  bool VisitGuardedByAttr(GuardedByAttr *A) {
615    Match("guarded_by", A->getLocation());
616    return true;
617  }
618};
619
620
621TEST(RecursiveASTVisitor, AttributesAreVisited) {
622  AttrVisitor Visitor;
623  Visitor.ExpectMatch("Attr", 4, 24);
624  Visitor.ExpectMatch("guarded_by", 4, 24);
625  Visitor.ExpectMatch("mu1",  4, 35);
626  Visitor.ExpectMatch("Attr", 5, 29);
627  Visitor.ExpectMatch("mu1",  5, 54);
628  Visitor.ExpectMatch("mu2",  5, 59);
629  EXPECT_TRUE(Visitor.runOver(
630    "class Foo {\n"
631    "  int mu1;\n"
632    "  int mu2;\n"
633    "  int a __attribute__((guarded_by(mu1)));\n"
634    "  void bar() __attribute__((exclusive_locks_required(mu1, mu2)));\n"
635    "};\n"));
636}
637
638} // end anonymous namespace
639