xref: /llvm-project/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp (revision a87dc23a6271cadd6d3f93561f2d8b1661399e6d)
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-exception
6 //
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 
15 namespace clang {
16 namespace ast_matchers {
17 namespace dynamic {
18 namespace {
19 
20 using ast_matchers::internal::Matcher;
21 
22 class RegistryTest : public ::testing::Test {
23 public:
Args()24   std::vector<ParserValue> Args() { return std::vector<ParserValue>(); }
Args(const VariantValue & Arg1)25   std::vector<ParserValue> Args(const VariantValue &Arg1) {
26     std::vector<ParserValue> Out(1);
27     Out[0].Value = Arg1;
28     return Out;
29   }
Args(const VariantValue & Arg1,const VariantValue & Arg2)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 
lookupMatcherCtor(StringRef MatcherName)38   std::optional<MatcherCtor> lookupMatcherCtor(StringRef MatcherName) {
39     return Registry::lookupMatcherCtor(MatcherName);
40   }
41 
constructMatcher(StringRef MatcherName,Diagnostics * Error=nullptr)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 
constructMatcher(StringRef MatcherName,const VariantValue & Arg1,Diagnostics * Error=nullptr)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 
constructMatcher(StringRef MatcherName,const VariantValue & Arg1,const VariantValue & Arg2,Diagnostics * Error=nullptr)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 
getCompletions()84   CompVector getCompletions() {
85     std::vector<std::pair<MatcherCtor, unsigned> > Context;
86     return Registry::getMatcherCompletions(
87         Registry::getAcceptedCompletionTypes(Context));
88   }
89 
getCompletions(StringRef MatcherName1,unsigned ArgNo1)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 
getCompletions(StringRef MatcherName1,unsigned ArgNo1,StringRef MatcherName2,unsigned ArgNo2)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 
hasCompletion(const CompVector & Comps,StringRef TypedText,StringRef MatcherDecl=StringRef ())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 
TEST_F(RegistryTest,CanConstructNoArgs)128 TEST_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 
TEST_F(RegistryTest,ConstructWithSimpleArgs)145 TEST_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 
TEST_F(RegistryTest,ConstructWithMatcherArgs)158 TEST_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 
TEST_F(RegistryTest,OverloadedMatchers)187 TEST_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 
TEST_F(RegistryTest,PolymorphicMatchers)249 TEST_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 
TEST_F(RegistryTest,TemplateArgument)290 TEST_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 
TEST_F(RegistryTest,TypeTraversal)304 TEST_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 
TEST_F(RegistryTest,CXXBaseSpecifier)320 TEST_F(RegistryTest, CXXBaseSpecifier) {
321   // TODO: rewrite with top-level cxxBaseSpecifier matcher when available
322   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 
TEST_F(RegistryTest,CXXCtorInitializer)331 TEST_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 
TEST_F(RegistryTest,Adaptative)344 TEST_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 
TEST_F(RegistryTest,VariadicOp)375 TEST_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 
TEST_F(RegistryTest,Errors)422 TEST_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 type
443   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 
TEST_F(RegistryTest,Completion)478 TEST_F(RegistryTest, Completion) {
479   CompVector Comps = getCompletions();
480   // Overloaded
481   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 
TEST_F(RegistryTest,MatcherBuilder)531 TEST_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 
TEST_F(RegistryTest,NodeType)545 TEST_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 
TEST_F(RegistryTest,HasArgs)551 TEST_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 
TEST_F(RegistryTest,ParenExpr)559 TEST_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 
TEST_F(RegistryTest,EqualsMatcher)565 TEST_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 0
585   // 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 #endif
589   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 namespace
609 } // end namespace dynamic
610 } // end namespace ast_matchers
611 } // end namespace clang
612