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