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