1 //===- unittest/ASTMatchers/Dynamic/RegistryTest.cpp - Registry unit tests -===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===-----------------------------------------------------------------------===// 8 9 #include "../ASTMatchersTest.h" 10 #include "clang/ASTMatchers/Dynamic/Registry.h" 11 #include "gtest/gtest.h" 12 #include <vector> 13 14 namespace clang { 15 namespace ast_matchers { 16 namespace dynamic { 17 namespace { 18 19 using ast_matchers::internal::Matcher; 20 21 class RegistryTest : public ::testing::Test { 22 public: 23 std::vector<ParserValue> Args() { return std::vector<ParserValue>(); } 24 std::vector<ParserValue> Args(const VariantValue &Arg1) { 25 std::vector<ParserValue> Out(1); 26 Out[0].Value = Arg1; 27 return Out; 28 } 29 std::vector<ParserValue> Args(const VariantValue &Arg1, 30 const VariantValue &Arg2) { 31 std::vector<ParserValue> Out(2); 32 Out[0].Value = Arg1; 33 Out[1].Value = Arg2; 34 return Out; 35 } 36 37 llvm::Optional<MatcherCtor> lookupMatcherCtor(StringRef MatcherName) { 38 return Registry::lookupMatcherCtor(MatcherName); 39 } 40 41 VariantMatcher constructMatcher(StringRef MatcherName, 42 Diagnostics *Error = nullptr) { 43 Diagnostics DummyError; 44 if (!Error) Error = &DummyError; 45 llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName); 46 VariantMatcher Out; 47 if (Ctor) 48 Out = Registry::constructMatcher(*Ctor, SourceRange(), Args(), Error); 49 EXPECT_EQ("", DummyError.toStringFull()); 50 return Out; 51 } 52 53 VariantMatcher constructMatcher(StringRef MatcherName, 54 const VariantValue &Arg1, 55 Diagnostics *Error = nullptr) { 56 Diagnostics DummyError; 57 if (!Error) Error = &DummyError; 58 llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName); 59 VariantMatcher Out; 60 if (Ctor) 61 Out = Registry::constructMatcher(*Ctor, SourceRange(), Args(Arg1), Error); 62 EXPECT_EQ("", DummyError.toStringFull()) << MatcherName; 63 return Out; 64 } 65 66 VariantMatcher constructMatcher(StringRef MatcherName, 67 const VariantValue &Arg1, 68 const VariantValue &Arg2, 69 Diagnostics *Error = nullptr) { 70 Diagnostics DummyError; 71 if (!Error) Error = &DummyError; 72 llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName); 73 VariantMatcher Out; 74 if (Ctor) 75 Out = Registry::constructMatcher(*Ctor, SourceRange(), Args(Arg1, Arg2), 76 Error); 77 EXPECT_EQ("", DummyError.toStringFull()); 78 return Out; 79 } 80 81 typedef std::vector<MatcherCompletion> CompVector; 82 83 CompVector getCompletions() { 84 std::vector<std::pair<MatcherCtor, unsigned> > Context; 85 return Registry::getMatcherCompletions( 86 Registry::getAcceptedCompletionTypes(Context)); 87 } 88 89 CompVector getCompletions(StringRef MatcherName1, unsigned ArgNo1) { 90 std::vector<std::pair<MatcherCtor, unsigned> > Context; 91 llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName1); 92 if (!Ctor) 93 return CompVector(); 94 Context.push_back(std::make_pair(*Ctor, ArgNo1)); 95 return Registry::getMatcherCompletions( 96 Registry::getAcceptedCompletionTypes(Context)); 97 } 98 99 CompVector getCompletions(StringRef MatcherName1, unsigned ArgNo1, 100 StringRef MatcherName2, unsigned ArgNo2) { 101 std::vector<std::pair<MatcherCtor, unsigned> > Context; 102 llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName1); 103 if (!Ctor) 104 return CompVector(); 105 Context.push_back(std::make_pair(*Ctor, ArgNo1)); 106 Ctor = lookupMatcherCtor(MatcherName2); 107 if (!Ctor) 108 return CompVector(); 109 Context.push_back(std::make_pair(*Ctor, ArgNo2)); 110 return Registry::getMatcherCompletions( 111 Registry::getAcceptedCompletionTypes(Context)); 112 } 113 114 bool hasCompletion(const CompVector &Comps, StringRef TypedText, 115 StringRef MatcherDecl = StringRef()) { 116 for (CompVector::const_iterator I = Comps.begin(), E = Comps.end(); I != E; 117 ++I) { 118 if (I->TypedText == TypedText && 119 (MatcherDecl.empty() || I->MatcherDecl == MatcherDecl)) { 120 return true; 121 } 122 } 123 return false; 124 } 125 }; 126 127 TEST_F(RegistryTest, CanConstructNoArgs) { 128 Matcher<Stmt> IsArrowValue = constructMatcher( 129 "memberExpr", constructMatcher("isArrow")).getTypedMatcher<Stmt>(); 130 Matcher<Stmt> BoolValue = 131 constructMatcher("cxxBoolLiteral").getTypedMatcher<Stmt>(); 132 133 const std::string ClassSnippet = "struct Foo { int x; };\n" 134 "Foo *foo = new Foo;\n" 135 "int i = foo->x;\n"; 136 const std::string BoolSnippet = "bool Foo = true;\n"; 137 138 EXPECT_TRUE(matches(ClassSnippet, IsArrowValue)); 139 EXPECT_TRUE(matches(BoolSnippet, BoolValue)); 140 EXPECT_FALSE(matches(ClassSnippet, BoolValue)); 141 EXPECT_FALSE(matches(BoolSnippet, IsArrowValue)); 142 } 143 144 TEST_F(RegistryTest, ConstructWithSimpleArgs) { 145 Matcher<Decl> Value = constructMatcher( 146 "namedDecl", constructMatcher("hasName", StringRef("X"))) 147 .getTypedMatcher<Decl>(); 148 EXPECT_TRUE(matches("class X {};", Value)); 149 EXPECT_FALSE(matches("int x;", Value)); 150 151 Value = functionDecl(constructMatcher("parameterCountIs", 2) 152 .getTypedMatcher<FunctionDecl>()); 153 EXPECT_TRUE(matches("void foo(int,int);", Value)); 154 EXPECT_FALSE(matches("void foo(int);", Value)); 155 } 156 157 TEST_F(RegistryTest, ConstructWithMatcherArgs) { 158 Matcher<Decl> HasInitializerSimple = constructMatcher( 159 "varDecl", constructMatcher("hasInitializer", constructMatcher("stmt"))) 160 .getTypedMatcher<Decl>(); 161 Matcher<Decl> HasInitializerComplex = constructMatcher( 162 "varDecl", 163 constructMatcher("hasInitializer", constructMatcher("callExpr"))) 164 .getTypedMatcher<Decl>(); 165 166 std::string code = "int i;"; 167 EXPECT_FALSE(matches(code, HasInitializerSimple)); 168 EXPECT_FALSE(matches(code, HasInitializerComplex)); 169 170 code = "int i = 1;"; 171 EXPECT_TRUE(matches(code, HasInitializerSimple)); 172 EXPECT_FALSE(matches(code, HasInitializerComplex)); 173 174 code = "int y(); int i = y();"; 175 EXPECT_TRUE(matches(code, HasInitializerSimple)); 176 EXPECT_TRUE(matches(code, HasInitializerComplex)); 177 178 Matcher<Decl> HasParameter = 179 functionDecl(constructMatcher( 180 "hasParameter", 1, constructMatcher("hasName", StringRef("x"))) 181 .getTypedMatcher<FunctionDecl>()); 182 EXPECT_TRUE(matches("void f(int a, int x);", HasParameter)); 183 EXPECT_FALSE(matches("void f(int x, int a);", HasParameter)); 184 } 185 186 TEST_F(RegistryTest, OverloadedMatchers) { 187 Matcher<Stmt> CallExpr0 = constructMatcher( 188 "callExpr", 189 constructMatcher("callee", constructMatcher("memberExpr", 190 constructMatcher("isArrow")))) 191 .getTypedMatcher<Stmt>(); 192 193 Matcher<Stmt> CallExpr1 = constructMatcher( 194 "callExpr", 195 constructMatcher( 196 "callee", 197 constructMatcher("cxxMethodDecl", 198 constructMatcher("hasName", StringRef("x"))))) 199 .getTypedMatcher<Stmt>(); 200 201 Matcher<Stmt> ObjCMsgExpr = 202 constructMatcher( 203 "objcMessageExpr", 204 constructMatcher( 205 "callee", 206 constructMatcher("objcMethodDecl", 207 constructMatcher("hasName", StringRef("x"))))) 208 .getTypedMatcher<Stmt>(); 209 210 std::string Code = "class Y { public: void x(); }; void z() { Y y; y.x(); }"; 211 EXPECT_FALSE(matches(Code, CallExpr0)); 212 EXPECT_TRUE(matches(Code, CallExpr1)); 213 EXPECT_FALSE(matches(Code, ObjCMsgExpr)); 214 215 Code = "class Z { public: void z() { this->z(); } };"; 216 EXPECT_TRUE(matches(Code, CallExpr0)); 217 EXPECT_FALSE(matches(Code, CallExpr1)); 218 EXPECT_FALSE(matches(Code, ObjCMsgExpr)); 219 220 Code = "@interface I " 221 "+ (void)x; " 222 "@end\n" 223 "int main() { [I x]; }"; 224 EXPECT_FALSE(matchesObjC(Code, CallExpr0)); 225 EXPECT_FALSE(matchesObjC(Code, CallExpr1)); 226 EXPECT_TRUE(matchesObjC(Code, ObjCMsgExpr)); 227 228 Matcher<Decl> DeclDecl = declaratorDecl(hasTypeLoc( 229 constructMatcher( 230 "loc", constructMatcher("asString", StringRef("const double *"))) 231 .getTypedMatcher<TypeLoc>())); 232 233 Matcher<NestedNameSpecifierLoc> NNSL = 234 constructMatcher( 235 "loc", VariantMatcher::SingleMatcher(nestedNameSpecifier( 236 specifiesType(hasDeclaration(recordDecl(hasName("A"))))))) 237 .getTypedMatcher<NestedNameSpecifierLoc>(); 238 239 Code = "const double * x = 0;"; 240 EXPECT_TRUE(matches(Code, DeclDecl)); 241 EXPECT_FALSE(matches(Code, NNSL)); 242 243 Code = "struct A { struct B {}; }; A::B a_b;"; 244 EXPECT_FALSE(matches(Code, DeclDecl)); 245 EXPECT_TRUE(matches(Code, NNSL)); 246 } 247 248 TEST_F(RegistryTest, PolymorphicMatchers) { 249 const VariantMatcher IsDefinition = constructMatcher("isDefinition"); 250 Matcher<Decl> Var = 251 constructMatcher("varDecl", IsDefinition).getTypedMatcher<Decl>(); 252 Matcher<Decl> Class = 253 constructMatcher("recordDecl", IsDefinition).getTypedMatcher<Decl>(); 254 Matcher<Decl> Func = 255 constructMatcher("functionDecl", IsDefinition).getTypedMatcher<Decl>(); 256 EXPECT_TRUE(matches("int a;", Var)); 257 EXPECT_FALSE(matches("extern int a;", Var)); 258 EXPECT_TRUE(matches("class A {};", Class)); 259 EXPECT_FALSE(matches("class A;", Class)); 260 EXPECT_TRUE(matches("void f(){};", Func)); 261 EXPECT_FALSE(matches("void f();", Func)); 262 263 Matcher<Decl> Anything = constructMatcher("anything").getTypedMatcher<Decl>(); 264 Matcher<Decl> RecordDecl = constructMatcher( 265 "recordDecl", constructMatcher("hasName", StringRef("Foo")), 266 VariantMatcher::SingleMatcher(Anything)).getTypedMatcher<Decl>(); 267 268 EXPECT_TRUE(matches("int Foo;", Anything)); 269 EXPECT_TRUE(matches("class Foo {};", Anything)); 270 EXPECT_TRUE(matches("void Foo(){};", Anything)); 271 EXPECT_FALSE(matches("int Foo;", RecordDecl)); 272 EXPECT_TRUE(matches("class Foo {};", RecordDecl)); 273 EXPECT_FALSE(matches("void Foo(){};", RecordDecl)); 274 275 Matcher<Stmt> ConstructExpr = constructMatcher( 276 "cxxConstructExpr", 277 constructMatcher( 278 "hasDeclaration", 279 constructMatcher( 280 "cxxMethodDecl", 281 constructMatcher( 282 "ofClass", constructMatcher("hasName", StringRef("Foo")))))) 283 .getTypedMatcher<Stmt>(); 284 EXPECT_FALSE(matches("class Foo { public: Foo(); };", ConstructExpr)); 285 EXPECT_TRUE( 286 matches("class Foo { public: Foo(); }; Foo foo = Foo();", ConstructExpr)); 287 } 288 289 TEST_F(RegistryTest, TemplateArgument) { 290 Matcher<Decl> HasTemplateArgument = constructMatcher( 291 "classTemplateSpecializationDecl", 292 constructMatcher( 293 "hasAnyTemplateArgument", 294 constructMatcher("refersToType", 295 constructMatcher("asString", StringRef("int"))))) 296 .getTypedMatcher<Decl>(); 297 EXPECT_TRUE(matches("template<typename T> class A {}; A<int> a;", 298 HasTemplateArgument)); 299 EXPECT_FALSE(matches("template<typename T> class A {}; A<char> a;", 300 HasTemplateArgument)); 301 } 302 303 TEST_F(RegistryTest, TypeTraversal) { 304 Matcher<Type> M = constructMatcher( 305 "pointerType", 306 constructMatcher("pointee", constructMatcher("isConstQualified"), 307 constructMatcher("isInteger"))).getTypedMatcher<Type>(); 308 EXPECT_FALSE(matches("int *a;", M)); 309 EXPECT_TRUE(matches("int const *b;", M)); 310 311 M = constructMatcher( 312 "arrayType", 313 constructMatcher("hasElementType", constructMatcher("builtinType"))) 314 .getTypedMatcher<Type>(); 315 EXPECT_FALSE(matches("struct A{}; A a[7];;", M)); 316 EXPECT_TRUE(matches("int b[7];", M)); 317 } 318 319 TEST_F(RegistryTest, CXXBaseSpecifier) { 320 // TODO: rewrite with top-level cxxBaseSpecifier matcher when available 321 DeclarationMatcher ClassHasAnyDirectBase = 322 constructMatcher("cxxRecordDecl", 323 constructMatcher("hasDirectBase", 324 constructMatcher("cxxBaseSpecifier"))) 325 .getTypedMatcher<Decl>(); 326 EXPECT_TRUE(matches("class X {}; class Y : X {};", ClassHasAnyDirectBase)); 327 EXPECT_TRUE(notMatches("class X {};", ClassHasAnyDirectBase)); 328 } 329 330 TEST_F(RegistryTest, CXXCtorInitializer) { 331 Matcher<Decl> CtorDecl = constructMatcher( 332 "cxxConstructorDecl", 333 constructMatcher( 334 "hasAnyConstructorInitializer", 335 constructMatcher("forField", 336 constructMatcher("hasName", StringRef("foo"))))) 337 .getTypedMatcher<Decl>(); 338 EXPECT_TRUE(matches("struct Foo { Foo() : foo(1) {} int foo; };", CtorDecl)); 339 EXPECT_FALSE(matches("struct Foo { Foo() {} int foo; };", CtorDecl)); 340 EXPECT_FALSE(matches("struct Foo { Foo() : bar(1) {} int bar; };", CtorDecl)); 341 } 342 343 TEST_F(RegistryTest, Adaptative) { 344 Matcher<Decl> D = constructMatcher( 345 "recordDecl", 346 constructMatcher( 347 "has", 348 constructMatcher("recordDecl", 349 constructMatcher("hasName", StringRef("X"))))) 350 .getTypedMatcher<Decl>(); 351 EXPECT_TRUE(matches("class X {};", D)); 352 EXPECT_TRUE(matches("class Y { class X {}; };", D)); 353 EXPECT_FALSE(matches("class Y { class Z {}; };", D)); 354 355 Matcher<Stmt> S = constructMatcher( 356 "forStmt", 357 constructMatcher( 358 "hasDescendant", 359 constructMatcher("varDecl", 360 constructMatcher("hasName", StringRef("X"))))) 361 .getTypedMatcher<Stmt>(); 362 EXPECT_TRUE(matches("void foo() { for(int X;;); }", S)); 363 EXPECT_TRUE(matches("void foo() { for(;;) { int X; } }", S)); 364 EXPECT_FALSE(matches("void foo() { for(;;); }", S)); 365 EXPECT_FALSE(matches("void foo() { if (int X = 0){} }", S)); 366 367 S = constructMatcher( 368 "compoundStmt", constructMatcher("hasParent", constructMatcher("ifStmt"))) 369 .getTypedMatcher<Stmt>(); 370 EXPECT_TRUE(matches("void foo() { if (true) { int x = 42; } }", S)); 371 EXPECT_FALSE(matches("void foo() { if (true) return; }", S)); 372 } 373 374 TEST_F(RegistryTest, VariadicOp) { 375 Matcher<Decl> D = constructMatcher( 376 "anyOf", 377 constructMatcher("recordDecl", 378 constructMatcher("hasName", StringRef("Foo"))), 379 constructMatcher("functionDecl", 380 constructMatcher("hasName", StringRef("foo")))) 381 .getTypedMatcher<Decl>(); 382 383 EXPECT_TRUE(matches("void foo(){}", D)); 384 EXPECT_TRUE(matches("struct Foo{};", D)); 385 EXPECT_FALSE(matches("int i = 0;", D)); 386 387 D = constructMatcher( 388 "allOf", constructMatcher("recordDecl"), 389 constructMatcher( 390 "namedDecl", 391 constructMatcher("anyOf", 392 constructMatcher("hasName", StringRef("Foo")), 393 constructMatcher("hasName", StringRef("Bar"))))) 394 .getTypedMatcher<Decl>(); 395 396 EXPECT_FALSE(matches("void foo(){}", D)); 397 EXPECT_TRUE(matches("struct Foo{};", D)); 398 EXPECT_FALSE(matches("int i = 0;", D)); 399 EXPECT_TRUE(matches("class Bar{};", D)); 400 EXPECT_FALSE(matches("class OtherBar{};", D)); 401 402 D = recordDecl( 403 has(fieldDecl(hasName("Foo"))), 404 constructMatcher( 405 "unless", 406 constructMatcher("namedDecl", 407 constructMatcher("hasName", StringRef("Bar")))) 408 .getTypedMatcher<Decl>()); 409 410 EXPECT_FALSE(matches("class Bar{ int Foo; };", D)); 411 EXPECT_TRUE(matches("class OtherBar{ int Foo; };", D)); 412 413 D = constructMatcher( 414 "namedDecl", constructMatcher("hasName", StringRef("Foo")), 415 constructMatcher("unless", constructMatcher("recordDecl"))) 416 .getTypedMatcher<Decl>(); 417 EXPECT_TRUE(matches("void Foo(){}", D)); 418 EXPECT_TRUE(notMatches("struct Foo {};", D)); 419 } 420 421 TEST_F(RegistryTest, Errors) { 422 // Incorrect argument count. 423 std::unique_ptr<Diagnostics> Error(new Diagnostics()); 424 EXPECT_TRUE(constructMatcher("hasInitializer", Error.get()).isNull()); 425 EXPECT_EQ("Incorrect argument count. (Expected = 1) != (Actual = 0)", 426 Error->toString()); 427 Error.reset(new Diagnostics()); 428 EXPECT_TRUE(constructMatcher("isArrow", StringRef(), Error.get()).isNull()); 429 EXPECT_EQ("Incorrect argument count. (Expected = 0) != (Actual = 1)", 430 Error->toString()); 431 Error.reset(new Diagnostics()); 432 EXPECT_TRUE(constructMatcher("anyOf", Error.get()).isNull()); 433 EXPECT_EQ("Incorrect argument count. (Expected = (2, )) != (Actual = 0)", 434 Error->toString()); 435 Error.reset(new Diagnostics()); 436 EXPECT_TRUE(constructMatcher("unless", StringRef(), StringRef(), 437 Error.get()).isNull()); 438 EXPECT_EQ("Incorrect argument count. (Expected = (1, 1)) != (Actual = 2)", 439 Error->toString()); 440 441 // Bad argument type 442 Error.reset(new Diagnostics()); 443 EXPECT_TRUE(constructMatcher("ofClass", StringRef(), Error.get()).isNull()); 444 EXPECT_EQ("Incorrect type for arg 1. (Expected = Matcher<CXXRecordDecl>) != " 445 "(Actual = String)", 446 Error->toString()); 447 Error.reset(new Diagnostics()); 448 EXPECT_TRUE( 449 constructMatcher("cxxRecordDecl", constructMatcher("cxxRecordDecl"), 450 constructMatcher("parameterCountIs", 3), Error.get()) 451 .isNull()); 452 EXPECT_EQ("Incorrect type for arg 2. (Expected = Matcher<CXXRecordDecl>) != " 453 "(Actual = Matcher<FunctionDecl|FunctionProtoType>)", 454 Error->toString()); 455 456 // Bad argument type with variadic. 457 Error.reset(new Diagnostics()); 458 EXPECT_TRUE(constructMatcher("anyOf", StringRef(), StringRef(), 459 Error.get()).isNull()); 460 EXPECT_EQ( 461 "Incorrect type for arg 1. (Expected = Matcher<>) != (Actual = String)", 462 Error->toString()); 463 Error.reset(new Diagnostics()); 464 EXPECT_TRUE(constructMatcher( 465 "cxxRecordDecl", 466 constructMatcher("allOf", 467 constructMatcher("isDerivedFrom", StringRef("FOO")), 468 constructMatcher("isArrow")), 469 Error.get()).isNull()); 470 EXPECT_EQ("Incorrect type for arg 1. " 471 "(Expected = Matcher<CXXRecordDecl>) != " 472 "(Actual = Matcher<CXXRecordDecl|ObjCInterfaceDecl>&Matcher" 473 "<MemberExpr|UnresolvedMemberExpr|CXXDependentScopeMemberExpr>)", 474 Error->toString()); 475 } 476 477 TEST_F(RegistryTest, Completion) { 478 CompVector Comps = getCompletions(); 479 // Overloaded 480 EXPECT_TRUE(hasCompletion( 481 Comps, "hasParent(", 482 "Matcher<NestedNameSpecifierLoc|TypeLoc|Decl|...> " 483 "hasParent(Matcher<NestedNameSpecifierLoc|TypeLoc|Decl|...>)")); 484 // Variadic. 485 EXPECT_TRUE(hasCompletion(Comps, "whileStmt(", 486 "Matcher<Stmt> whileStmt(Matcher<WhileStmt>...)")); 487 // Polymorphic. 488 EXPECT_TRUE(hasCompletion( 489 Comps, "hasDescendant(", 490 "Matcher<NestedNameSpecifierLoc|QualType|TypeLoc|...> " 491 "hasDescendant(Matcher<NestedNameSpecifierLoc|QualType|TypeLoc|...>)")); 492 493 CompVector WhileComps = getCompletions("whileStmt", 0); 494 495 EXPECT_TRUE(hasCompletion(WhileComps, "hasBody(", 496 "Matcher<WhileStmt> hasBody(Matcher<Stmt>)")); 497 EXPECT_TRUE(hasCompletion( 498 WhileComps, "hasParent(", 499 "Matcher<Stmt> " 500 "hasParent(Matcher<NestedNameSpecifierLoc|TypeLoc|Decl|...>)")); 501 EXPECT_TRUE( 502 hasCompletion(WhileComps, "allOf(", "Matcher<T> allOf(Matcher<T>...)")); 503 504 EXPECT_FALSE(hasCompletion(WhileComps, "whileStmt(")); 505 EXPECT_FALSE(hasCompletion(WhileComps, "ifStmt(")); 506 507 CompVector AllOfWhileComps = 508 getCompletions("allOf", 0, "whileStmt", 0); 509 ASSERT_EQ(AllOfWhileComps.size(), WhileComps.size()); 510 EXPECT_TRUE(std::equal(WhileComps.begin(), WhileComps.end(), 511 AllOfWhileComps.begin())); 512 513 CompVector DeclWhileComps = 514 getCompletions("decl", 0, "whileStmt", 0); 515 EXPECT_EQ(0u, DeclWhileComps.size()); 516 517 CompVector NamedDeclComps = getCompletions("namedDecl", 0); 518 EXPECT_TRUE( 519 hasCompletion(NamedDeclComps, "isPublic()", "Matcher<Decl> isPublic()")); 520 EXPECT_TRUE(hasCompletion(NamedDeclComps, "hasName(\"", 521 "Matcher<NamedDecl> hasName(string)")); 522 523 // Heterogeneous overloads. 524 Comps = getCompletions("classTemplateSpecializationDecl", 0); 525 EXPECT_TRUE(hasCompletion( 526 Comps, "isSameOrDerivedFrom(", 527 "Matcher<CXXRecordDecl> isSameOrDerivedFrom(string|Matcher<NamedDecl>)")); 528 } 529 530 TEST_F(RegistryTest, MatcherBuilder) { 531 auto Ctor = *lookupMatcherCtor("mapAnyOf"); 532 EXPECT_TRUE(Registry::isBuilderMatcher(Ctor)); 533 auto BuiltCtor = Registry::buildMatcherCtor(Ctor, {}, Args(ASTNodeKind::getFromNodeKind<WhileStmt>(), ASTNodeKind::getFromNodeKind<ForStmt>()), nullptr); 534 EXPECT_TRUE(BuiltCtor.get()); 535 auto LoopMatcher = Registry::constructMatcher(BuiltCtor.get(), SourceRange(), Args(), nullptr).getTypedMatcher<Stmt>(); 536 EXPECT_TRUE(matches("void f() { for (;;) {} }", LoopMatcher)); 537 EXPECT_TRUE(matches("void f() { while (true) {} }", LoopMatcher)); 538 EXPECT_FALSE(matches("void f() { if (true) {} }", LoopMatcher)); 539 540 auto NotBuiltCtor = Registry::buildMatcherCtor(Ctor, {}, Args(ASTNodeKind::getFromNodeKind<FunctionDecl>(), ASTNodeKind::getFromNodeKind<ForStmt>()), nullptr); 541 EXPECT_FALSE(NotBuiltCtor.get()); 542 } 543 544 TEST_F(RegistryTest, NodeType) { 545 EXPECT_TRUE(Registry::nodeMatcherType(*lookupMatcherCtor("callExpr")).isSame(ASTNodeKind::getFromNodeKind<CallExpr>())); 546 EXPECT_TRUE(Registry::nodeMatcherType(*lookupMatcherCtor("has")).isNone()); 547 EXPECT_TRUE(Registry::nodeMatcherType(*lookupMatcherCtor("allOf")).isNone()); 548 } 549 550 TEST_F(RegistryTest, HasArgs) { 551 Matcher<Decl> Value = constructMatcher( 552 "decl", constructMatcher("hasAttr", StringRef("attr::WarnUnused"))) 553 .getTypedMatcher<Decl>(); 554 EXPECT_TRUE(matches("struct __attribute__((warn_unused)) X {};", Value)); 555 EXPECT_FALSE(matches("struct X {};", Value)); 556 } 557 558 TEST_F(RegistryTest, ParenExpr) { 559 Matcher<Stmt> Value = constructMatcher("parenExpr").getTypedMatcher<Stmt>(); 560 EXPECT_TRUE(matches("int i = (1);", traverse(TK_AsIs, Value))); 561 EXPECT_FALSE(matches("int i = 1;", traverse(TK_AsIs, Value))); 562 } 563 564 TEST_F(RegistryTest, EqualsMatcher) { 565 Matcher<Stmt> BooleanStmt = constructMatcher( 566 "cxxBoolLiteral", constructMatcher("equals", VariantValue(true))) 567 .getTypedMatcher<Stmt>(); 568 EXPECT_TRUE(matches("bool x = true;", BooleanStmt)); 569 EXPECT_FALSE(matches("bool x = false;", BooleanStmt)); 570 EXPECT_FALSE(matches("bool x = 0;", BooleanStmt)); 571 572 BooleanStmt = constructMatcher( 573 "cxxBoolLiteral", constructMatcher("equals", VariantValue(0))) 574 .getTypedMatcher<Stmt>(); 575 EXPECT_TRUE(matches("bool x = false;", BooleanStmt)); 576 EXPECT_FALSE(matches("bool x = true;", BooleanStmt)); 577 EXPECT_FALSE(matches("bool x = 0;", BooleanStmt)); 578 579 Matcher<Stmt> DoubleStmt = constructMatcher( 580 "floatLiteral", constructMatcher("equals", VariantValue(1.2))) 581 .getTypedMatcher<Stmt>(); 582 EXPECT_TRUE(matches("double x = 1.2;", DoubleStmt)); 583 #if 0 584 // FIXME floatLiteral matching should work regardless of suffix. 585 EXPECT_TRUE(matches("double x = 1.2f;", DoubleStmt)); 586 EXPECT_TRUE(matches("double x = 1.2l;", DoubleStmt)); 587 #endif 588 EXPECT_TRUE(matches("double x = 12e-1;", DoubleStmt)); 589 EXPECT_FALSE(matches("double x = 1.23;", DoubleStmt)); 590 591 Matcher<Stmt> IntegerStmt = constructMatcher( 592 "integerLiteral", constructMatcher("equals", VariantValue(42))) 593 .getTypedMatcher<Stmt>(); 594 EXPECT_TRUE(matches("int x = 42;", IntegerStmt)); 595 EXPECT_FALSE(matches("int x = 1;", IntegerStmt)); 596 597 Matcher<Stmt> CharStmt = constructMatcher( 598 "characterLiteral", constructMatcher("equals", VariantValue('x'))) 599 .getTypedMatcher<Stmt>(); 600 EXPECT_TRUE(matches("int x = 'x';", CharStmt)); 601 EXPECT_TRUE(matches("int x = L'x';", CharStmt)); 602 EXPECT_TRUE(matches("int x = u'x';", CharStmt)); 603 EXPECT_TRUE(matches("int x = U'x';", CharStmt)); 604 EXPECT_FALSE(matches("int x = 120;", CharStmt)); 605 } 606 607 } // end anonymous namespace 608 } // end namespace dynamic 609 } // end namespace ast_matchers 610 } // end namespace clang 611