Home | History | Annotate | Download | only in Tooling
      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:
     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:
     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:
     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:
     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:
     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.
     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:
     76   bool VisitParenExpr(ParenExpr *Parens) {
     77     Match("", Parens->getExprLoc());
     78     return true;
     79   }
     80 };
     81 
     82 class TemplateArgumentLocTraverser
     83   : public ExpectedLocationVisitor<TemplateArgumentLocTraverser> {
     84 public:
     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:
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    329 TEST(RecursiveASTVisitor, VisitsParensDuringDataRecursion) {
    330   ParenExprVisitor Visitor;
    331   Visitor.ExpectMatch("", 1, 9);
    332   EXPECT_TRUE(Visitor.runOver("int k = (4) + 9;\n"));
    333 }
    334 
    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 
    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 
    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:
    366   bool shouldVisitImplicitCode() const { return true; }
    367 
    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 
    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:
    398   ConstructExprVisitor() : ShouldVisitImplicitCode(false) {}
    399 
    400   bool shouldVisitImplicitCode() const { return ShouldVisitImplicitCode; }
    401 
    402   void setShouldVisitImplicitCode(bool NewValue) {
    403     ShouldVisitImplicitCode = NewValue;
    404   }
    405 
    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 
    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.
    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 
    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 
    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