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