xref: /llvm-project/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp (revision 5553d0d4cadc35733a910e7af5f8911105ff529d)
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 
89 TEST_F(RegistryTest, CanConstructNoArgs) {
90   Matcher<Stmt> IsArrowValue = constructMatcher(
91       "memberExpr", constructMatcher("isArrow")).getTypedMatcher<Stmt>();
92   Matcher<Stmt> BoolValue =
93       constructMatcher("boolLiteral").getTypedMatcher<Stmt>();
94 
95   const std::string ClassSnippet = "struct Foo { int x; };\n"
96                                    "Foo *foo = new Foo;\n"
97                                    "int i = foo->x;\n";
98   const std::string BoolSnippet = "bool Foo = true;\n";
99 
100   EXPECT_TRUE(matches(ClassSnippet, IsArrowValue));
101   EXPECT_TRUE(matches(BoolSnippet, BoolValue));
102   EXPECT_FALSE(matches(ClassSnippet, BoolValue));
103   EXPECT_FALSE(matches(BoolSnippet, IsArrowValue));
104 }
105 
106 TEST_F(RegistryTest, ConstructWithSimpleArgs) {
107   Matcher<Decl> Value = constructMatcher(
108       "namedDecl", constructMatcher("hasName", std::string("X")))
109       .getTypedMatcher<Decl>();
110   EXPECT_TRUE(matches("class X {};", Value));
111   EXPECT_FALSE(matches("int x;", Value));
112 
113   Value = functionDecl(constructMatcher("parameterCountIs", 2)
114                            .getTypedMatcher<FunctionDecl>());
115   EXPECT_TRUE(matches("void foo(int,int);", Value));
116   EXPECT_FALSE(matches("void foo(int);", Value));
117 }
118 
119 TEST_F(RegistryTest, ConstructWithMatcherArgs) {
120   Matcher<Decl> HasInitializerSimple = constructMatcher(
121       "varDecl", constructMatcher("hasInitializer", constructMatcher("stmt")))
122       .getTypedMatcher<Decl>();
123   Matcher<Decl> HasInitializerComplex = constructMatcher(
124       "varDecl",
125       constructMatcher("hasInitializer", constructMatcher("callExpr")))
126       .getTypedMatcher<Decl>();
127 
128   std::string code = "int i;";
129   EXPECT_FALSE(matches(code, HasInitializerSimple));
130   EXPECT_FALSE(matches(code, HasInitializerComplex));
131 
132   code = "int i = 1;";
133   EXPECT_TRUE(matches(code, HasInitializerSimple));
134   EXPECT_FALSE(matches(code, HasInitializerComplex));
135 
136   code = "int y(); int i = y();";
137   EXPECT_TRUE(matches(code, HasInitializerSimple));
138   EXPECT_TRUE(matches(code, HasInitializerComplex));
139 
140   Matcher<Decl> HasParameter =
141       functionDecl(constructMatcher(
142           "hasParameter", 1, constructMatcher("hasName", std::string("x")))
143                        .getTypedMatcher<FunctionDecl>());
144   EXPECT_TRUE(matches("void f(int a, int x);", HasParameter));
145   EXPECT_FALSE(matches("void f(int x, int a);", HasParameter));
146 }
147 
148 TEST_F(RegistryTest, OverloadedMatchers) {
149   Matcher<Stmt> CallExpr0 = constructMatcher(
150       "callExpr",
151       constructMatcher("callee", constructMatcher("memberExpr",
152                                                   constructMatcher("isArrow"))))
153       .getTypedMatcher<Stmt>();
154 
155   Matcher<Stmt> CallExpr1 = constructMatcher(
156       "callExpr",
157       constructMatcher(
158           "callee",
159           constructMatcher("methodDecl",
160                            constructMatcher("hasName", std::string("x")))))
161       .getTypedMatcher<Stmt>();
162 
163   std::string Code = "class Y { public: void x(); }; void z() { Y y; y.x(); }";
164   EXPECT_FALSE(matches(Code, CallExpr0));
165   EXPECT_TRUE(matches(Code, CallExpr1));
166 
167   Code = "class Z { public: void z() { this->z(); } };";
168   EXPECT_TRUE(matches(Code, CallExpr0));
169   EXPECT_FALSE(matches(Code, CallExpr1));
170 }
171 
172 TEST_F(RegistryTest, PolymorphicMatchers) {
173   const VariantMatcher IsDefinition = constructMatcher("isDefinition");
174   Matcher<Decl> Var =
175       constructMatcher("varDecl", IsDefinition).getTypedMatcher<Decl>();
176   Matcher<Decl> Class =
177       constructMatcher("recordDecl", IsDefinition).getTypedMatcher<Decl>();
178   Matcher<Decl> Func =
179       constructMatcher("functionDecl", IsDefinition).getTypedMatcher<Decl>();
180   EXPECT_TRUE(matches("int a;", Var));
181   EXPECT_FALSE(matches("extern int a;", Var));
182   EXPECT_TRUE(matches("class A {};", Class));
183   EXPECT_FALSE(matches("class A;", Class));
184   EXPECT_TRUE(matches("void f(){};", Func));
185   EXPECT_FALSE(matches("void f();", Func));
186 
187   Matcher<Decl> Anything = constructMatcher("anything").getTypedMatcher<Decl>();
188   Matcher<Decl> RecordDecl = constructMatcher(
189       "recordDecl", constructMatcher("hasName", std::string("Foo")),
190       VariantMatcher::SingleMatcher(Anything)).getTypedMatcher<Decl>();
191 
192   EXPECT_TRUE(matches("int Foo;", Anything));
193   EXPECT_TRUE(matches("class Foo {};", Anything));
194   EXPECT_TRUE(matches("void Foo(){};", Anything));
195   EXPECT_FALSE(matches("int Foo;", RecordDecl));
196   EXPECT_TRUE(matches("class Foo {};", RecordDecl));
197   EXPECT_FALSE(matches("void Foo(){};", RecordDecl));
198 
199   Matcher<Stmt> ConstructExpr = constructMatcher(
200       "constructExpr",
201       constructMatcher(
202           "hasDeclaration",
203           constructMatcher(
204               "methodDecl",
205               constructMatcher(
206                   "ofClass", constructMatcher("hasName", std::string("Foo"))))))
207                                     .getTypedMatcher<Stmt>();
208   EXPECT_FALSE(matches("class Foo { public: Foo(); };", ConstructExpr));
209   EXPECT_TRUE(
210       matches("class Foo { public: Foo(); }; Foo foo = Foo();", ConstructExpr));
211 }
212 
213 TEST_F(RegistryTest, TemplateArgument) {
214   Matcher<Decl> HasTemplateArgument = constructMatcher(
215       "classTemplateSpecializationDecl",
216       constructMatcher(
217           "hasAnyTemplateArgument",
218           constructMatcher("refersToType",
219                            constructMatcher("asString", std::string("int")))))
220       .getTypedMatcher<Decl>();
221   EXPECT_TRUE(matches("template<typename T> class A {}; A<int> a;",
222                       HasTemplateArgument));
223   EXPECT_FALSE(matches("template<typename T> class A {}; A<char> a;",
224                        HasTemplateArgument));
225 }
226 
227 TEST_F(RegistryTest, TypeTraversal) {
228   Matcher<Type> M = constructMatcher(
229       "pointerType",
230       constructMatcher("pointee", constructMatcher("isConstQualified"),
231                        constructMatcher("isInteger"))).getTypedMatcher<Type>();
232   EXPECT_FALSE(matches("int *a;", M));
233   EXPECT_TRUE(matches("int const *b;", M));
234 
235   M = constructMatcher(
236       "arrayType",
237       constructMatcher("hasElementType", constructMatcher("builtinType")))
238       .getTypedMatcher<Type>();
239   EXPECT_FALSE(matches("struct A{}; A a[7];;", M));
240   EXPECT_TRUE(matches("int b[7];", M));
241 }
242 
243 TEST_F(RegistryTest, CXXCtorInitializer) {
244   Matcher<Decl> CtorDecl = constructMatcher(
245       "constructorDecl",
246       constructMatcher(
247           "hasAnyConstructorInitializer",
248           constructMatcher("forField",
249                            constructMatcher("hasName", std::string("foo")))))
250       .getTypedMatcher<Decl>();
251   EXPECT_TRUE(matches("struct Foo { Foo() : foo(1) {} int foo; };", CtorDecl));
252   EXPECT_FALSE(matches("struct Foo { Foo() {} int foo; };", CtorDecl));
253   EXPECT_FALSE(matches("struct Foo { Foo() : bar(1) {} int bar; };", CtorDecl));
254 }
255 
256 TEST_F(RegistryTest, Adaptative) {
257   Matcher<Decl> D = constructMatcher(
258       "recordDecl",
259       constructMatcher(
260           "has",
261           constructMatcher("recordDecl",
262                            constructMatcher("hasName", std::string("X")))))
263       .getTypedMatcher<Decl>();
264   EXPECT_TRUE(matches("class X {};", D));
265   EXPECT_TRUE(matches("class Y { class X {}; };", D));
266   EXPECT_FALSE(matches("class Y { class Z {}; };", D));
267 
268   Matcher<Stmt> S = constructMatcher(
269       "forStmt",
270       constructMatcher(
271           "hasDescendant",
272           constructMatcher("varDecl",
273                            constructMatcher("hasName", std::string("X")))))
274       .getTypedMatcher<Stmt>();
275   EXPECT_TRUE(matches("void foo() { for(int X;;); }", S));
276   EXPECT_TRUE(matches("void foo() { for(;;) { int X; } }", S));
277   EXPECT_FALSE(matches("void foo() { for(;;); }", S));
278   EXPECT_FALSE(matches("void foo() { if (int X = 0){} }", S));
279 
280   S = constructMatcher(
281       "compoundStmt", constructMatcher("hasParent", constructMatcher("ifStmt")))
282       .getTypedMatcher<Stmt>();
283   EXPECT_TRUE(matches("void foo() { if (true) { int x = 42; } }", S));
284   EXPECT_FALSE(matches("void foo() { if (true) return; }", S));
285 }
286 
287 TEST_F(RegistryTest, VariadicOp) {
288   Matcher<Decl> D = constructMatcher(
289       "anyOf",
290       constructMatcher("recordDecl",
291                        constructMatcher("hasName", std::string("Foo"))),
292       constructMatcher("namedDecl",
293                        constructMatcher("hasName", std::string("foo"))))
294       .getTypedMatcher<Decl>();
295 
296   EXPECT_TRUE(matches("void foo(){}", D));
297   EXPECT_TRUE(matches("struct Foo{};", D));
298   EXPECT_FALSE(matches("int i = 0;", D));
299 
300   D = constructMatcher(
301       "allOf", constructMatcher("recordDecl"),
302       constructMatcher(
303           "namedDecl",
304           constructMatcher("anyOf",
305                            constructMatcher("hasName", std::string("Foo")),
306                            constructMatcher("hasName", std::string("Bar")))))
307       .getTypedMatcher<Decl>();
308 
309   EXPECT_FALSE(matches("void foo(){}", D));
310   EXPECT_TRUE(matches("struct Foo{};", D));
311   EXPECT_FALSE(matches("int i = 0;", D));
312   EXPECT_TRUE(matches("class Bar{};", D));
313   EXPECT_FALSE(matches("class OtherBar{};", D));
314 
315   D = recordDecl(
316       has(fieldDecl(hasName("Foo"))),
317       constructMatcher(
318           "unless",
319           constructMatcher("namedDecl",
320                            constructMatcher("hasName", std::string("Bar"))))
321           .getTypedMatcher<Decl>());
322 
323   EXPECT_FALSE(matches("class Bar{ int Foo; };", D));
324   EXPECT_TRUE(matches("class OtherBar{ int Foo; };", D));
325 }
326 
327 TEST_F(RegistryTest, Errors) {
328   // Incorrect argument count.
329   OwningPtr<Diagnostics> Error(new Diagnostics());
330   EXPECT_TRUE(constructMatcher("hasInitializer", Error.get()).isNull());
331   EXPECT_EQ("Incorrect argument count. (Expected = 1) != (Actual = 0)",
332             Error->toString());
333   Error.reset(new Diagnostics());
334   EXPECT_TRUE(constructMatcher("isArrow", std::string(), Error.get()).isNull());
335   EXPECT_EQ("Incorrect argument count. (Expected = 0) != (Actual = 1)",
336             Error->toString());
337   Error.reset(new Diagnostics());
338   EXPECT_TRUE(constructMatcher("anyOf", Error.get()).isNull());
339   EXPECT_EQ("Incorrect argument count. (Expected = (2, )) != (Actual = 0)",
340             Error->toString());
341   Error.reset(new Diagnostics());
342   EXPECT_TRUE(constructMatcher("unless", std::string(), std::string(),
343                                Error.get()).isNull());
344   EXPECT_EQ("Incorrect argument count. (Expected = (1, 1)) != (Actual = 2)",
345             Error->toString());
346 
347   // Bad argument type
348   Error.reset(new Diagnostics());
349   EXPECT_TRUE(constructMatcher("ofClass", std::string(), Error.get()).isNull());
350   EXPECT_EQ("Incorrect type for arg 1. (Expected = Matcher<CXXRecordDecl>) != "
351             "(Actual = String)",
352             Error->toString());
353   Error.reset(new Diagnostics());
354   EXPECT_TRUE(constructMatcher("recordDecl", constructMatcher("recordDecl"),
355                                constructMatcher("parameterCountIs", 3),
356                                Error.get()).isNull());
357   EXPECT_EQ("Incorrect type for arg 2. (Expected = Matcher<CXXRecordDecl>) != "
358             "(Actual = Matcher<FunctionDecl>)",
359             Error->toString());
360 
361   // Bad argument type with variadic.
362   Error.reset(new Diagnostics());
363   EXPECT_TRUE(constructMatcher("anyOf", std::string(), std::string(),
364                                Error.get()).isNull());
365   EXPECT_EQ(
366       "Incorrect type for arg 1. (Expected = Matcher<>) != (Actual = String)",
367       Error->toString());
368   Error.reset(new Diagnostics());
369   EXPECT_TRUE(constructMatcher(
370       "recordDecl",
371       constructMatcher("allOf",
372                        constructMatcher("isDerivedFrom", std::string("FOO")),
373                        constructMatcher("isArrow")),
374       Error.get()).isNull());
375   EXPECT_EQ("Incorrect type for arg 1. "
376             "(Expected = Matcher<CXXRecordDecl>) != "
377             "(Actual = Matcher<CXXRecordDecl>&Matcher<MemberExpr>)",
378             Error->toString());
379 }
380 
381 } // end anonymous namespace
382 } // end namespace dynamic
383 } // end namespace ast_matchers
384 } // end namespace clang
385