xref: /llvm-project/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp (revision 7f8a5b140aaac95c73bb7b57875252f79dd14a4a)
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   MatcherList constructMatcher(StringRef MatcherName,
40                                Diagnostics *Error = NULL) {
41     Diagnostics DummyError;
42     if (!Error) Error = &DummyError;
43     const MatcherList Out =
44         Registry::constructMatcher(MatcherName, SourceRange(), Args(), Error);
45     EXPECT_EQ("", DummyError.toStringFull());
46     return Out;
47   }
48 
49   MatcherList constructMatcher(StringRef MatcherName, const VariantValue &Arg1,
50                                Diagnostics *Error = NULL) {
51     Diagnostics DummyError;
52     if (!Error) Error = &DummyError;
53     const MatcherList Out = Registry::constructMatcher(
54         MatcherName, SourceRange(), Args(Arg1), Error);
55     EXPECT_EQ("", DummyError.toStringFull());
56     return Out;
57   }
58 
59   MatcherList constructMatcher(StringRef MatcherName, const VariantValue &Arg1,
60                                const VariantValue &Arg2,
61                                Diagnostics *Error = NULL) {
62     Diagnostics DummyError;
63     if (!Error) Error = &DummyError;
64     const MatcherList Out = Registry::constructMatcher(
65         MatcherName, SourceRange(), Args(Arg1, Arg2), Error);
66     EXPECT_EQ("", DummyError.toStringFull());
67     return Out;
68   }
69 };
70 
71 TEST_F(RegistryTest, CanConstructNoArgs) {
72   Matcher<Stmt> IsArrowValue = constructMatcher(
73       "memberExpr", constructMatcher("isArrow")).getTypedMatcher<Stmt>();
74   Matcher<Stmt> BoolValue =
75       constructMatcher("boolLiteral").getTypedMatcher<Stmt>();
76 
77   const std::string ClassSnippet = "struct Foo { int x; };\n"
78                                    "Foo *foo = new Foo;\n"
79                                    "int i = foo->x;\n";
80   const std::string BoolSnippet = "bool Foo = true;\n";
81 
82   EXPECT_TRUE(matches(ClassSnippet, IsArrowValue));
83   EXPECT_TRUE(matches(BoolSnippet, BoolValue));
84   EXPECT_FALSE(matches(ClassSnippet, BoolValue));
85   EXPECT_FALSE(matches(BoolSnippet, IsArrowValue));
86 }
87 
88 TEST_F(RegistryTest, ConstructWithSimpleArgs) {
89   Matcher<Decl> Value = constructMatcher(
90       "namedDecl", constructMatcher("hasName", std::string("X")))
91       .getTypedMatcher<Decl>();
92   EXPECT_TRUE(matches("class X {};", Value));
93   EXPECT_FALSE(matches("int x;", Value));
94 
95   Value = functionDecl(constructMatcher("parameterCountIs", 2)
96                            .getTypedMatcher<FunctionDecl>());
97   EXPECT_TRUE(matches("void foo(int,int);", Value));
98   EXPECT_FALSE(matches("void foo(int);", Value));
99 }
100 
101 TEST_F(RegistryTest, ConstructWithMatcherArgs) {
102   Matcher<Decl> HasInitializerSimple =
103       constructMatcher("varDecl", constructMatcher("hasInitializer", stmt()))
104           .getTypedMatcher<Decl>();
105   Matcher<Decl> HasInitializerComplex = constructMatcher(
106       "varDecl", constructMatcher("hasInitializer", callExpr()))
107       .getTypedMatcher<Decl>();
108 
109   std::string code = "int i;";
110   EXPECT_FALSE(matches(code, HasInitializerSimple));
111   EXPECT_FALSE(matches(code, HasInitializerComplex));
112 
113   code = "int i = 1;";
114   EXPECT_TRUE(matches(code, HasInitializerSimple));
115   EXPECT_FALSE(matches(code, HasInitializerComplex));
116 
117   code = "int y(); int i = y();";
118   EXPECT_TRUE(matches(code, HasInitializerSimple));
119   EXPECT_TRUE(matches(code, HasInitializerComplex));
120 
121   Matcher<Decl> HasParameter = functionDecl(constructMatcher(
122       "hasParameter", 1, hasName("x")).getTypedMatcher<FunctionDecl>());
123   EXPECT_TRUE(matches("void f(int a, int x);", HasParameter));
124   EXPECT_FALSE(matches("void f(int x, int a);", HasParameter));
125 }
126 
127 TEST_F(RegistryTest, OverloadedMatchers) {
128   Matcher<Stmt> CallExpr0 = constructMatcher(
129       "callExpr",
130       constructMatcher("callee", constructMatcher("memberExpr",
131                                                   constructMatcher("isArrow"))))
132       .getTypedMatcher<Stmt>();
133 
134   Matcher<Stmt> CallExpr1 = constructMatcher(
135       "callExpr",
136       constructMatcher(
137           "callee",
138           constructMatcher("methodDecl",
139                            constructMatcher("hasName", std::string("x")))))
140       .getTypedMatcher<Stmt>();
141 
142   std::string Code = "class Y { public: void x(); }; void z() { Y y; y.x(); }";
143   EXPECT_FALSE(matches(Code, CallExpr0));
144   EXPECT_TRUE(matches(Code, CallExpr1));
145 
146   Code = "class Z { public: void z() { this->z(); } };";
147   EXPECT_TRUE(matches(Code, CallExpr0));
148   EXPECT_FALSE(matches(Code, CallExpr1));
149 }
150 
151 TEST_F(RegistryTest, PolymorphicMatchers) {
152   const MatcherList IsDefinition = constructMatcher("isDefinition");
153   Matcher<Decl> Var =
154       constructMatcher("varDecl", IsDefinition).getTypedMatcher<Decl>();
155   Matcher<Decl> Class =
156       constructMatcher("recordDecl", IsDefinition).getTypedMatcher<Decl>();
157   Matcher<Decl> Func =
158       constructMatcher("functionDecl", IsDefinition).getTypedMatcher<Decl>();
159   EXPECT_TRUE(matches("int a;", Var));
160   EXPECT_FALSE(matches("extern int a;", Var));
161   EXPECT_TRUE(matches("class A {};", Class));
162   EXPECT_FALSE(matches("class A;", Class));
163   EXPECT_TRUE(matches("void f(){};", Func));
164   EXPECT_FALSE(matches("void f();", Func));
165 
166   Matcher<Decl> Anything = constructMatcher("anything").getTypedMatcher<Decl>();
167   Matcher<Decl> RecordDecl =
168       constructMatcher("recordDecl", Anything).getTypedMatcher<Decl>();
169 
170   EXPECT_TRUE(matches("int a;", Anything));
171   EXPECT_TRUE(matches("class A {};", Anything));
172   EXPECT_TRUE(matches("void f(){};", Anything));
173   // FIXME: A couple of tests have been suppressed.
174   // I know it'd be bad with _MSC_VER here, though.
175 #if !defined(_MSC_VER)
176   EXPECT_FALSE(matches("int a;", RecordDecl));
177 #endif
178   EXPECT_TRUE(matches("class A {};", RecordDecl));
179 #if !defined(_MSC_VER)
180   EXPECT_FALSE(matches("void f(){};", RecordDecl));
181 #endif
182 }
183 
184 TEST_F(RegistryTest, TemplateArgument) {
185   Matcher<Decl> HasTemplateArgument = constructMatcher(
186       "classTemplateSpecializationDecl",
187       constructMatcher(
188           "hasAnyTemplateArgument",
189           constructMatcher("refersToType",
190                            constructMatcher("asString", std::string("int")))))
191       .getTypedMatcher<Decl>();
192   EXPECT_TRUE(matches("template<typename T> class A {}; A<int> a;",
193                       HasTemplateArgument));
194   EXPECT_FALSE(matches("template<typename T> class A {}; A<char> a;",
195                        HasTemplateArgument));
196 }
197 
198 TEST_F(RegistryTest, TypeTraversal) {
199   Matcher<Type> M = constructMatcher(
200       "pointerType",
201       constructMatcher("pointee", constructMatcher("isConstQualified"),
202                        constructMatcher("isInteger"))).getTypedMatcher<Type>();
203   EXPECT_FALSE(matches("int *a;", M));
204   EXPECT_TRUE(matches("int const *b;", M));
205 
206   M = constructMatcher(
207       "arrayType",
208       constructMatcher("hasElementType", constructMatcher("builtinType")))
209       .getTypedMatcher<Type>();
210   EXPECT_FALSE(matches("struct A{}; A a[7];;", M));
211   EXPECT_TRUE(matches("int b[7];", M));
212 }
213 
214 TEST_F(RegistryTest, CXXCtorInitializer) {
215   Matcher<Decl> CtorDecl = constructMatcher(
216       "constructorDecl",
217       constructMatcher("hasAnyConstructorInitializer",
218                        constructMatcher("forField", hasName("foo"))))
219       .getTypedMatcher<Decl>();
220   EXPECT_TRUE(matches("struct Foo { Foo() : foo(1) {} int foo; };", CtorDecl));
221   EXPECT_FALSE(matches("struct Foo { Foo() {} int foo; };", CtorDecl));
222   EXPECT_FALSE(matches("struct Foo { Foo() : bar(1) {} int bar; };", CtorDecl));
223 }
224 
225 TEST_F(RegistryTest, Adaptative) {
226   Matcher<Decl> D = constructMatcher(
227       "recordDecl",
228       constructMatcher(
229           "has",
230           constructMatcher("recordDecl",
231                            constructMatcher("hasName", std::string("X")))))
232       .getTypedMatcher<Decl>();
233   EXPECT_TRUE(matches("class X {};", D));
234   EXPECT_TRUE(matches("class Y { class X {}; };", D));
235   EXPECT_FALSE(matches("class Y { class Z {}; };", D));
236 
237   Matcher<Stmt> S = constructMatcher(
238       "forStmt",
239       constructMatcher(
240           "hasDescendant",
241           constructMatcher("varDecl",
242                            constructMatcher("hasName", std::string("X")))))
243       .getTypedMatcher<Stmt>();
244   EXPECT_TRUE(matches("void foo() { for(int X;;); }", S));
245   EXPECT_TRUE(matches("void foo() { for(;;) { int X; } }", S));
246   EXPECT_FALSE(matches("void foo() { for(;;); }", S));
247   EXPECT_FALSE(matches("void foo() { if (int X = 0){} }", S));
248 
249   S = constructMatcher(
250       "compoundStmt", constructMatcher("hasParent", constructMatcher("ifStmt")))
251       .getTypedMatcher<Stmt>();
252   EXPECT_TRUE(matches("void foo() { if (true) { int x = 42; } }", S));
253   EXPECT_FALSE(matches("void foo() { if (true) return; }", S));
254 }
255 
256 TEST_F(RegistryTest, Errors) {
257   // Incorrect argument count.
258   OwningPtr<Diagnostics> Error(new Diagnostics());
259   EXPECT_TRUE(constructMatcher("hasInitializer", Error.get()).empty());
260   EXPECT_EQ("Incorrect argument count. (Expected = 1) != (Actual = 0)",
261             Error->toString());
262   Error.reset(new Diagnostics());
263   EXPECT_TRUE(constructMatcher("isArrow", std::string(), Error.get()).empty());
264   EXPECT_EQ("Incorrect argument count. (Expected = 0) != (Actual = 1)",
265             Error->toString());
266 
267   // Bad argument type
268   Error.reset(new Diagnostics());
269   EXPECT_TRUE(constructMatcher("ofClass", std::string(), Error.get()).empty());
270   EXPECT_EQ("Incorrect type for arg 1. (Expected = Matcher<CXXRecordDecl>) != "
271             "(Actual = String)",
272             Error->toString());
273   Error.reset(new Diagnostics());
274   EXPECT_TRUE(constructMatcher("recordDecl", recordDecl(), parameterCountIs(3),
275                                Error.get()).empty());
276   EXPECT_EQ("Incorrect type for arg 2. (Expected = Matcher<CXXRecordDecl>) != "
277             "(Actual = Matcher<FunctionDecl>)",
278             Error->toString());
279 }
280 
281 } // end anonymous namespace
282 } // end namespace dynamic
283 } // end namespace ast_matchers
284 } // end namespace clang
285