xref: /llvm-project/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp (revision fe48aaf1a4aa0cf13bdd8c1754de11b39f03290f)
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 =
173       constructMatcher("recordDecl", VariantMatcher::SingleMatcher(Anything))
174           .getTypedMatcher<Decl>();
175 
176   EXPECT_TRUE(matches("int a;", Anything));
177   EXPECT_TRUE(matches("class A {};", Anything));
178   EXPECT_TRUE(matches("void f(){};", Anything));
179   // FIXME: A couple of tests have been suppressed.
180   // I know it'd be bad with _MSC_VER here, though.
181 #if !defined(_MSC_VER)
182   EXPECT_FALSE(matches("int a;", RecordDecl));
183 #endif
184   EXPECT_TRUE(matches("class A {};", RecordDecl));
185 #if !defined(_MSC_VER)
186   EXPECT_FALSE(matches("void f(){};", RecordDecl));
187 #endif
188 }
189 
190 TEST_F(RegistryTest, TemplateArgument) {
191   Matcher<Decl> HasTemplateArgument = constructMatcher(
192       "classTemplateSpecializationDecl",
193       constructMatcher(
194           "hasAnyTemplateArgument",
195           constructMatcher("refersToType",
196                            constructMatcher("asString", std::string("int")))))
197       .getTypedMatcher<Decl>();
198   EXPECT_TRUE(matches("template<typename T> class A {}; A<int> a;",
199                       HasTemplateArgument));
200   EXPECT_FALSE(matches("template<typename T> class A {}; A<char> a;",
201                        HasTemplateArgument));
202 }
203 
204 TEST_F(RegistryTest, TypeTraversal) {
205   Matcher<Type> M = constructMatcher(
206       "pointerType",
207       constructMatcher("pointee", constructMatcher("isConstQualified"),
208                        constructMatcher("isInteger"))).getTypedMatcher<Type>();
209   EXPECT_FALSE(matches("int *a;", M));
210   EXPECT_TRUE(matches("int const *b;", M));
211 
212   M = constructMatcher(
213       "arrayType",
214       constructMatcher("hasElementType", constructMatcher("builtinType")))
215       .getTypedMatcher<Type>();
216   EXPECT_FALSE(matches("struct A{}; A a[7];;", M));
217   EXPECT_TRUE(matches("int b[7];", M));
218 }
219 
220 TEST_F(RegistryTest, CXXCtorInitializer) {
221   Matcher<Decl> CtorDecl = constructMatcher(
222       "constructorDecl",
223       constructMatcher(
224           "hasAnyConstructorInitializer",
225           constructMatcher("forField",
226                            constructMatcher("hasName", std::string("foo")))))
227       .getTypedMatcher<Decl>();
228   EXPECT_TRUE(matches("struct Foo { Foo() : foo(1) {} int foo; };", CtorDecl));
229   EXPECT_FALSE(matches("struct Foo { Foo() {} int foo; };", CtorDecl));
230   EXPECT_FALSE(matches("struct Foo { Foo() : bar(1) {} int bar; };", CtorDecl));
231 }
232 
233 TEST_F(RegistryTest, Adaptative) {
234   Matcher<Decl> D = constructMatcher(
235       "recordDecl",
236       constructMatcher(
237           "has",
238           constructMatcher("recordDecl",
239                            constructMatcher("hasName", std::string("X")))))
240       .getTypedMatcher<Decl>();
241   EXPECT_TRUE(matches("class X {};", D));
242   EXPECT_TRUE(matches("class Y { class X {}; };", D));
243   EXPECT_FALSE(matches("class Y { class Z {}; };", D));
244 
245   Matcher<Stmt> S = constructMatcher(
246       "forStmt",
247       constructMatcher(
248           "hasDescendant",
249           constructMatcher("varDecl",
250                            constructMatcher("hasName", std::string("X")))))
251       .getTypedMatcher<Stmt>();
252   EXPECT_TRUE(matches("void foo() { for(int X;;); }", S));
253   EXPECT_TRUE(matches("void foo() { for(;;) { int X; } }", S));
254   EXPECT_FALSE(matches("void foo() { for(;;); }", S));
255   EXPECT_FALSE(matches("void foo() { if (int X = 0){} }", S));
256 
257   S = constructMatcher(
258       "compoundStmt", constructMatcher("hasParent", constructMatcher("ifStmt")))
259       .getTypedMatcher<Stmt>();
260   EXPECT_TRUE(matches("void foo() { if (true) { int x = 42; } }", S));
261   EXPECT_FALSE(matches("void foo() { if (true) return; }", S));
262 }
263 
264 TEST_F(RegistryTest, VariadicOp) {
265   Matcher<Decl> D = constructMatcher(
266       "anyOf", constructMatcher("recordDecl"),
267       constructMatcher("namedDecl",
268                        constructMatcher("hasName", std::string("foo"))))
269       .getTypedMatcher<Decl>();
270 
271   EXPECT_TRUE(matches("void foo(){}", D));
272   EXPECT_TRUE(matches("struct Foo{};", D));
273   EXPECT_FALSE(matches("int i = 0;", D));
274 
275   D = constructMatcher(
276       "allOf", constructMatcher("recordDecl"),
277       constructMatcher(
278           "namedDecl",
279           constructMatcher("anyOf",
280                            constructMatcher("hasName", std::string("Foo")),
281                            constructMatcher("hasName", std::string("Bar")))))
282       .getTypedMatcher<Decl>();
283 
284   EXPECT_FALSE(matches("void foo(){}", D));
285   EXPECT_TRUE(matches("struct Foo{};", D));
286   EXPECT_FALSE(matches("int i = 0;", D));
287   EXPECT_TRUE(matches("class Bar{};", D));
288   EXPECT_FALSE(matches("class OtherBar{};", D));
289 }
290 
291 TEST_F(RegistryTest, Errors) {
292   // Incorrect argument count.
293   OwningPtr<Diagnostics> Error(new Diagnostics());
294   EXPECT_TRUE(constructMatcher("hasInitializer", Error.get()).isNull());
295   EXPECT_EQ("Incorrect argument count. (Expected = 1) != (Actual = 0)",
296             Error->toString());
297   Error.reset(new Diagnostics());
298   EXPECT_TRUE(constructMatcher("isArrow", std::string(), Error.get()).isNull());
299   EXPECT_EQ("Incorrect argument count. (Expected = 0) != (Actual = 1)",
300             Error->toString());
301 
302   // Bad argument type
303   Error.reset(new Diagnostics());
304   EXPECT_TRUE(constructMatcher("ofClass", std::string(), Error.get()).isNull());
305   EXPECT_EQ("Incorrect type for arg 1. (Expected = Matcher<CXXRecordDecl>) != "
306             "(Actual = String)",
307             Error->toString());
308   Error.reset(new Diagnostics());
309   EXPECT_TRUE(constructMatcher("recordDecl", constructMatcher("recordDecl"),
310                                constructMatcher("parameterCountIs", 3),
311                                Error.get()).isNull());
312   EXPECT_EQ("Incorrect type for arg 2. (Expected = Matcher<CXXRecordDecl>) != "
313             "(Actual = Matcher<FunctionDecl>)",
314             Error->toString());
315 
316   // Bad argument type with variadic.
317   Error.reset(new Diagnostics());
318   EXPECT_TRUE(constructMatcher("anyOf", std::string(), Error.get()).isNull());
319   EXPECT_EQ(
320       "Incorrect type for arg 1. (Expected = Matcher<>) != (Actual = String)",
321       Error->toString());
322   Error.reset(new Diagnostics());
323   EXPECT_TRUE(constructMatcher(
324       "recordDecl",
325       constructMatcher("allOf",
326                        constructMatcher("isDerivedFrom", std::string("FOO")),
327                        constructMatcher("isArrow")),
328       Error.get()).isNull());
329   EXPECT_EQ("Incorrect type for arg 1. "
330             "(Expected = Matcher<CXXRecordDecl>) != "
331             "(Actual = Matcher<CXXRecordDecl>&Matcher<MemberExpr>)",
332             Error->toString());
333 }
334 
335 } // end anonymous namespace
336 } // end namespace dynamic
337 } // end namespace ast_matchers
338 } // end namespace clang
339