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