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
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: *Ctor, NameRange: SourceRange(), Args: 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: *Ctor, NameRange: SourceRange(), Args: 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: *Ctor, NameRange: SourceRange(), Args: 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 AcceptedTypes: 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(MatcherName: MatcherName1);
93 if (!Ctor)
94 return CompVector();
95 Context.push_back(x: std::make_pair(x&: *Ctor, y&: ArgNo1));
96 return Registry::getMatcherCompletions(
97 AcceptedTypes: 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(MatcherName: MatcherName1);
104 if (!Ctor)
105 return CompVector();
106 Context.push_back(x: std::make_pair(x&: *Ctor, y&: ArgNo1));
107 Ctor = lookupMatcherCtor(MatcherName: MatcherName2);
108 if (!Ctor)
109 return CompVector();
110 Context.push_back(x: std::make_pair(x&: *Ctor, y&: ArgNo2));
111 return Registry::getMatcherCompletions(
112 AcceptedTypes: 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 MatcherName: "memberExpr", Arg1: constructMatcher(MatcherName: "isArrow")).getTypedMatcher<Stmt>();
131 Matcher<Stmt> BoolValue =
132 constructMatcher(MatcherName: "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 MatcherName: "namedDecl", Arg1: constructMatcher(MatcherName: "hasName", Arg1: StringRef("X")))
148 .getTypedMatcher<Decl>();
149 EXPECT_TRUE(matches("class X {};", Value));
150 EXPECT_FALSE(matches("int x;", Value));
151
152 Value = functionDecl(constructMatcher(MatcherName: "parameterCountIs", Arg1: 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 MatcherName: "varDecl", Arg1: constructMatcher(MatcherName: "hasInitializer", Arg1: constructMatcher(MatcherName: "stmt")))
161 .getTypedMatcher<Decl>();
162 Matcher<Decl> HasInitializerComplex = constructMatcher(
163 MatcherName: "varDecl",
164 Arg1: constructMatcher(MatcherName: "hasInitializer", Arg1: constructMatcher(MatcherName: "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 MatcherName: "hasParameter", Arg1: 1, Arg2: constructMatcher(MatcherName: "hasName", Arg1: 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 MatcherName: "callExpr",
190 Arg1: constructMatcher(MatcherName: "callee", Arg1: constructMatcher(MatcherName: "memberExpr",
191 Arg1: constructMatcher(MatcherName: "isArrow"))))
192 .getTypedMatcher<Stmt>();
193
194 Matcher<Stmt> CallExpr1 = constructMatcher(
195 MatcherName: "callExpr",
196 Arg1: constructMatcher(
197 MatcherName: "callee",
198 Arg1: constructMatcher(MatcherName: "cxxMethodDecl",
199 Arg1: constructMatcher(MatcherName: "hasName", Arg1: StringRef("x")))))
200 .getTypedMatcher<Stmt>();
201
202 Matcher<Stmt> ObjCMsgExpr =
203 constructMatcher(
204 MatcherName: "objcMessageExpr",
205 Arg1: constructMatcher(
206 MatcherName: "callee",
207 Arg1: constructMatcher(MatcherName: "objcMethodDecl",
208 Arg1: constructMatcher(MatcherName: "hasName", Arg1: 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 Inner: constructMatcher(
231 MatcherName: "loc", Arg1: constructMatcher(MatcherName: "asString", Arg1: StringRef("const double *")))
232 .getTypedMatcher<TypeLoc>()));
233
234 Matcher<NestedNameSpecifierLoc> NNSL =
235 constructMatcher(
236 MatcherName: "loc", Arg1: VariantMatcher::SingleMatcher(Matcher: nestedNameSpecifier(
237 specifiesType(InnerMatcher: hasDeclaration(InnerMatcher: recordDecl(hasName(Name: "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(MatcherName: "isDefinition");
251 Matcher<Decl> Var =
252 constructMatcher(MatcherName: "varDecl", Arg1: IsDefinition).getTypedMatcher<Decl>();
253 Matcher<Decl> Class =
254 constructMatcher(MatcherName: "recordDecl", Arg1: IsDefinition).getTypedMatcher<Decl>();
255 Matcher<Decl> Func =
256 constructMatcher(MatcherName: "functionDecl", Arg1: 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(MatcherName: "anything").getTypedMatcher<Decl>();
265 Matcher<Decl> RecordDecl = constructMatcher(
266 MatcherName: "recordDecl", Arg1: constructMatcher(MatcherName: "hasName", Arg1: StringRef("Foo")),
267 Arg2: VariantMatcher::SingleMatcher(Matcher: 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 MatcherName: "cxxConstructExpr",
278 Arg1: constructMatcher(
279 MatcherName: "hasDeclaration",
280 Arg1: constructMatcher(
281 MatcherName: "cxxMethodDecl",
282 Arg1: constructMatcher(
283 MatcherName: "ofClass", Arg1: constructMatcher(MatcherName: "hasName", Arg1: 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 MatcherName: "classTemplateSpecializationDecl",
293 Arg1: constructMatcher(
294 MatcherName: "hasAnyTemplateArgument",
295 Arg1: constructMatcher(MatcherName: "refersToType",
296 Arg1: constructMatcher(MatcherName: "asString", Arg1: 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 MatcherName: "pointerType",
307 Arg1: constructMatcher(MatcherName: "pointee", Arg1: constructMatcher(MatcherName: "isConstQualified"),
308 Arg2: constructMatcher(MatcherName: "isInteger"))).getTypedMatcher<Type>();
309 EXPECT_FALSE(matches("int *a;", M));
310 EXPECT_TRUE(matches("int const *b;", M));
311
312 M = constructMatcher(
313 MatcherName: "arrayType",
314 Arg1: constructMatcher(MatcherName: "hasElementType", Arg1: constructMatcher(MatcherName: "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 available
322 DeclarationMatcher ClassHasAnyDirectBase =
323 constructMatcher(MatcherName: "cxxRecordDecl",
324 Arg1: constructMatcher(MatcherName: "hasDirectBase",
325 Arg1: constructMatcher(MatcherName: "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 MatcherName: "cxxConstructorDecl",
334 Arg1: constructMatcher(
335 MatcherName: "hasAnyConstructorInitializer",
336 Arg1: constructMatcher(MatcherName: "forField",
337 Arg1: constructMatcher(MatcherName: "hasName", Arg1: 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 MatcherName: "recordDecl",
347 Arg1: constructMatcher(
348 MatcherName: "has",
349 Arg1: constructMatcher(MatcherName: "recordDecl",
350 Arg1: constructMatcher(MatcherName: "hasName", Arg1: 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 MatcherName: "forStmt",
358 Arg1: constructMatcher(
359 MatcherName: "hasDescendant",
360 Arg1: constructMatcher(MatcherName: "varDecl",
361 Arg1: constructMatcher(MatcherName: "hasName", Arg1: 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 MatcherName: "compoundStmt", Arg1: constructMatcher(MatcherName: "hasParent", Arg1: constructMatcher(MatcherName: "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 MatcherName: "anyOf",
378 Arg1: constructMatcher(MatcherName: "recordDecl",
379 Arg1: constructMatcher(MatcherName: "hasName", Arg1: StringRef("Foo"))),
380 Arg2: constructMatcher(MatcherName: "functionDecl",
381 Arg1: constructMatcher(MatcherName: "hasName", Arg1: 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 MatcherName: "allOf", Arg1: constructMatcher(MatcherName: "recordDecl"),
390 Arg2: constructMatcher(
391 MatcherName: "namedDecl",
392 Arg1: constructMatcher(MatcherName: "anyOf",
393 Arg1: constructMatcher(MatcherName: "hasName", Arg1: StringRef("Foo")),
394 Arg2: constructMatcher(MatcherName: "hasName", Arg1: 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(Name: "Foo"))),
405 constructMatcher(
406 MatcherName: "unless",
407 Arg1: constructMatcher(MatcherName: "namedDecl",
408 Arg1: constructMatcher(MatcherName: "hasName", Arg1: 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 MatcherName: "namedDecl", Arg1: constructMatcher(MatcherName: "hasName", Arg1: StringRef("Foo")),
416 Arg2: constructMatcher(MatcherName: "unless", Arg1: constructMatcher(MatcherName: "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(p: 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(p: 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(p: 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(p: 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(p: 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(p: 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(p: 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 // 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(MatcherName1: "whileStmt", ArgNo1: 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(MatcherName1: "allOf", ArgNo1: 0, MatcherName2: "whileStmt", ArgNo2: 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(MatcherName1: "decl", ArgNo1: 0, MatcherName2: "whileStmt", ArgNo2: 0);
516 EXPECT_EQ(0u, DeclWhileComps.size());
517
518 CompVector NamedDeclComps = getCompletions(MatcherName1: "namedDecl", ArgNo1: 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(MatcherName1: "classTemplateSpecializationDecl", ArgNo1: 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(MatcherName: "mapAnyOf");
533 EXPECT_TRUE(Registry::isBuilderMatcher(Ctor));
534 auto BuiltCtor = Registry::buildMatcherCtor(Ctor, NameRange: {}, Args: Args(Arg1: ASTNodeKind::getFromNodeKind<WhileStmt>(), Arg2: ASTNodeKind::getFromNodeKind<ForStmt>()), Error: nullptr);
535 EXPECT_TRUE(BuiltCtor.get());
536 auto LoopMatcher = Registry::constructMatcher(Ctor: BuiltCtor.get(), NameRange: SourceRange(), Args: Args(), Error: 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, NameRange: {}, Args: Args(Arg1: ASTNodeKind::getFromNodeKind<FunctionDecl>(), Arg2: ASTNodeKind::getFromNodeKind<ForStmt>()), Error: 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 MatcherName: "decl", Arg1: constructMatcher(MatcherName: "hasAttr", Arg1: 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(MatcherName: "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 MatcherName: "cxxBoolLiteral", Arg1: constructMatcher(MatcherName: "equals", Arg1: 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 MatcherName: "cxxBoolLiteral", Arg1: constructMatcher(MatcherName: "equals", Arg1: 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 MatcherName: "floatLiteral", Arg1: constructMatcher(MatcherName: "equals", Arg1: 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 MatcherName: "integerLiteral", Arg1: constructMatcher(MatcherName: "equals", Arg1: 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 MatcherName: "characterLiteral", Arg1: constructMatcher(MatcherName: "equals", Arg1: 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

source code of clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp