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 #include <stack>
     12 
     13 using namespace clang;
     14 
     15 namespace {
     16 
     17 class LambdaExprVisitor : public ExpectedLocationVisitor<LambdaExprVisitor> {
     18 public:
     19   bool VisitLambdaExpr(LambdaExpr *Lambda) {
     20     PendingBodies.push(Lambda);
     21     Match("", Lambda->getIntroducerRange().getBegin());
     22     return true;
     23   }
     24   /// For each call to VisitLambdaExpr, we expect a subsequent call (with
     25   /// proper nesting) to TraverseLambdaBody.
     26   bool TraverseLambdaBody(LambdaExpr *Lambda) {
     27     EXPECT_FALSE(PendingBodies.empty());
     28     EXPECT_EQ(PendingBodies.top(), Lambda);
     29     PendingBodies.pop();
     30     return TraverseStmt(Lambda->getBody());
     31   }
     32   /// Determine whether TraverseLambdaBody has been called for every call to
     33   /// VisitLambdaExpr.
     34   bool allBodiesHaveBeenTraversed() const {
     35     return PendingBodies.empty();
     36   }
     37 private:
     38   std::stack<LambdaExpr *> PendingBodies;
     39 };
     40 
     41 TEST(RecursiveASTVisitor, VisitsLambdaExpr) {
     42   LambdaExprVisitor Visitor;
     43   Visitor.ExpectMatch("", 1, 12);
     44   EXPECT_TRUE(Visitor.runOver("void f() { []{ return; }(); }",
     45                               LambdaExprVisitor::Lang_CXX11));
     46 }
     47 
     48 TEST(RecursiveASTVisitor, TraverseLambdaBodyCanBeOverridden) {
     49   LambdaExprVisitor Visitor;
     50   EXPECT_TRUE(Visitor.runOver("void f() { []{ return; }(); }",
     51                               LambdaExprVisitor::Lang_CXX11));
     52   EXPECT_TRUE(Visitor.allBodiesHaveBeenTraversed());
     53 }
     54 
     55 // Matches the (optional) capture-default of a lambda-introducer.
     56 class LambdaDefaultCaptureVisitor
     57   : public ExpectedLocationVisitor<LambdaDefaultCaptureVisitor> {
     58 public:
     59   bool VisitLambdaExpr(LambdaExpr *Lambda) {
     60     if (Lambda->getCaptureDefault() != LCD_None) {
     61       Match("", Lambda->getCaptureDefaultLoc());
     62     }
     63     return true;
     64   }
     65 };
     66 
     67 TEST(RecursiveASTVisitor, HasCaptureDefaultLoc) {
     68   LambdaDefaultCaptureVisitor Visitor;
     69   Visitor.ExpectMatch("", 1, 20);
     70   EXPECT_TRUE(Visitor.runOver("void f() { int a; [=]{a;}; }",
     71                               LambdaDefaultCaptureVisitor::Lang_CXX11));
     72 }
     73 
     74 // Checks for lambda classes that are not marked as implicitly-generated.
     75 // (There should be none.)
     76 class ClassVisitor : public ExpectedLocationVisitor<ClassVisitor> {
     77 public:
     78   ClassVisitor() : SawNonImplicitLambdaClass(false) {}
     79   bool VisitCXXRecordDecl(CXXRecordDecl* record) {
     80     if (record->isLambda() && !record->isImplicit())
     81       SawNonImplicitLambdaClass = true;
     82     return true;
     83   }
     84 
     85   bool sawOnlyImplicitLambdaClasses() const {
     86     return !SawNonImplicitLambdaClass;
     87   }
     88 
     89 private:
     90   bool SawNonImplicitLambdaClass;
     91 };
     92 
     93 TEST(RecursiveASTVisitor, LambdaClosureTypesAreImplicit) {
     94   ClassVisitor Visitor;
     95   EXPECT_TRUE(Visitor.runOver("auto lambda = []{};", ClassVisitor::Lang_CXX11));
     96   EXPECT_TRUE(Visitor.sawOnlyImplicitLambdaClasses());
     97 }
     98 
     99 
    100 // Check to ensure that attributes and expressions within them are being
    101 // visited.
    102 class AttrVisitor : public ExpectedLocationVisitor<AttrVisitor> {
    103 public:
    104   bool VisitMemberExpr(MemberExpr *ME) {
    105     Match(ME->getMemberDecl()->getNameAsString(), ME->getLocStart());
    106     return true;
    107   }
    108   bool VisitAttr(Attr *A) {
    109     Match("Attr", A->getLocation());
    110     return true;
    111   }
    112   bool VisitGuardedByAttr(GuardedByAttr *A) {
    113     Match("guarded_by", A->getLocation());
    114     return true;
    115   }
    116 };
    117 
    118 
    119 TEST(RecursiveASTVisitor, AttributesAreVisited) {
    120   AttrVisitor Visitor;
    121   Visitor.ExpectMatch("Attr", 4, 24);
    122   Visitor.ExpectMatch("guarded_by", 4, 24);
    123   Visitor.ExpectMatch("mu1",  4, 35);
    124   Visitor.ExpectMatch("Attr", 5, 29);
    125   Visitor.ExpectMatch("mu1",  5, 54);
    126   Visitor.ExpectMatch("mu2",  5, 59);
    127   EXPECT_TRUE(Visitor.runOver(
    128     "class Foo {\n"
    129     "  int mu1;\n"
    130     "  int mu2;\n"
    131     "  int a __attribute__((guarded_by(mu1)));\n"
    132     "  void bar() __attribute__((exclusive_locks_required(mu1, mu2)));\n"
    133     "};\n"));
    134 }
    135 
    136 // Check to ensure that VarDecls are visited.
    137 class VarDeclVisitor : public ExpectedLocationVisitor<VarDeclVisitor> {
    138 public:
    139   bool VisitVarDecl(VarDecl *VD) {
    140     Match(VD->getNameAsString(), VD->getLocStart());
    141     return true;
    142   }
    143 };
    144 
    145 TEST(RecursiveASTVisitor, ArrayInitializersAreVisited) {
    146   VarDeclVisitor Visitor;
    147   Visitor.ExpectMatch("__i0", 1, 8);
    148   EXPECT_TRUE(
    149       Visitor.runOver("struct MyClass {\n"
    150                       "  int c[1];\n"
    151                       "  static MyClass Create() { return MyClass(); }\n"
    152                       "};\n"));
    153 }
    154 
    155 } // end anonymous namespace
    156