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:
Args()23 std::vector<ParserValue> Args() { return std::vector<ParserValue>(); }
Args(const VariantValue & Arg1)24 std::vector<ParserValue> Args(const VariantValue &Arg1) {
25 std::vector<ParserValue> Out(1);
26 Out[0].Value = Arg1;
27 return Out;
28 }
Args(const VariantValue & Arg1,const VariantValue & Arg2)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
lookupMatcherCtor(StringRef MatcherName)37 llvm::Optional<MatcherCtor> lookupMatcherCtor(StringRef MatcherName) {
38 return Registry::lookupMatcherCtor(MatcherName);
39 }
40
constructMatcher(StringRef MatcherName,Diagnostics * Error=nullptr)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
constructMatcher(StringRef MatcherName,const VariantValue & Arg1,Diagnostics * Error=nullptr)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
constructMatcher(StringRef MatcherName,const VariantValue & Arg1,const VariantValue & Arg2,Diagnostics * Error=nullptr)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
getCompletions()83 CompVector getCompletions() {
84 std::vector<std::pair<MatcherCtor, unsigned> > Context;
85 return Registry::getMatcherCompletions(
86 Registry::getAcceptedCompletionTypes(Context));
87 }
88
getCompletions(StringRef MatcherName1,unsigned ArgNo1)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
getCompletions(StringRef MatcherName1,unsigned ArgNo1,StringRef MatcherName2,unsigned ArgNo2)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
hasCompletion(const CompVector & Comps,StringRef TypedText,StringRef MatcherDecl=StringRef ())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
TEST_F(RegistryTest,CanConstructNoArgs)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
TEST_F(RegistryTest,ConstructWithSimpleArgs)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
TEST_F(RegistryTest,ConstructWithMatcherArgs)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
TEST_F(RegistryTest,OverloadedMatchers)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
TEST_F(RegistryTest,PolymorphicMatchers)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
TEST_F(RegistryTest,TemplateArgument)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
TEST_F(RegistryTest,TypeTraversal)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
TEST_F(RegistryTest,CXXBaseSpecifier)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
TEST_F(RegistryTest,CXXCtorInitializer)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
TEST_F(RegistryTest,Adaptative)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
TEST_F(RegistryTest,VariadicOp)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
TEST_F(RegistryTest,Errors)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
TEST_F(RegistryTest,Completion)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
TEST_F(RegistryTest,MatcherBuilder)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
TEST_F(RegistryTest,NodeType)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
TEST_F(RegistryTest,HasArgs)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
TEST_F(RegistryTest,ParenExpr)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
TEST_F(RegistryTest,EqualsMatcher)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