1 //===- unittest/ASTMatchers/Dynamic/RegistryTest.cpp - Registry unit tests -===// 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 "../ASTMatchersTest.h" 11 #include "clang/ASTMatchers/Dynamic/Registry.h" 12 #include "gtest/gtest.h" 13 #include <vector> 14 15 namespace clang { 16 namespace ast_matchers { 17 namespace dynamic { 18 namespace { 19 20 using ast_matchers::internal::Matcher; 21 22 class RegistryTest : public ::testing::Test { 23 public: 24 std::vector<ParserValue> Args() { return std::vector<ParserValue>(); } 25 std::vector<ParserValue> Args(const VariantValue &Arg1) { 26 std::vector<ParserValue> Out(1); 27 Out[0].Value = Arg1; 28 return Out; 29 } 30 std::vector<ParserValue> Args(const VariantValue &Arg1, 31 const VariantValue &Arg2) { 32 std::vector<ParserValue> Out(2); 33 Out[0].Value = Arg1; 34 Out[1].Value = Arg2; 35 return Out; 36 } 37 38 llvm::Optional<MatcherCtor> lookupMatcherCtor(StringRef MatcherName, 39 Diagnostics *Error = 0) { 40 Diagnostics DummyError; 41 if (!Error) Error = &DummyError; 42 llvm::Optional<MatcherCtor> Ctor = 43 Registry::lookupMatcherCtor(MatcherName, SourceRange(), Error); 44 EXPECT_EQ("", DummyError.toStringFull()); 45 return Ctor; 46 } 47 48 VariantMatcher constructMatcher(StringRef MatcherName, 49 Diagnostics *Error = NULL) { 50 Diagnostics DummyError; 51 if (!Error) Error = &DummyError; 52 llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName, Error); 53 VariantMatcher Out; 54 if (Ctor) 55 Out = Registry::constructMatcher(*Ctor, SourceRange(), Args(), Error); 56 EXPECT_EQ("", DummyError.toStringFull()); 57 return Out; 58 } 59 60 VariantMatcher constructMatcher(StringRef MatcherName, 61 const VariantValue &Arg1, 62 Diagnostics *Error = NULL) { 63 Diagnostics DummyError; 64 if (!Error) Error = &DummyError; 65 llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName, Error); 66 VariantMatcher Out; 67 if (Ctor) 68 Out = Registry::constructMatcher(*Ctor, SourceRange(), Args(Arg1), Error); 69 EXPECT_EQ("", DummyError.toStringFull()); 70 return Out; 71 } 72 73 VariantMatcher constructMatcher(StringRef MatcherName, 74 const VariantValue &Arg1, 75 const VariantValue &Arg2, 76 Diagnostics *Error = NULL) { 77 Diagnostics DummyError; 78 if (!Error) Error = &DummyError; 79 llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName, Error); 80 VariantMatcher Out; 81 if (Ctor) 82 Out = Registry::constructMatcher(*Ctor, SourceRange(), Args(Arg1, Arg2), 83 Error); 84 EXPECT_EQ("", DummyError.toStringFull()); 85 return Out; 86 } 87 88 typedef std::vector<MatcherCompletion> CompVector; 89 90 CompVector getCompletions() { 91 return Registry::getCompletions( 92 llvm::ArrayRef<std::pair<MatcherCtor, unsigned> >()); 93 } 94 95 CompVector getCompletions(StringRef MatcherName1, unsigned ArgNo1) { 96 std::vector<std::pair<MatcherCtor, unsigned> > Context; 97 llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName1); 98 if (!Ctor) 99 return CompVector(); 100 Context.push_back(std::make_pair(*Ctor, ArgNo1)); 101 return Registry::getCompletions(Context); 102 } 103 104 CompVector getCompletions(StringRef MatcherName1, unsigned ArgNo1, 105 StringRef MatcherName2, unsigned ArgNo2) { 106 std::vector<std::pair<MatcherCtor, unsigned> > Context; 107 llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName1); 108 if (!Ctor) 109 return CompVector(); 110 Context.push_back(std::make_pair(*Ctor, ArgNo1)); 111 Ctor = lookupMatcherCtor(MatcherName2); 112 if (!Ctor) 113 return CompVector(); 114 Context.push_back(std::make_pair(*Ctor, ArgNo2)); 115 return Registry::getCompletions(Context); 116 } 117 118 bool hasCompletion(const CompVector &Comps, StringRef TypedText, 119 StringRef MatcherDecl = StringRef(), unsigned *Index = 0) { 120 for (CompVector::const_iterator I = Comps.begin(), E = Comps.end(); I != E; 121 ++I) { 122 if (I->TypedText == TypedText && 123 (MatcherDecl.empty() || I->MatcherDecl == MatcherDecl)) { 124 if (Index) 125 *Index = I - Comps.begin(); 126 return true; 127 } 128 } 129 return false; 130 } 131 }; 132 133 TEST_F(RegistryTest, CanConstructNoArgs) { 134 Matcher<Stmt> IsArrowValue = constructMatcher( 135 "memberExpr", constructMatcher("isArrow")).getTypedMatcher<Stmt>(); 136 Matcher<Stmt> BoolValue = 137 constructMatcher("boolLiteral").getTypedMatcher<Stmt>(); 138 139 const std::string ClassSnippet = "struct Foo { int x; };\n" 140 "Foo *foo = new Foo;\n" 141 "int i = foo->x;\n"; 142 const std::string BoolSnippet = "bool Foo = true;\n"; 143 144 EXPECT_TRUE(matches(ClassSnippet, IsArrowValue)); 145 EXPECT_TRUE(matches(BoolSnippet, BoolValue)); 146 EXPECT_FALSE(matches(ClassSnippet, BoolValue)); 147 EXPECT_FALSE(matches(BoolSnippet, IsArrowValue)); 148 } 149 150 TEST_F(RegistryTest, ConstructWithSimpleArgs) { 151 Matcher<Decl> Value = constructMatcher( 152 "namedDecl", constructMatcher("hasName", std::string("X"))) 153 .getTypedMatcher<Decl>(); 154 EXPECT_TRUE(matches("class X {};", Value)); 155 EXPECT_FALSE(matches("int x;", Value)); 156 157 Value = functionDecl(constructMatcher("parameterCountIs", 2) 158 .getTypedMatcher<FunctionDecl>()); 159 EXPECT_TRUE(matches("void foo(int,int);", Value)); 160 EXPECT_FALSE(matches("void foo(int);", Value)); 161 } 162 163 TEST_F(RegistryTest, ConstructWithMatcherArgs) { 164 Matcher<Decl> HasInitializerSimple = constructMatcher( 165 "varDecl", constructMatcher("hasInitializer", constructMatcher("stmt"))) 166 .getTypedMatcher<Decl>(); 167 Matcher<Decl> HasInitializerComplex = constructMatcher( 168 "varDecl", 169 constructMatcher("hasInitializer", constructMatcher("callExpr"))) 170 .getTypedMatcher<Decl>(); 171 172 std::string code = "int i;"; 173 EXPECT_FALSE(matches(code, HasInitializerSimple)); 174 EXPECT_FALSE(matches(code, HasInitializerComplex)); 175 176 code = "int i = 1;"; 177 EXPECT_TRUE(matches(code, HasInitializerSimple)); 178 EXPECT_FALSE(matches(code, HasInitializerComplex)); 179 180 code = "int y(); int i = y();"; 181 EXPECT_TRUE(matches(code, HasInitializerSimple)); 182 EXPECT_TRUE(matches(code, HasInitializerComplex)); 183 184 Matcher<Decl> HasParameter = 185 functionDecl(constructMatcher( 186 "hasParameter", 1, constructMatcher("hasName", std::string("x"))) 187 .getTypedMatcher<FunctionDecl>()); 188 EXPECT_TRUE(matches("void f(int a, int x);", HasParameter)); 189 EXPECT_FALSE(matches("void f(int x, int a);", HasParameter)); 190 } 191 192 TEST_F(RegistryTest, OverloadedMatchers) { 193 Matcher<Stmt> CallExpr0 = constructMatcher( 194 "callExpr", 195 constructMatcher("callee", constructMatcher("memberExpr", 196 constructMatcher("isArrow")))) 197 .getTypedMatcher<Stmt>(); 198 199 Matcher<Stmt> CallExpr1 = constructMatcher( 200 "callExpr", 201 constructMatcher( 202 "callee", 203 constructMatcher("methodDecl", 204 constructMatcher("hasName", std::string("x"))))) 205 .getTypedMatcher<Stmt>(); 206 207 std::string Code = "class Y { public: void x(); }; void z() { Y y; y.x(); }"; 208 EXPECT_FALSE(matches(Code, CallExpr0)); 209 EXPECT_TRUE(matches(Code, CallExpr1)); 210 211 Code = "class Z { public: void z() { this->z(); } };"; 212 EXPECT_TRUE(matches(Code, CallExpr0)); 213 EXPECT_FALSE(matches(Code, CallExpr1)); 214 } 215 216 TEST_F(RegistryTest, PolymorphicMatchers) { 217 const VariantMatcher IsDefinition = constructMatcher("isDefinition"); 218 Matcher<Decl> Var = 219 constructMatcher("varDecl", IsDefinition).getTypedMatcher<Decl>(); 220 Matcher<Decl> Class = 221 constructMatcher("recordDecl", IsDefinition).getTypedMatcher<Decl>(); 222 Matcher<Decl> Func = 223 constructMatcher("functionDecl", IsDefinition).getTypedMatcher<Decl>(); 224 EXPECT_TRUE(matches("int a;", Var)); 225 EXPECT_FALSE(matches("extern int a;", Var)); 226 EXPECT_TRUE(matches("class A {};", Class)); 227 EXPECT_FALSE(matches("class A;", Class)); 228 EXPECT_TRUE(matches("void f(){};", Func)); 229 EXPECT_FALSE(matches("void f();", Func)); 230 231 Matcher<Decl> Anything = constructMatcher("anything").getTypedMatcher<Decl>(); 232 Matcher<Decl> RecordDecl = constructMatcher( 233 "recordDecl", constructMatcher("hasName", std::string("Foo")), 234 VariantMatcher::SingleMatcher(Anything)).getTypedMatcher<Decl>(); 235 236 EXPECT_TRUE(matches("int Foo;", Anything)); 237 EXPECT_TRUE(matches("class Foo {};", Anything)); 238 EXPECT_TRUE(matches("void Foo(){};", Anything)); 239 EXPECT_FALSE(matches("int Foo;", RecordDecl)); 240 EXPECT_TRUE(matches("class Foo {};", RecordDecl)); 241 EXPECT_FALSE(matches("void Foo(){};", RecordDecl)); 242 243 Matcher<Stmt> ConstructExpr = constructMatcher( 244 "constructExpr", 245 constructMatcher( 246 "hasDeclaration", 247 constructMatcher( 248 "methodDecl", 249 constructMatcher( 250 "ofClass", constructMatcher("hasName", std::string("Foo")))))) 251 .getTypedMatcher<Stmt>(); 252 EXPECT_FALSE(matches("class Foo { public: Foo(); };", ConstructExpr)); 253 EXPECT_TRUE( 254 matches("class Foo { public: Foo(); }; Foo foo = Foo();", ConstructExpr)); 255 } 256 257 TEST_F(RegistryTest, TemplateArgument) { 258 Matcher<Decl> HasTemplateArgument = constructMatcher( 259 "classTemplateSpecializationDecl", 260 constructMatcher( 261 "hasAnyTemplateArgument", 262 constructMatcher("refersToType", 263 constructMatcher("asString", std::string("int"))))) 264 .getTypedMatcher<Decl>(); 265 EXPECT_TRUE(matches("template<typename T> class A {}; A<int> a;", 266 HasTemplateArgument)); 267 EXPECT_FALSE(matches("template<typename T> class A {}; A<char> a;", 268 HasTemplateArgument)); 269 } 270 271 TEST_F(RegistryTest, TypeTraversal) { 272 Matcher<Type> M = constructMatcher( 273 "pointerType", 274 constructMatcher("pointee", constructMatcher("isConstQualified"), 275 constructMatcher("isInteger"))).getTypedMatcher<Type>(); 276 EXPECT_FALSE(matches("int *a;", M)); 277 EXPECT_TRUE(matches("int const *b;", M)); 278 279 M = constructMatcher( 280 "arrayType", 281 constructMatcher("hasElementType", constructMatcher("builtinType"))) 282 .getTypedMatcher<Type>(); 283 EXPECT_FALSE(matches("struct A{}; A a[7];;", M)); 284 EXPECT_TRUE(matches("int b[7];", M)); 285 } 286 287 TEST_F(RegistryTest, CXXCtorInitializer) { 288 Matcher<Decl> CtorDecl = constructMatcher( 289 "constructorDecl", 290 constructMatcher( 291 "hasAnyConstructorInitializer", 292 constructMatcher("forField", 293 constructMatcher("hasName", std::string("foo"))))) 294 .getTypedMatcher<Decl>(); 295 EXPECT_TRUE(matches("struct Foo { Foo() : foo(1) {} int foo; };", CtorDecl)); 296 EXPECT_FALSE(matches("struct Foo { Foo() {} int foo; };", CtorDecl)); 297 EXPECT_FALSE(matches("struct Foo { Foo() : bar(1) {} int bar; };", CtorDecl)); 298 } 299 300 TEST_F(RegistryTest, Adaptative) { 301 Matcher<Decl> D = constructMatcher( 302 "recordDecl", 303 constructMatcher( 304 "has", 305 constructMatcher("recordDecl", 306 constructMatcher("hasName", std::string("X"))))) 307 .getTypedMatcher<Decl>(); 308 EXPECT_TRUE(matches("class X {};", D)); 309 EXPECT_TRUE(matches("class Y { class X {}; };", D)); 310 EXPECT_FALSE(matches("class Y { class Z {}; };", D)); 311 312 Matcher<Stmt> S = constructMatcher( 313 "forStmt", 314 constructMatcher( 315 "hasDescendant", 316 constructMatcher("varDecl", 317 constructMatcher("hasName", std::string("X"))))) 318 .getTypedMatcher<Stmt>(); 319 EXPECT_TRUE(matches("void foo() { for(int X;;); }", S)); 320 EXPECT_TRUE(matches("void foo() { for(;;) { int X; } }", S)); 321 EXPECT_FALSE(matches("void foo() { for(;;); }", S)); 322 EXPECT_FALSE(matches("void foo() { if (int X = 0){} }", S)); 323 324 S = constructMatcher( 325 "compoundStmt", constructMatcher("hasParent", constructMatcher("ifStmt"))) 326 .getTypedMatcher<Stmt>(); 327 EXPECT_TRUE(matches("void foo() { if (true) { int x = 42; } }", S)); 328 EXPECT_FALSE(matches("void foo() { if (true) return; }", S)); 329 } 330 331 TEST_F(RegistryTest, VariadicOp) { 332 Matcher<Decl> D = constructMatcher( 333 "anyOf", 334 constructMatcher("recordDecl", 335 constructMatcher("hasName", std::string("Foo"))), 336 constructMatcher("namedDecl", 337 constructMatcher("hasName", std::string("foo")))) 338 .getTypedMatcher<Decl>(); 339 340 EXPECT_TRUE(matches("void foo(){}", D)); 341 EXPECT_TRUE(matches("struct Foo{};", D)); 342 EXPECT_FALSE(matches("int i = 0;", D)); 343 344 D = constructMatcher( 345 "allOf", constructMatcher("recordDecl"), 346 constructMatcher( 347 "namedDecl", 348 constructMatcher("anyOf", 349 constructMatcher("hasName", std::string("Foo")), 350 constructMatcher("hasName", std::string("Bar"))))) 351 .getTypedMatcher<Decl>(); 352 353 EXPECT_FALSE(matches("void foo(){}", D)); 354 EXPECT_TRUE(matches("struct Foo{};", D)); 355 EXPECT_FALSE(matches("int i = 0;", D)); 356 EXPECT_TRUE(matches("class Bar{};", D)); 357 EXPECT_FALSE(matches("class OtherBar{};", D)); 358 359 D = recordDecl( 360 has(fieldDecl(hasName("Foo"))), 361 constructMatcher( 362 "unless", 363 constructMatcher("namedDecl", 364 constructMatcher("hasName", std::string("Bar")))) 365 .getTypedMatcher<Decl>()); 366 367 EXPECT_FALSE(matches("class Bar{ int Foo; };", D)); 368 EXPECT_TRUE(matches("class OtherBar{ int Foo; };", D)); 369 } 370 371 TEST_F(RegistryTest, Errors) { 372 // Incorrect argument count. 373 OwningPtr<Diagnostics> Error(new Diagnostics()); 374 EXPECT_TRUE(constructMatcher("hasInitializer", Error.get()).isNull()); 375 EXPECT_EQ("Incorrect argument count. (Expected = 1) != (Actual = 0)", 376 Error->toString()); 377 Error.reset(new Diagnostics()); 378 EXPECT_TRUE(constructMatcher("isArrow", std::string(), Error.get()).isNull()); 379 EXPECT_EQ("Incorrect argument count. (Expected = 0) != (Actual = 1)", 380 Error->toString()); 381 Error.reset(new Diagnostics()); 382 EXPECT_TRUE(constructMatcher("anyOf", Error.get()).isNull()); 383 EXPECT_EQ("Incorrect argument count. (Expected = (2, )) != (Actual = 0)", 384 Error->toString()); 385 Error.reset(new Diagnostics()); 386 EXPECT_TRUE(constructMatcher("unless", std::string(), std::string(), 387 Error.get()).isNull()); 388 EXPECT_EQ("Incorrect argument count. (Expected = (1, 1)) != (Actual = 2)", 389 Error->toString()); 390 391 // Bad argument type 392 Error.reset(new Diagnostics()); 393 EXPECT_TRUE(constructMatcher("ofClass", std::string(), Error.get()).isNull()); 394 EXPECT_EQ("Incorrect type for arg 1. (Expected = Matcher<CXXRecordDecl>) != " 395 "(Actual = String)", 396 Error->toString()); 397 Error.reset(new Diagnostics()); 398 EXPECT_TRUE(constructMatcher("recordDecl", constructMatcher("recordDecl"), 399 constructMatcher("parameterCountIs", 3), 400 Error.get()).isNull()); 401 EXPECT_EQ("Incorrect type for arg 2. (Expected = Matcher<CXXRecordDecl>) != " 402 "(Actual = Matcher<FunctionDecl>)", 403 Error->toString()); 404 405 // Bad argument type with variadic. 406 Error.reset(new Diagnostics()); 407 EXPECT_TRUE(constructMatcher("anyOf", std::string(), std::string(), 408 Error.get()).isNull()); 409 EXPECT_EQ( 410 "Incorrect type for arg 1. (Expected = Matcher<>) != (Actual = String)", 411 Error->toString()); 412 Error.reset(new Diagnostics()); 413 EXPECT_TRUE(constructMatcher( 414 "recordDecl", 415 constructMatcher("allOf", 416 constructMatcher("isDerivedFrom", std::string("FOO")), 417 constructMatcher("isArrow")), 418 Error.get()).isNull()); 419 EXPECT_EQ("Incorrect type for arg 1. " 420 "(Expected = Matcher<CXXRecordDecl>) != " 421 "(Actual = Matcher<CXXRecordDecl>&Matcher<MemberExpr>)", 422 Error->toString()); 423 } 424 425 TEST_F(RegistryTest, Completion) { 426 CompVector Comps = getCompletions(); 427 EXPECT_TRUE(hasCompletion( 428 Comps, "hasParent(", "Matcher<Decl|Stmt> hasParent(Matcher<Decl|Stmt>)")); 429 EXPECT_TRUE(hasCompletion(Comps, "whileStmt(", 430 "Matcher<Stmt> whileStmt(Matcher<WhileStmt>...)")); 431 432 CompVector WhileComps = getCompletions("whileStmt", 0); 433 434 unsigned HasBodyIndex, HasParentIndex, AllOfIndex; 435 EXPECT_TRUE(hasCompletion(WhileComps, "hasBody(", 436 "Matcher<WhileStmt> hasBody(Matcher<Stmt>)", 437 &HasBodyIndex)); 438 EXPECT_TRUE(hasCompletion(WhileComps, "hasParent(", 439 "Matcher<Stmt> hasParent(Matcher<Decl|Stmt>)", 440 &HasParentIndex)); 441 EXPECT_TRUE(hasCompletion(WhileComps, "allOf(", 442 "Matcher<T> allOf(Matcher<T>...)", &AllOfIndex)); 443 EXPECT_GT(HasParentIndex, HasBodyIndex); 444 EXPECT_GT(AllOfIndex, HasParentIndex); 445 446 EXPECT_FALSE(hasCompletion(WhileComps, "whileStmt(")); 447 EXPECT_FALSE(hasCompletion(WhileComps, "ifStmt(")); 448 449 CompVector AllOfWhileComps = 450 getCompletions("allOf", 0, "whileStmt", 0); 451 ASSERT_EQ(AllOfWhileComps.size(), WhileComps.size()); 452 EXPECT_TRUE(std::equal(WhileComps.begin(), WhileComps.end(), 453 AllOfWhileComps.begin())); 454 455 CompVector DeclWhileComps = 456 getCompletions("decl", 0, "whileStmt", 0); 457 EXPECT_EQ(0u, DeclWhileComps.size()); 458 459 CompVector NamedDeclComps = getCompletions("namedDecl", 0); 460 EXPECT_TRUE( 461 hasCompletion(NamedDeclComps, "isPublic()", "Matcher<Decl> isPublic()")); 462 EXPECT_TRUE(hasCompletion(NamedDeclComps, "hasName(\"", 463 "Matcher<NamedDecl> hasName(string)")); 464 } 465 466 } // end anonymous namespace 467 } // end namespace dynamic 468 } // end namespace ast_matchers 469 } // end namespace clang 470