xref: /llvm-project/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp (revision d32e28c87a91b038cf4d3860e29e741566d7a66f)
1 //===- unittest/ASTMatchers/Dynamic/RegistryTest.cpp - Registry unit tests -===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===-----------------------------------------------------------------------===//
9 
10 #include "../ASTMatchersTest.h"
11 #include "clang/ASTMatchers/Dynamic/Registry.h"
12 #include "gtest/gtest.h"
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:
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   llvm::Optional<MatcherCtor> lookupMatcherCtor(StringRef MatcherName,
39                                                 Diagnostics *Error = 0) {
40     Diagnostics DummyError;
41     if (!Error) Error = &DummyError;
42     llvm::Optional<MatcherCtor> Ctor =
43         Registry::lookupMatcherCtor(MatcherName, SourceRange(), Error);
44     EXPECT_EQ("", DummyError.toStringFull());
45     return Ctor;
46   }
47 
48   VariantMatcher constructMatcher(StringRef MatcherName,
49                                   Diagnostics *Error = NULL) {
50     Diagnostics DummyError;
51     if (!Error) Error = &DummyError;
52     llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName, Error);
53     VariantMatcher Out;
54     if (Ctor)
55       Out = Registry::constructMatcher(*Ctor, SourceRange(), Args(), Error);
56     EXPECT_EQ("", DummyError.toStringFull());
57     return Out;
58   }
59 
60   VariantMatcher constructMatcher(StringRef MatcherName,
61                                   const VariantValue &Arg1,
62                                   Diagnostics *Error = NULL) {
63     Diagnostics DummyError;
64     if (!Error) Error = &DummyError;
65     llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName, Error);
66     VariantMatcher Out;
67     if (Ctor)
68       Out = Registry::constructMatcher(*Ctor, SourceRange(), Args(Arg1), Error);
69     EXPECT_EQ("", DummyError.toStringFull());
70     return Out;
71   }
72 
73   VariantMatcher constructMatcher(StringRef MatcherName,
74                                   const VariantValue &Arg1,
75                                   const VariantValue &Arg2,
76                                   Diagnostics *Error = NULL) {
77     Diagnostics DummyError;
78     if (!Error) Error = &DummyError;
79     llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName, Error);
80     VariantMatcher Out;
81     if (Ctor)
82       Out = Registry::constructMatcher(*Ctor, SourceRange(), Args(Arg1, Arg2),
83                                        Error);
84     EXPECT_EQ("", DummyError.toStringFull());
85     return Out;
86   }
87 
88   typedef std::vector<MatcherCompletion> CompVector;
89 
90   CompVector getCompletions() {
91     return Registry::getCompletions(
92         llvm::ArrayRef<std::pair<MatcherCtor, unsigned> >());
93   }
94 
95   CompVector getCompletions(StringRef MatcherName1, unsigned ArgNo1) {
96     std::vector<std::pair<MatcherCtor, unsigned> > Context;
97     llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName1);
98     if (!Ctor)
99       return CompVector();
100     Context.push_back(std::make_pair(*Ctor, ArgNo1));
101     return Registry::getCompletions(Context);
102   }
103 
104   CompVector getCompletions(StringRef MatcherName1, unsigned ArgNo1,
105                             StringRef MatcherName2, unsigned ArgNo2) {
106     std::vector<std::pair<MatcherCtor, unsigned> > Context;
107     llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName1);
108     if (!Ctor)
109       return CompVector();
110     Context.push_back(std::make_pair(*Ctor, ArgNo1));
111     Ctor = lookupMatcherCtor(MatcherName2);
112     if (!Ctor)
113       return CompVector();
114     Context.push_back(std::make_pair(*Ctor, ArgNo2));
115     return Registry::getCompletions(Context);
116   }
117 
118   bool hasCompletion(const CompVector &Comps, StringRef TypedText,
119                      StringRef MatcherDecl = StringRef(), unsigned *Index = 0) {
120     for (CompVector::const_iterator I = Comps.begin(), E = Comps.end(); I != E;
121          ++I) {
122       if (I->TypedText == TypedText &&
123           (MatcherDecl.empty() || I->MatcherDecl == MatcherDecl)) {
124         if (Index)
125           *Index = I - Comps.begin();
126         return true;
127       }
128     }
129     return false;
130   }
131 };
132 
133 TEST_F(RegistryTest, CanConstructNoArgs) {
134   Matcher<Stmt> IsArrowValue = constructMatcher(
135       "memberExpr", constructMatcher("isArrow")).getTypedMatcher<Stmt>();
136   Matcher<Stmt> BoolValue =
137       constructMatcher("boolLiteral").getTypedMatcher<Stmt>();
138 
139   const std::string ClassSnippet = "struct Foo { int x; };\n"
140                                    "Foo *foo = new Foo;\n"
141                                    "int i = foo->x;\n";
142   const std::string BoolSnippet = "bool Foo = true;\n";
143 
144   EXPECT_TRUE(matches(ClassSnippet, IsArrowValue));
145   EXPECT_TRUE(matches(BoolSnippet, BoolValue));
146   EXPECT_FALSE(matches(ClassSnippet, BoolValue));
147   EXPECT_FALSE(matches(BoolSnippet, IsArrowValue));
148 }
149 
150 TEST_F(RegistryTest, ConstructWithSimpleArgs) {
151   Matcher<Decl> Value = constructMatcher(
152       "namedDecl", constructMatcher("hasName", std::string("X")))
153       .getTypedMatcher<Decl>();
154   EXPECT_TRUE(matches("class X {};", Value));
155   EXPECT_FALSE(matches("int x;", Value));
156 
157   Value = functionDecl(constructMatcher("parameterCountIs", 2)
158                            .getTypedMatcher<FunctionDecl>());
159   EXPECT_TRUE(matches("void foo(int,int);", Value));
160   EXPECT_FALSE(matches("void foo(int);", Value));
161 }
162 
163 TEST_F(RegistryTest, ConstructWithMatcherArgs) {
164   Matcher<Decl> HasInitializerSimple = constructMatcher(
165       "varDecl", constructMatcher("hasInitializer", constructMatcher("stmt")))
166       .getTypedMatcher<Decl>();
167   Matcher<Decl> HasInitializerComplex = constructMatcher(
168       "varDecl",
169       constructMatcher("hasInitializer", constructMatcher("callExpr")))
170       .getTypedMatcher<Decl>();
171 
172   std::string code = "int i;";
173   EXPECT_FALSE(matches(code, HasInitializerSimple));
174   EXPECT_FALSE(matches(code, HasInitializerComplex));
175 
176   code = "int i = 1;";
177   EXPECT_TRUE(matches(code, HasInitializerSimple));
178   EXPECT_FALSE(matches(code, HasInitializerComplex));
179 
180   code = "int y(); int i = y();";
181   EXPECT_TRUE(matches(code, HasInitializerSimple));
182   EXPECT_TRUE(matches(code, HasInitializerComplex));
183 
184   Matcher<Decl> HasParameter =
185       functionDecl(constructMatcher(
186           "hasParameter", 1, constructMatcher("hasName", std::string("x")))
187                        .getTypedMatcher<FunctionDecl>());
188   EXPECT_TRUE(matches("void f(int a, int x);", HasParameter));
189   EXPECT_FALSE(matches("void f(int x, int a);", HasParameter));
190 }
191 
192 TEST_F(RegistryTest, OverloadedMatchers) {
193   Matcher<Stmt> CallExpr0 = constructMatcher(
194       "callExpr",
195       constructMatcher("callee", constructMatcher("memberExpr",
196                                                   constructMatcher("isArrow"))))
197       .getTypedMatcher<Stmt>();
198 
199   Matcher<Stmt> CallExpr1 = constructMatcher(
200       "callExpr",
201       constructMatcher(
202           "callee",
203           constructMatcher("methodDecl",
204                            constructMatcher("hasName", std::string("x")))))
205       .getTypedMatcher<Stmt>();
206 
207   std::string Code = "class Y { public: void x(); }; void z() { Y y; y.x(); }";
208   EXPECT_FALSE(matches(Code, CallExpr0));
209   EXPECT_TRUE(matches(Code, CallExpr1));
210 
211   Code = "class Z { public: void z() { this->z(); } };";
212   EXPECT_TRUE(matches(Code, CallExpr0));
213   EXPECT_FALSE(matches(Code, CallExpr1));
214 }
215 
216 TEST_F(RegistryTest, PolymorphicMatchers) {
217   const VariantMatcher IsDefinition = constructMatcher("isDefinition");
218   Matcher<Decl> Var =
219       constructMatcher("varDecl", IsDefinition).getTypedMatcher<Decl>();
220   Matcher<Decl> Class =
221       constructMatcher("recordDecl", IsDefinition).getTypedMatcher<Decl>();
222   Matcher<Decl> Func =
223       constructMatcher("functionDecl", IsDefinition).getTypedMatcher<Decl>();
224   EXPECT_TRUE(matches("int a;", Var));
225   EXPECT_FALSE(matches("extern int a;", Var));
226   EXPECT_TRUE(matches("class A {};", Class));
227   EXPECT_FALSE(matches("class A;", Class));
228   EXPECT_TRUE(matches("void f(){};", Func));
229   EXPECT_FALSE(matches("void f();", Func));
230 
231   Matcher<Decl> Anything = constructMatcher("anything").getTypedMatcher<Decl>();
232   Matcher<Decl> RecordDecl = constructMatcher(
233       "recordDecl", constructMatcher("hasName", std::string("Foo")),
234       VariantMatcher::SingleMatcher(Anything)).getTypedMatcher<Decl>();
235 
236   EXPECT_TRUE(matches("int Foo;", Anything));
237   EXPECT_TRUE(matches("class Foo {};", Anything));
238   EXPECT_TRUE(matches("void Foo(){};", Anything));
239   EXPECT_FALSE(matches("int Foo;", RecordDecl));
240   EXPECT_TRUE(matches("class Foo {};", RecordDecl));
241   EXPECT_FALSE(matches("void Foo(){};", RecordDecl));
242 
243   Matcher<Stmt> ConstructExpr = constructMatcher(
244       "constructExpr",
245       constructMatcher(
246           "hasDeclaration",
247           constructMatcher(
248               "methodDecl",
249               constructMatcher(
250                   "ofClass", constructMatcher("hasName", std::string("Foo"))))))
251                                     .getTypedMatcher<Stmt>();
252   EXPECT_FALSE(matches("class Foo { public: Foo(); };", ConstructExpr));
253   EXPECT_TRUE(
254       matches("class Foo { public: Foo(); }; Foo foo = Foo();", ConstructExpr));
255 }
256 
257 TEST_F(RegistryTest, TemplateArgument) {
258   Matcher<Decl> HasTemplateArgument = constructMatcher(
259       "classTemplateSpecializationDecl",
260       constructMatcher(
261           "hasAnyTemplateArgument",
262           constructMatcher("refersToType",
263                            constructMatcher("asString", std::string("int")))))
264       .getTypedMatcher<Decl>();
265   EXPECT_TRUE(matches("template<typename T> class A {}; A<int> a;",
266                       HasTemplateArgument));
267   EXPECT_FALSE(matches("template<typename T> class A {}; A<char> a;",
268                        HasTemplateArgument));
269 }
270 
271 TEST_F(RegistryTest, TypeTraversal) {
272   Matcher<Type> M = constructMatcher(
273       "pointerType",
274       constructMatcher("pointee", constructMatcher("isConstQualified"),
275                        constructMatcher("isInteger"))).getTypedMatcher<Type>();
276   EXPECT_FALSE(matches("int *a;", M));
277   EXPECT_TRUE(matches("int const *b;", M));
278 
279   M = constructMatcher(
280       "arrayType",
281       constructMatcher("hasElementType", constructMatcher("builtinType")))
282       .getTypedMatcher<Type>();
283   EXPECT_FALSE(matches("struct A{}; A a[7];;", M));
284   EXPECT_TRUE(matches("int b[7];", M));
285 }
286 
287 TEST_F(RegistryTest, CXXCtorInitializer) {
288   Matcher<Decl> CtorDecl = constructMatcher(
289       "constructorDecl",
290       constructMatcher(
291           "hasAnyConstructorInitializer",
292           constructMatcher("forField",
293                            constructMatcher("hasName", std::string("foo")))))
294       .getTypedMatcher<Decl>();
295   EXPECT_TRUE(matches("struct Foo { Foo() : foo(1) {} int foo; };", CtorDecl));
296   EXPECT_FALSE(matches("struct Foo { Foo() {} int foo; };", CtorDecl));
297   EXPECT_FALSE(matches("struct Foo { Foo() : bar(1) {} int bar; };", CtorDecl));
298 }
299 
300 TEST_F(RegistryTest, Adaptative) {
301   Matcher<Decl> D = constructMatcher(
302       "recordDecl",
303       constructMatcher(
304           "has",
305           constructMatcher("recordDecl",
306                            constructMatcher("hasName", std::string("X")))))
307       .getTypedMatcher<Decl>();
308   EXPECT_TRUE(matches("class X {};", D));
309   EXPECT_TRUE(matches("class Y { class X {}; };", D));
310   EXPECT_FALSE(matches("class Y { class Z {}; };", D));
311 
312   Matcher<Stmt> S = constructMatcher(
313       "forStmt",
314       constructMatcher(
315           "hasDescendant",
316           constructMatcher("varDecl",
317                            constructMatcher("hasName", std::string("X")))))
318       .getTypedMatcher<Stmt>();
319   EXPECT_TRUE(matches("void foo() { for(int X;;); }", S));
320   EXPECT_TRUE(matches("void foo() { for(;;) { int X; } }", S));
321   EXPECT_FALSE(matches("void foo() { for(;;); }", S));
322   EXPECT_FALSE(matches("void foo() { if (int X = 0){} }", S));
323 
324   S = constructMatcher(
325       "compoundStmt", constructMatcher("hasParent", constructMatcher("ifStmt")))
326       .getTypedMatcher<Stmt>();
327   EXPECT_TRUE(matches("void foo() { if (true) { int x = 42; } }", S));
328   EXPECT_FALSE(matches("void foo() { if (true) return; }", S));
329 }
330 
331 TEST_F(RegistryTest, VariadicOp) {
332   Matcher<Decl> D = constructMatcher(
333       "anyOf",
334       constructMatcher("recordDecl",
335                        constructMatcher("hasName", std::string("Foo"))),
336       constructMatcher("namedDecl",
337                        constructMatcher("hasName", std::string("foo"))))
338       .getTypedMatcher<Decl>();
339 
340   EXPECT_TRUE(matches("void foo(){}", D));
341   EXPECT_TRUE(matches("struct Foo{};", D));
342   EXPECT_FALSE(matches("int i = 0;", D));
343 
344   D = constructMatcher(
345       "allOf", constructMatcher("recordDecl"),
346       constructMatcher(
347           "namedDecl",
348           constructMatcher("anyOf",
349                            constructMatcher("hasName", std::string("Foo")),
350                            constructMatcher("hasName", std::string("Bar")))))
351       .getTypedMatcher<Decl>();
352 
353   EXPECT_FALSE(matches("void foo(){}", D));
354   EXPECT_TRUE(matches("struct Foo{};", D));
355   EXPECT_FALSE(matches("int i = 0;", D));
356   EXPECT_TRUE(matches("class Bar{};", D));
357   EXPECT_FALSE(matches("class OtherBar{};", D));
358 
359   D = recordDecl(
360       has(fieldDecl(hasName("Foo"))),
361       constructMatcher(
362           "unless",
363           constructMatcher("namedDecl",
364                            constructMatcher("hasName", std::string("Bar"))))
365           .getTypedMatcher<Decl>());
366 
367   EXPECT_FALSE(matches("class Bar{ int Foo; };", D));
368   EXPECT_TRUE(matches("class OtherBar{ int Foo; };", D));
369 }
370 
371 TEST_F(RegistryTest, Errors) {
372   // Incorrect argument count.
373   OwningPtr<Diagnostics> Error(new Diagnostics());
374   EXPECT_TRUE(constructMatcher("hasInitializer", Error.get()).isNull());
375   EXPECT_EQ("Incorrect argument count. (Expected = 1) != (Actual = 0)",
376             Error->toString());
377   Error.reset(new Diagnostics());
378   EXPECT_TRUE(constructMatcher("isArrow", std::string(), Error.get()).isNull());
379   EXPECT_EQ("Incorrect argument count. (Expected = 0) != (Actual = 1)",
380             Error->toString());
381   Error.reset(new Diagnostics());
382   EXPECT_TRUE(constructMatcher("anyOf", Error.get()).isNull());
383   EXPECT_EQ("Incorrect argument count. (Expected = (2, )) != (Actual = 0)",
384             Error->toString());
385   Error.reset(new Diagnostics());
386   EXPECT_TRUE(constructMatcher("unless", std::string(), std::string(),
387                                Error.get()).isNull());
388   EXPECT_EQ("Incorrect argument count. (Expected = (1, 1)) != (Actual = 2)",
389             Error->toString());
390 
391   // Bad argument type
392   Error.reset(new Diagnostics());
393   EXPECT_TRUE(constructMatcher("ofClass", std::string(), Error.get()).isNull());
394   EXPECT_EQ("Incorrect type for arg 1. (Expected = Matcher<CXXRecordDecl>) != "
395             "(Actual = String)",
396             Error->toString());
397   Error.reset(new Diagnostics());
398   EXPECT_TRUE(constructMatcher("recordDecl", constructMatcher("recordDecl"),
399                                constructMatcher("parameterCountIs", 3),
400                                Error.get()).isNull());
401   EXPECT_EQ("Incorrect type for arg 2. (Expected = Matcher<CXXRecordDecl>) != "
402             "(Actual = Matcher<FunctionDecl>)",
403             Error->toString());
404 
405   // Bad argument type with variadic.
406   Error.reset(new Diagnostics());
407   EXPECT_TRUE(constructMatcher("anyOf", std::string(), std::string(),
408                                Error.get()).isNull());
409   EXPECT_EQ(
410       "Incorrect type for arg 1. (Expected = Matcher<>) != (Actual = String)",
411       Error->toString());
412   Error.reset(new Diagnostics());
413   EXPECT_TRUE(constructMatcher(
414       "recordDecl",
415       constructMatcher("allOf",
416                        constructMatcher("isDerivedFrom", std::string("FOO")),
417                        constructMatcher("isArrow")),
418       Error.get()).isNull());
419   EXPECT_EQ("Incorrect type for arg 1. "
420             "(Expected = Matcher<CXXRecordDecl>) != "
421             "(Actual = Matcher<CXXRecordDecl>&Matcher<MemberExpr>)",
422             Error->toString());
423 }
424 
425 TEST_F(RegistryTest, Completion) {
426   CompVector Comps = getCompletions();
427   EXPECT_TRUE(hasCompletion(
428       Comps, "hasParent(", "Matcher<Decl|Stmt> hasParent(Matcher<Decl|Stmt>)"));
429   EXPECT_TRUE(hasCompletion(Comps, "whileStmt(",
430                             "Matcher<Stmt> whileStmt(Matcher<WhileStmt>...)"));
431 
432   CompVector WhileComps = getCompletions("whileStmt", 0);
433 
434   unsigned HasBodyIndex, HasParentIndex, AllOfIndex;
435   EXPECT_TRUE(hasCompletion(WhileComps, "hasBody(",
436                             "Matcher<WhileStmt> hasBody(Matcher<Stmt>)",
437                             &HasBodyIndex));
438   EXPECT_TRUE(hasCompletion(WhileComps, "hasParent(",
439                             "Matcher<Stmt> hasParent(Matcher<Decl|Stmt>)",
440                             &HasParentIndex));
441   EXPECT_TRUE(hasCompletion(WhileComps, "allOf(",
442                             "Matcher<T> allOf(Matcher<T>...)", &AllOfIndex));
443   EXPECT_GT(HasParentIndex, HasBodyIndex);
444   EXPECT_GT(AllOfIndex, HasParentIndex);
445 
446   EXPECT_FALSE(hasCompletion(WhileComps, "whileStmt("));
447   EXPECT_FALSE(hasCompletion(WhileComps, "ifStmt("));
448 
449   CompVector AllOfWhileComps =
450       getCompletions("allOf", 0, "whileStmt", 0);
451   ASSERT_EQ(AllOfWhileComps.size(), WhileComps.size());
452   EXPECT_TRUE(std::equal(WhileComps.begin(), WhileComps.end(),
453                          AllOfWhileComps.begin()));
454 
455   CompVector DeclWhileComps =
456       getCompletions("decl", 0, "whileStmt", 0);
457   EXPECT_EQ(0u, DeclWhileComps.size());
458 
459   CompVector NamedDeclComps = getCompletions("namedDecl", 0);
460   EXPECT_TRUE(
461       hasCompletion(NamedDeclComps, "isPublic()", "Matcher<Decl> isPublic()"));
462   EXPECT_TRUE(hasCompletion(NamedDeclComps, "hasName(\"",
463                             "Matcher<NamedDecl> hasName(string)"));
464 }
465 
466 } // end anonymous namespace
467 } // end namespace dynamic
468 } // end namespace ast_matchers
469 } // end namespace clang
470