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 = []{};",
     96 			      ClassVisitor::Lang_CXX11));
     97   EXPECT_TRUE(Visitor.sawOnlyImplicitLambdaClasses());
     98 }
     99 
    100 
    101 // Check to ensure that attributes and expressions within them are being
    102 // visited.
    103 class AttrVisitor : public ExpectedLocationVisitor<AttrVisitor> {
    104 public:
    105   bool VisitMemberExpr(MemberExpr *ME) {
    106     Match(ME->getMemberDecl()->getNameAsString(), ME->getLocStart());
    107     return true;
    108   }
    109   bool VisitAttr(Attr *A) {
    110     Match("Attr", A->getLocation());
    111     return true;
    112   }
    113   bool VisitGuardedByAttr(GuardedByAttr *A) {
    114     Match("guarded_by", A->getLocation());
    115     return true;
    116   }
    117 };
    118 
    119 
    120 TEST(RecursiveASTVisitor, AttributesAreVisited) {
    121   AttrVisitor Visitor;
    122   Visitor.ExpectMatch("Attr", 4, 24);
    123   Visitor.ExpectMatch("guarded_by", 4, 24);
    124   Visitor.ExpectMatch("mu1",  4, 35);
    125   Visitor.ExpectMatch("Attr", 5, 29);
    126   Visitor.ExpectMatch("mu1",  5, 54);
    127   Visitor.ExpectMatch("mu2",  5, 59);
    128   EXPECT_TRUE(Visitor.runOver(
    129     "class Foo {\n"
    130     "  int mu1;\n"
    131     "  int mu2;\n"
    132     "  int a __attribute__((guarded_by(mu1)));\n"
    133     "  void bar() __attribute__((exclusive_locks_required(mu1, mu2)));\n"
    134     "};\n"));
    135 }
    136 
    137 } // end anonymous namespace
    138