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
16namespace clang {
17namespace ast_matchers {
18namespace dynamic {
19namespace {
20
21using ast_matchers::internal::Matcher;
22
23class RegistryTest : public ::testing::Test {
24public:
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
71TEST_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
88TEST_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
101TEST_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
127TEST_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
151TEST_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
184TEST_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
198TEST_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
214TEST_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
225TEST_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
256TEST_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