Home | History | Annotate | Download | only in Tooling
      1 //===- unittest/Tooling/RecursiveASTVisitorTestExprVisitor.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 
     13 using namespace clang;
     14 
     15 namespace {
     16 
     17 class ParenExprVisitor : public ExpectedLocationVisitor<ParenExprVisitor> {
     18 public:
     19   bool VisitParenExpr(ParenExpr *Parens) {
     20     Match("", Parens->getExprLoc());
     21     return true;
     22   }
     23 };
     24 
     25 TEST(RecursiveASTVisitor, VisitsParensDuringDataRecursion) {
     26   ParenExprVisitor Visitor;
     27   Visitor.ExpectMatch("", 1, 9);
     28   EXPECT_TRUE(Visitor.runOver("int k = (4) + 9;\n"));
     29 }
     30 
     31 class TemplateArgumentLocTraverser
     32   : public ExpectedLocationVisitor<TemplateArgumentLocTraverser> {
     33 public:
     34   bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc) {
     35     std::string ArgStr;
     36     llvm::raw_string_ostream Stream(ArgStr);
     37     const TemplateArgument &Arg = ArgLoc.getArgument();
     38 
     39     Arg.print(Context->getPrintingPolicy(), Stream);
     40     Match(Stream.str(), ArgLoc.getLocation());
     41     return ExpectedLocationVisitor<TemplateArgumentLocTraverser>::
     42       TraverseTemplateArgumentLoc(ArgLoc);
     43   }
     44 };
     45 
     46 TEST(RecursiveASTVisitor, VisitsClassTemplateTemplateParmDefaultArgument) {
     47   TemplateArgumentLocTraverser Visitor;
     48   Visitor.ExpectMatch("X", 2, 40);
     49   EXPECT_TRUE(Visitor.runOver(
     50     "template<typename T> class X;\n"
     51     "template<template <typename> class T = X> class Y;\n"
     52     "template<template <typename> class T> class Y {};\n"));
     53 }
     54 
     55 class CXXBoolLiteralExprVisitor
     56   : public ExpectedLocationVisitor<CXXBoolLiteralExprVisitor> {
     57 public:
     58   bool VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *BE) {
     59     if (BE->getValue())
     60       Match("true", BE->getLocation());
     61     else
     62       Match("false", BE->getLocation());
     63     return true;
     64   }
     65 };
     66 
     67 TEST(RecursiveASTVisitor, VisitsClassTemplateNonTypeParmDefaultArgument) {
     68   CXXBoolLiteralExprVisitor Visitor;
     69   Visitor.ExpectMatch("true", 2, 19);
     70   EXPECT_TRUE(Visitor.runOver(
     71     "template<bool B> class X;\n"
     72     "template<bool B = true> class Y;\n"
     73     "template<bool B> class Y {};\n"));
     74 }
     75 
     76 // A visitor that visits implicit declarations and matches constructors.
     77 class ImplicitCtorVisitor
     78     : public ExpectedLocationVisitor<ImplicitCtorVisitor> {
     79 public:
     80   bool shouldVisitImplicitCode() const { return true; }
     81 
     82   bool VisitCXXConstructorDecl(CXXConstructorDecl* Ctor) {
     83     if (Ctor->isImplicit()) {  // Was not written in source code
     84       if (const CXXRecordDecl* Class = Ctor->getParent()) {
     85         Match(Class->getName(), Ctor->getLocation());
     86       }
     87     }
     88     return true;
     89   }
     90 };
     91 
     92 TEST(RecursiveASTVisitor, VisitsImplicitCopyConstructors) {
     93   ImplicitCtorVisitor Visitor;
     94   Visitor.ExpectMatch("Simple", 2, 8);
     95   // Note: Clang lazily instantiates implicit declarations, so we need
     96   // to use them in order to force them to appear in the AST.
     97   EXPECT_TRUE(Visitor.runOver(
     98       "struct WithCtor { WithCtor(); }; \n"
     99       "struct Simple { Simple(); WithCtor w; }; \n"
    100       "int main() { Simple s; Simple t(s); }\n"));
    101 }
    102 
    103 /// \brief A visitor that optionally includes implicit code and matches
    104 /// CXXConstructExpr.
    105 ///
    106 /// The name recorded for the match is the name of the class whose constructor
    107 /// is invoked by the CXXConstructExpr, not the name of the class whose
    108 /// constructor the CXXConstructExpr is contained in.
    109 class ConstructExprVisitor
    110     : public ExpectedLocationVisitor<ConstructExprVisitor> {
    111 public:
    112   ConstructExprVisitor() : ShouldVisitImplicitCode(false) {}
    113 
    114   bool shouldVisitImplicitCode() const { return ShouldVisitImplicitCode; }
    115 
    116   void setShouldVisitImplicitCode(bool NewValue) {
    117     ShouldVisitImplicitCode = NewValue;
    118   }
    119 
    120   bool VisitCXXConstructExpr(CXXConstructExpr* Expr) {
    121     if (const CXXConstructorDecl* Ctor = Expr->getConstructor()) {
    122       if (const CXXRecordDecl* Class = Ctor->getParent()) {
    123         Match(Class->getName(), Expr->getLocation());
    124       }
    125     }
    126     return true;
    127   }
    128 
    129  private:
    130   bool ShouldVisitImplicitCode;
    131 };
    132 
    133 TEST(RecursiveASTVisitor, CanVisitImplicitMemberInitializations) {
    134   ConstructExprVisitor Visitor;
    135   Visitor.setShouldVisitImplicitCode(true);
    136   Visitor.ExpectMatch("WithCtor", 2, 8);
    137   // Simple has a constructor that implicitly initializes 'w'.  Test
    138   // that a visitor that visits implicit code visits that initialization.
    139   // Note: Clang lazily instantiates implicit declarations, so we need
    140   // to use them in order to force them to appear in the AST.
    141   EXPECT_TRUE(Visitor.runOver(
    142       "struct WithCtor { WithCtor(); }; \n"
    143       "struct Simple { WithCtor w; }; \n"
    144       "int main() { Simple s; }\n"));
    145 }
    146 
    147 // The same as CanVisitImplicitMemberInitializations, but checking that the
    148 // visits are omitted when the visitor does not include implicit code.
    149 TEST(RecursiveASTVisitor, CanSkipImplicitMemberInitializations) {
    150   ConstructExprVisitor Visitor;
    151   Visitor.setShouldVisitImplicitCode(false);
    152   Visitor.DisallowMatch("WithCtor", 2, 8);
    153   // Simple has a constructor that implicitly initializes 'w'.  Test
    154   // that a visitor that skips implicit code skips that initialization.
    155   // Note: Clang lazily instantiates implicit declarations, so we need
    156   // to use them in order to force them to appear in the AST.
    157   EXPECT_TRUE(Visitor.runOver(
    158       "struct WithCtor { WithCtor(); }; \n"
    159       "struct Simple { WithCtor w; }; \n"
    160       "int main() { Simple s; }\n"));
    161 }
    162 
    163 class DeclRefExprVisitor : public ExpectedLocationVisitor<DeclRefExprVisitor> {
    164 public:
    165   bool VisitDeclRefExpr(DeclRefExpr *Reference) {
    166     Match(Reference->getNameInfo().getAsString(), Reference->getLocation());
    167     return true;
    168   }
    169 };
    170 
    171 TEST(RecursiveASTVisitor, VisitsBaseClassTemplateArguments) {
    172   DeclRefExprVisitor Visitor;
    173   Visitor.ExpectMatch("x", 2, 3);
    174   EXPECT_TRUE(Visitor.runOver(
    175     "void x(); template <void (*T)()> class X {};\nX<x> y;"));
    176 }
    177 
    178 TEST(RecursiveASTVisitor, VisitsCXXForRangeStmtRange) {
    179   DeclRefExprVisitor Visitor;
    180   Visitor.ExpectMatch("x", 2, 25);
    181   Visitor.ExpectMatch("x", 2, 30);
    182   EXPECT_TRUE(Visitor.runOver(
    183     "int x[5];\n"
    184     "void f() { for (int i : x) { x[0] = 1; } }",
    185     DeclRefExprVisitor::Lang_CXX11));
    186 }
    187 
    188 TEST(RecursiveASTVisitor, VisitsCallExpr) {
    189   DeclRefExprVisitor Visitor;
    190   Visitor.ExpectMatch("x", 1, 22);
    191   EXPECT_TRUE(Visitor.runOver(
    192     "void x(); void y() { x(); }"));
    193 }
    194 
    195 /* FIXME: According to Richard Smith this is a bug in the AST.
    196 TEST(RecursiveASTVisitor, VisitsBaseClassTemplateArgumentsInInstantiation) {
    197   DeclRefExprVisitor Visitor;
    198   Visitor.ExpectMatch("x", 3, 43);
    199   EXPECT_TRUE(Visitor.runOver(
    200     "template <typename T> void x();\n"
    201     "template <void (*T)()> class X {};\n"
    202     "template <typename T> class Y : public X< x<T> > {};\n"
    203     "Y<int> y;"));
    204 }
    205 */
    206 
    207 TEST(RecursiveASTVisitor, VisitsExtension) {
    208   DeclRefExprVisitor Visitor;
    209   Visitor.ExpectMatch("s", 1, 24);
    210   EXPECT_TRUE(Visitor.runOver(
    211     "int s = __extension__ (s);\n"));
    212 }
    213 
    214 TEST(RecursiveASTVisitor, VisitsCopyExprOfBlockDeclCapture) {
    215   DeclRefExprVisitor Visitor;
    216   Visitor.ExpectMatch("x", 3, 24);
    217   EXPECT_TRUE(Visitor.runOver("void f(int(^)(int)); \n"
    218                               "void g() { \n"
    219                               "  f([&](int x){ return x; }); \n"
    220                               "}",
    221                               DeclRefExprVisitor::Lang_OBJCXX11));
    222 }
    223 
    224 } // end anonymous namespace
    225