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 13using namespace clang; 14 15namespace { 16 17class ParenExprVisitor : public ExpectedLocationVisitor<ParenExprVisitor> { 18public: 19 bool VisitParenExpr(ParenExpr *Parens) { 20 Match("", Parens->getExprLoc()); 21 return true; 22 } 23}; 24 25TEST(RecursiveASTVisitor, VisitsParensDuringDataRecursion) { 26 ParenExprVisitor Visitor; 27 Visitor.ExpectMatch("", 1, 9); 28 EXPECT_TRUE(Visitor.runOver("int k = (4) + 9;\n")); 29} 30 31class TemplateArgumentLocTraverser 32 : public ExpectedLocationVisitor<TemplateArgumentLocTraverser> { 33public: 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 46TEST(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 55class CXXBoolLiteralExprVisitor 56 : public ExpectedLocationVisitor<CXXBoolLiteralExprVisitor> { 57public: 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 67TEST(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. 77class ImplicitCtorVisitor 78 : public ExpectedLocationVisitor<ImplicitCtorVisitor> { 79public: 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 92TEST(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. 109class ConstructExprVisitor 110 : public ExpectedLocationVisitor<ConstructExprVisitor> { 111public: 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 133TEST(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. 149TEST(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 163class DeclRefExprVisitor : public ExpectedLocationVisitor<DeclRefExprVisitor> { 164public: 165 bool VisitDeclRefExpr(DeclRefExpr *Reference) { 166 Match(Reference->getNameInfo().getAsString(), Reference->getLocation()); 167 return true; 168 } 169}; 170 171TEST(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 178TEST(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 188TEST(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. 196TEST(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 207TEST(RecursiveASTVisitor, VisitsExtension) { 208 DeclRefExprVisitor Visitor; 209 Visitor.ExpectMatch("s", 1, 24); 210 EXPECT_TRUE(Visitor.runOver( 211 "int s = __extension__ (s);\n")); 212} 213 214TEST(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