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 std::string Code = "class Y { public: void x(); }; void z() { Y y; y.x(); }"; 202 EXPECT_FALSE(matches(Code, CallExpr0)); 203 EXPECT_TRUE(matches(Code, CallExpr1)); 204 205 Code = "class Z { public: void z() { this->z(); } };"; 206 EXPECT_TRUE(matches(Code, CallExpr0)); 207 EXPECT_FALSE(matches(Code, CallExpr1)); 208 209 Matcher<Decl> DeclDecl = declaratorDecl(hasTypeLoc( 210 constructMatcher( 211 "loc", constructMatcher("asString", StringRef("const double *"))) 212 .getTypedMatcher<TypeLoc>())); 213 214 Matcher<NestedNameSpecifierLoc> NNSL = 215 constructMatcher( 216 "loc", VariantMatcher::SingleMatcher(nestedNameSpecifier( 217 specifiesType(hasDeclaration(recordDecl(hasName("A"))))))) 218 .getTypedMatcher<NestedNameSpecifierLoc>(); 219 220 Code = "const double * x = 0;"; 221 EXPECT_TRUE(matches(Code, DeclDecl)); 222 EXPECT_FALSE(matches(Code, NNSL)); 223 224 Code = "struct A { struct B {}; }; A::B a_b;"; 225 EXPECT_FALSE(matches(Code, DeclDecl)); 226 EXPECT_TRUE(matches(Code, NNSL)); 227 } 228 229 TEST_F(RegistryTest, PolymorphicMatchers) { 230 const VariantMatcher IsDefinition = constructMatcher("isDefinition"); 231 Matcher<Decl> Var = 232 constructMatcher("varDecl", IsDefinition).getTypedMatcher<Decl>(); 233 Matcher<Decl> Class = 234 constructMatcher("recordDecl", IsDefinition).getTypedMatcher<Decl>(); 235 Matcher<Decl> Func = 236 constructMatcher("functionDecl", IsDefinition).getTypedMatcher<Decl>(); 237 EXPECT_TRUE(matches("int a;", Var)); 238 EXPECT_FALSE(matches("extern int a;", Var)); 239 EXPECT_TRUE(matches("class A {};", Class)); 240 EXPECT_FALSE(matches("class A;", Class)); 241 EXPECT_TRUE(matches("void f(){};", Func)); 242 EXPECT_FALSE(matches("void f();", Func)); 243 244 Matcher<Decl> Anything = constructMatcher("anything").getTypedMatcher<Decl>(); 245 Matcher<Decl> RecordDecl = constructMatcher( 246 "recordDecl", constructMatcher("hasName", StringRef("Foo")), 247 VariantMatcher::SingleMatcher(Anything)).getTypedMatcher<Decl>(); 248 249 EXPECT_TRUE(matches("int Foo;", Anything)); 250 EXPECT_TRUE(matches("class Foo {};", Anything)); 251 EXPECT_TRUE(matches("void Foo(){};", Anything)); 252 EXPECT_FALSE(matches("int Foo;", RecordDecl)); 253 EXPECT_TRUE(matches("class Foo {};", RecordDecl)); 254 EXPECT_FALSE(matches("void Foo(){};", RecordDecl)); 255 256 Matcher<Stmt> ConstructExpr = constructMatcher( 257 "cxxConstructExpr", 258 constructMatcher( 259 "hasDeclaration", 260 constructMatcher( 261 "cxxMethodDecl", 262 constructMatcher( 263 "ofClass", constructMatcher("hasName", StringRef("Foo")))))) 264 .getTypedMatcher<Stmt>(); 265 EXPECT_FALSE(matches("class Foo { public: Foo(); };", ConstructExpr)); 266 EXPECT_TRUE( 267 matches("class Foo { public: Foo(); }; Foo foo = Foo();", ConstructExpr)); 268 } 269 270 TEST_F(RegistryTest, TemplateArgument) { 271 Matcher<Decl> HasTemplateArgument = constructMatcher( 272 "classTemplateSpecializationDecl", 273 constructMatcher( 274 "hasAnyTemplateArgument", 275 constructMatcher("refersToType", 276 constructMatcher("asString", StringRef("int"))))) 277 .getTypedMatcher<Decl>(); 278 EXPECT_TRUE(matches("template<typename T> class A {}; A<int> a;", 279 HasTemplateArgument)); 280 EXPECT_FALSE(matches("template<typename T> class A {}; A<char> a;", 281 HasTemplateArgument)); 282 } 283 284 TEST_F(RegistryTest, TypeTraversal) { 285 Matcher<Type> M = constructMatcher( 286 "pointerType", 287 constructMatcher("pointee", constructMatcher("isConstQualified"), 288 constructMatcher("isInteger"))).getTypedMatcher<Type>(); 289 EXPECT_FALSE(matches("int *a;", M)); 290 EXPECT_TRUE(matches("int const *b;", M)); 291 292 M = constructMatcher( 293 "arrayType", 294 constructMatcher("hasElementType", constructMatcher("builtinType"))) 295 .getTypedMatcher<Type>(); 296 EXPECT_FALSE(matches("struct A{}; A a[7];;", M)); 297 EXPECT_TRUE(matches("int b[7];", M)); 298 } 299 300 TEST_F(RegistryTest, CXXCtorInitializer) { 301 Matcher<Decl> CtorDecl = constructMatcher( 302 "cxxConstructorDecl", 303 constructMatcher( 304 "hasAnyConstructorInitializer", 305 constructMatcher("forField", 306 constructMatcher("hasName", StringRef("foo"))))) 307 .getTypedMatcher<Decl>(); 308 EXPECT_TRUE(matches("struct Foo { Foo() : foo(1) {} int foo; };", CtorDecl)); 309 EXPECT_FALSE(matches("struct Foo { Foo() {} int foo; };", CtorDecl)); 310 EXPECT_FALSE(matches("struct Foo { Foo() : bar(1) {} int bar; };", CtorDecl)); 311 } 312 313 TEST_F(RegistryTest, Adaptative) { 314 Matcher<Decl> D = constructMatcher( 315 "recordDecl", 316 constructMatcher( 317 "has", 318 constructMatcher("recordDecl", 319 constructMatcher("hasName", StringRef("X"))))) 320 .getTypedMatcher<Decl>(); 321 EXPECT_TRUE(matches("class X {};", D)); 322 EXPECT_TRUE(matches("class Y { class X {}; };", D)); 323 EXPECT_FALSE(matches("class Y { class Z {}; };", D)); 324 325 Matcher<Stmt> S = constructMatcher( 326 "forStmt", 327 constructMatcher( 328 "hasDescendant", 329 constructMatcher("varDecl", 330 constructMatcher("hasName", StringRef("X"))))) 331 .getTypedMatcher<Stmt>(); 332 EXPECT_TRUE(matches("void foo() { for(int X;;); }", S)); 333 EXPECT_TRUE(matches("void foo() { for(;;) { int X; } }", S)); 334 EXPECT_FALSE(matches("void foo() { for(;;); }", S)); 335 EXPECT_FALSE(matches("void foo() { if (int X = 0){} }", S)); 336 337 S = constructMatcher( 338 "compoundStmt", constructMatcher("hasParent", constructMatcher("ifStmt"))) 339 .getTypedMatcher<Stmt>(); 340 EXPECT_TRUE(matches("void foo() { if (true) { int x = 42; } }", S)); 341 EXPECT_FALSE(matches("void foo() { if (true) return; }", S)); 342 } 343 344 TEST_F(RegistryTest, VariadicOp) { 345 Matcher<Decl> D = constructMatcher( 346 "anyOf", 347 constructMatcher("recordDecl", 348 constructMatcher("hasName", StringRef("Foo"))), 349 constructMatcher("functionDecl", 350 constructMatcher("hasName", StringRef("foo")))) 351 .getTypedMatcher<Decl>(); 352 353 EXPECT_TRUE(matches("void foo(){}", D)); 354 EXPECT_TRUE(matches("struct Foo{};", D)); 355 EXPECT_FALSE(matches("int i = 0;", D)); 356 357 D = constructMatcher( 358 "allOf", constructMatcher("recordDecl"), 359 constructMatcher( 360 "namedDecl", 361 constructMatcher("anyOf", 362 constructMatcher("hasName", StringRef("Foo")), 363 constructMatcher("hasName", StringRef("Bar"))))) 364 .getTypedMatcher<Decl>(); 365 366 EXPECT_FALSE(matches("void foo(){}", D)); 367 EXPECT_TRUE(matches("struct Foo{};", D)); 368 EXPECT_FALSE(matches("int i = 0;", D)); 369 EXPECT_TRUE(matches("class Bar{};", D)); 370 EXPECT_FALSE(matches("class OtherBar{};", D)); 371 372 D = recordDecl( 373 has(fieldDecl(hasName("Foo"))), 374 constructMatcher( 375 "unless", 376 constructMatcher("namedDecl", 377 constructMatcher("hasName", StringRef("Bar")))) 378 .getTypedMatcher<Decl>()); 379 380 EXPECT_FALSE(matches("class Bar{ int Foo; };", D)); 381 EXPECT_TRUE(matches("class OtherBar{ int Foo; };", D)); 382 383 D = constructMatcher( 384 "namedDecl", constructMatcher("hasName", StringRef("Foo")), 385 constructMatcher("unless", constructMatcher("recordDecl"))) 386 .getTypedMatcher<Decl>(); 387 EXPECT_TRUE(matches("void Foo(){}", D)); 388 EXPECT_TRUE(notMatches("struct Foo {};", D)); 389 } 390 391 TEST_F(RegistryTest, Errors) { 392 // Incorrect argument count. 393 std::unique_ptr<Diagnostics> Error(new Diagnostics()); 394 EXPECT_TRUE(constructMatcher("hasInitializer", Error.get()).isNull()); 395 EXPECT_EQ("Incorrect argument count. (Expected = 1) != (Actual = 0)", 396 Error->toString()); 397 Error.reset(new Diagnostics()); 398 EXPECT_TRUE(constructMatcher("isArrow", StringRef(), Error.get()).isNull()); 399 EXPECT_EQ("Incorrect argument count. (Expected = 0) != (Actual = 1)", 400 Error->toString()); 401 Error.reset(new Diagnostics()); 402 EXPECT_TRUE(constructMatcher("anyOf", Error.get()).isNull()); 403 EXPECT_EQ("Incorrect argument count. (Expected = (2, )) != (Actual = 0)", 404 Error->toString()); 405 Error.reset(new Diagnostics()); 406 EXPECT_TRUE(constructMatcher("unless", StringRef(), StringRef(), 407 Error.get()).isNull()); 408 EXPECT_EQ("Incorrect argument count. (Expected = (1, 1)) != (Actual = 2)", 409 Error->toString()); 410 411 // Bad argument type 412 Error.reset(new Diagnostics()); 413 EXPECT_TRUE(constructMatcher("ofClass", StringRef(), Error.get()).isNull()); 414 EXPECT_EQ("Incorrect type for arg 1. (Expected = Matcher<CXXRecordDecl>) != " 415 "(Actual = String)", 416 Error->toString()); 417 Error.reset(new Diagnostics()); 418 EXPECT_TRUE( 419 constructMatcher("cxxRecordDecl", constructMatcher("cxxRecordDecl"), 420 constructMatcher("parameterCountIs", 3), Error.get()) 421 .isNull()); 422 EXPECT_EQ("Incorrect type for arg 2. (Expected = Matcher<CXXRecordDecl>) != " 423 "(Actual = Matcher<FunctionDecl|FunctionProtoType>)", 424 Error->toString()); 425 426 // Bad argument type with variadic. 427 Error.reset(new Diagnostics()); 428 EXPECT_TRUE(constructMatcher("anyOf", StringRef(), StringRef(), 429 Error.get()).isNull()); 430 EXPECT_EQ( 431 "Incorrect type for arg 1. (Expected = Matcher<>) != (Actual = String)", 432 Error->toString()); 433 Error.reset(new Diagnostics()); 434 EXPECT_TRUE(constructMatcher( 435 "cxxRecordDecl", 436 constructMatcher("allOf", 437 constructMatcher("isDerivedFrom", StringRef("FOO")), 438 constructMatcher("isArrow")), 439 Error.get()).isNull()); 440 EXPECT_EQ("Incorrect type for arg 1. " 441 "(Expected = Matcher<CXXRecordDecl>) != " 442 "(Actual = Matcher<CXXRecordDecl|ObjCInterfaceDecl>&Matcher" 443 "<MemberExpr|UnresolvedMemberExpr|CXXDependentScopeMemberExpr>)", 444 Error->toString()); 445 } 446 447 TEST_F(RegistryTest, Completion) { 448 CompVector Comps = getCompletions(); 449 // Overloaded 450 EXPECT_TRUE(hasCompletion( 451 Comps, "hasParent(", 452 "Matcher<NestedNameSpecifierLoc|TypeLoc|Decl|...> " 453 "hasParent(Matcher<NestedNameSpecifierLoc|TypeLoc|Decl|...>)")); 454 // Variadic. 455 EXPECT_TRUE(hasCompletion(Comps, "whileStmt(", 456 "Matcher<Stmt> whileStmt(Matcher<WhileStmt>...)")); 457 // Polymorphic. 458 EXPECT_TRUE(hasCompletion( 459 Comps, "hasDescendant(", 460 "Matcher<NestedNameSpecifierLoc|QualType|TypeLoc|...> " 461 "hasDescendant(Matcher<NestedNameSpecifierLoc|QualType|TypeLoc|...>)")); 462 463 CompVector WhileComps = getCompletions("whileStmt", 0); 464 465 EXPECT_TRUE(hasCompletion(WhileComps, "hasBody(", 466 "Matcher<WhileStmt> hasBody(Matcher<Stmt>)")); 467 EXPECT_TRUE(hasCompletion( 468 WhileComps, "hasParent(", 469 "Matcher<Stmt> " 470 "hasParent(Matcher<NestedNameSpecifierLoc|TypeLoc|Decl|...>)")); 471 EXPECT_TRUE( 472 hasCompletion(WhileComps, "allOf(", "Matcher<T> allOf(Matcher<T>...)")); 473 474 EXPECT_FALSE(hasCompletion(WhileComps, "whileStmt(")); 475 EXPECT_FALSE(hasCompletion(WhileComps, "ifStmt(")); 476 477 CompVector AllOfWhileComps = 478 getCompletions("allOf", 0, "whileStmt", 0); 479 ASSERT_EQ(AllOfWhileComps.size(), WhileComps.size()); 480 EXPECT_TRUE(std::equal(WhileComps.begin(), WhileComps.end(), 481 AllOfWhileComps.begin())); 482 483 CompVector DeclWhileComps = 484 getCompletions("decl", 0, "whileStmt", 0); 485 EXPECT_EQ(0u, DeclWhileComps.size()); 486 487 CompVector NamedDeclComps = getCompletions("namedDecl", 0); 488 EXPECT_TRUE( 489 hasCompletion(NamedDeclComps, "isPublic()", "Matcher<Decl> isPublic()")); 490 EXPECT_TRUE(hasCompletion(NamedDeclComps, "hasName(\"", 491 "Matcher<NamedDecl> hasName(string)")); 492 493 // Heterogeneous overloads. 494 Comps = getCompletions("classTemplateSpecializationDecl", 0); 495 EXPECT_TRUE(hasCompletion( 496 Comps, "isSameOrDerivedFrom(", 497 "Matcher<CXXRecordDecl> isSameOrDerivedFrom(string|Matcher<NamedDecl>)")); 498 } 499 500 TEST_F(RegistryTest, NodeType) { 501 EXPECT_TRUE(Registry::nodeMatcherType(*lookupMatcherCtor("callExpr")).isSame(ASTNodeKind::getFromNodeKind<CallExpr>())); 502 EXPECT_TRUE(Registry::nodeMatcherType(*lookupMatcherCtor("has")).isNone()); 503 EXPECT_TRUE(Registry::nodeMatcherType(*lookupMatcherCtor("allOf")).isNone()); 504 } 505 506 TEST_F(RegistryTest, HasArgs) { 507 Matcher<Decl> Value = constructMatcher( 508 "decl", constructMatcher("hasAttr", StringRef("attr::WarnUnused"))) 509 .getTypedMatcher<Decl>(); 510 EXPECT_TRUE(matches("struct __attribute__((warn_unused)) X {};", Value)); 511 EXPECT_FALSE(matches("struct X {};", Value)); 512 } 513 514 TEST_F(RegistryTest, ParenExpr) { 515 Matcher<Stmt> Value = constructMatcher("parenExpr").getTypedMatcher<Stmt>(); 516 EXPECT_TRUE(matches("int i = (1);", traverse(TK_AsIs, Value))); 517 EXPECT_FALSE(matches("int i = 1;", traverse(TK_AsIs, Value))); 518 } 519 520 TEST_F(RegistryTest, EqualsMatcher) { 521 Matcher<Stmt> BooleanStmt = constructMatcher( 522 "cxxBoolLiteral", constructMatcher("equals", VariantValue(true))) 523 .getTypedMatcher<Stmt>(); 524 EXPECT_TRUE(matches("bool x = true;", BooleanStmt)); 525 EXPECT_FALSE(matches("bool x = false;", BooleanStmt)); 526 EXPECT_FALSE(matches("bool x = 0;", BooleanStmt)); 527 528 BooleanStmt = constructMatcher( 529 "cxxBoolLiteral", constructMatcher("equals", VariantValue(0))) 530 .getTypedMatcher<Stmt>(); 531 EXPECT_TRUE(matches("bool x = false;", BooleanStmt)); 532 EXPECT_FALSE(matches("bool x = true;", BooleanStmt)); 533 EXPECT_FALSE(matches("bool x = 0;", BooleanStmt)); 534 535 Matcher<Stmt> DoubleStmt = constructMatcher( 536 "floatLiteral", constructMatcher("equals", VariantValue(1.2))) 537 .getTypedMatcher<Stmt>(); 538 EXPECT_TRUE(matches("double x = 1.2;", DoubleStmt)); 539 #if 0 540 // FIXME floatLiteral matching should work regardless of suffix. 541 EXPECT_TRUE(matches("double x = 1.2f;", DoubleStmt)); 542 EXPECT_TRUE(matches("double x = 1.2l;", DoubleStmt)); 543 #endif 544 EXPECT_TRUE(matches("double x = 12e-1;", DoubleStmt)); 545 EXPECT_FALSE(matches("double x = 1.23;", DoubleStmt)); 546 547 Matcher<Stmt> IntegerStmt = constructMatcher( 548 "integerLiteral", constructMatcher("equals", VariantValue(42))) 549 .getTypedMatcher<Stmt>(); 550 EXPECT_TRUE(matches("int x = 42;", IntegerStmt)); 551 EXPECT_FALSE(matches("int x = 1;", IntegerStmt)); 552 553 Matcher<Stmt> CharStmt = constructMatcher( 554 "characterLiteral", constructMatcher("equals", VariantValue('x'))) 555 .getTypedMatcher<Stmt>(); 556 EXPECT_TRUE(matches("int x = 'x';", CharStmt)); 557 EXPECT_TRUE(matches("int x = L'x';", CharStmt)); 558 EXPECT_TRUE(matches("int x = u'x';", CharStmt)); 559 EXPECT_TRUE(matches("int x = U'x';", CharStmt)); 560 EXPECT_FALSE(matches("int x = 120;", CharStmt)); 561 } 562 563 } // end anonymous namespace 564 } // end namespace dynamic 565 } // end namespace ast_matchers 566 } // end namespace clang 567