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