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