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 "../ASTMatchersTest.h"
11#include "clang/ASTMatchers/Dynamic/Registry.h"
12#include "gtest/gtest.h"
13#include <vector>
14
15namespace clang {
16namespace ast_matchers {
17namespace dynamic {
18namespace {
19
20using ast_matchers::internal::Matcher;
21
22class RegistryTest : public ::testing::Test {
23public:
24  std::vector<ParserValue> Args() { return std::vector<ParserValue>(); }
25  std::vector<ParserValue> Args(const VariantValue &Arg1) {
26    std::vector<ParserValue> Out(1);
27    Out[0].Value = Arg1;
28    return Out;
29  }
30  std::vector<ParserValue> Args(const VariantValue &Arg1,
31                                const VariantValue &Arg2) {
32    std::vector<ParserValue> Out(2);
33    Out[0].Value = Arg1;
34    Out[1].Value = Arg2;
35    return Out;
36  }
37
38  llvm::Optional<MatcherCtor> lookupMatcherCtor(StringRef MatcherName) {
39    return Registry::lookupMatcherCtor(MatcherName);
40  }
41
42  VariantMatcher constructMatcher(StringRef MatcherName,
43                                  Diagnostics *Error = nullptr) {
44    Diagnostics DummyError;
45    if (!Error) Error = &DummyError;
46    llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName);
47    VariantMatcher Out;
48    if (Ctor)
49      Out = Registry::constructMatcher(*Ctor, SourceRange(), Args(), Error);
50    EXPECT_EQ("", DummyError.toStringFull());
51    return Out;
52  }
53
54  VariantMatcher constructMatcher(StringRef MatcherName,
55                                  const VariantValue &Arg1,
56                                  Diagnostics *Error = nullptr) {
57    Diagnostics DummyError;
58    if (!Error) Error = &DummyError;
59    llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName);
60    VariantMatcher Out;
61    if (Ctor)
62      Out = Registry::constructMatcher(*Ctor, SourceRange(), Args(Arg1), Error);
63    EXPECT_EQ("", DummyError.toStringFull()) << MatcherName;
64    return Out;
65  }
66
67  VariantMatcher constructMatcher(StringRef MatcherName,
68                                  const VariantValue &Arg1,
69                                  const VariantValue &Arg2,
70                                  Diagnostics *Error = nullptr) {
71    Diagnostics DummyError;
72    if (!Error) Error = &DummyError;
73    llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName);
74    VariantMatcher Out;
75    if (Ctor)
76      Out = Registry::constructMatcher(*Ctor, SourceRange(), Args(Arg1, Arg2),
77                                       Error);
78    EXPECT_EQ("", DummyError.toStringFull());
79    return Out;
80  }
81
82  typedef std::vector<MatcherCompletion> CompVector;
83
84  CompVector getCompletions() {
85    std::vector<std::pair<MatcherCtor, unsigned> > Context;
86    return Registry::getMatcherCompletions(
87        Registry::getAcceptedCompletionTypes(Context));
88  }
89
90  CompVector getCompletions(StringRef MatcherName1, unsigned ArgNo1) {
91    std::vector<std::pair<MatcherCtor, unsigned> > Context;
92    llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName1);
93    if (!Ctor)
94      return CompVector();
95    Context.push_back(std::make_pair(*Ctor, ArgNo1));
96    return Registry::getMatcherCompletions(
97        Registry::getAcceptedCompletionTypes(Context));
98  }
99
100  CompVector getCompletions(StringRef MatcherName1, unsigned ArgNo1,
101                            StringRef MatcherName2, unsigned ArgNo2) {
102    std::vector<std::pair<MatcherCtor, unsigned> > Context;
103    llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName1);
104    if (!Ctor)
105      return CompVector();
106    Context.push_back(std::make_pair(*Ctor, ArgNo1));
107    Ctor = lookupMatcherCtor(MatcherName2);
108    if (!Ctor)
109      return CompVector();
110    Context.push_back(std::make_pair(*Ctor, ArgNo2));
111    return Registry::getMatcherCompletions(
112        Registry::getAcceptedCompletionTypes(Context));
113  }
114
115  bool hasCompletion(const CompVector &Comps, StringRef TypedText,
116                     StringRef MatcherDecl = StringRef()) {
117    for (CompVector::const_iterator I = Comps.begin(), E = Comps.end(); I != E;
118         ++I) {
119      if (I->TypedText == TypedText &&
120          (MatcherDecl.empty() || I->MatcherDecl == MatcherDecl)) {
121        return true;
122      }
123    }
124    return false;
125  }
126};
127
128TEST_F(RegistryTest, CanConstructNoArgs) {
129  Matcher<Stmt> IsArrowValue = constructMatcher(
130      "memberExpr", constructMatcher("isArrow")).getTypedMatcher<Stmt>();
131  Matcher<Stmt> BoolValue =
132      constructMatcher("cxxBoolLiteral").getTypedMatcher<Stmt>();
133
134  const std::string ClassSnippet = "struct Foo { int x; };\n"
135                                   "Foo *foo = new Foo;\n"
136                                   "int i = foo->x;\n";
137  const std::string BoolSnippet = "bool Foo = true;\n";
138
139  EXPECT_TRUE(matches(ClassSnippet, IsArrowValue));
140  EXPECT_TRUE(matches(BoolSnippet, BoolValue));
141  EXPECT_FALSE(matches(ClassSnippet, BoolValue));
142  EXPECT_FALSE(matches(BoolSnippet, IsArrowValue));
143}
144
145TEST_F(RegistryTest, ConstructWithSimpleArgs) {
146  Matcher<Decl> Value = constructMatcher(
147      "namedDecl", constructMatcher("hasName", StringRef("X")))
148      .getTypedMatcher<Decl>();
149  EXPECT_TRUE(matches("class X {};", Value));
150  EXPECT_FALSE(matches("int x;", Value));
151
152  Value = functionDecl(constructMatcher("parameterCountIs", 2)
153                           .getTypedMatcher<FunctionDecl>());
154  EXPECT_TRUE(matches("void foo(int,int);", Value));
155  EXPECT_FALSE(matches("void foo(int);", Value));
156}
157
158TEST_F(RegistryTest, ConstructWithMatcherArgs) {
159  Matcher<Decl> HasInitializerSimple = constructMatcher(
160      "varDecl", constructMatcher("hasInitializer", constructMatcher("stmt")))
161      .getTypedMatcher<Decl>();
162  Matcher<Decl> HasInitializerComplex = constructMatcher(
163      "varDecl",
164      constructMatcher("hasInitializer", constructMatcher("callExpr")))
165      .getTypedMatcher<Decl>();
166
167  std::string code = "int i;";
168  EXPECT_FALSE(matches(code, HasInitializerSimple));
169  EXPECT_FALSE(matches(code, HasInitializerComplex));
170
171  code = "int i = 1;";
172  EXPECT_TRUE(matches(code, HasInitializerSimple));
173  EXPECT_FALSE(matches(code, HasInitializerComplex));
174
175  code = "int y(); int i = y();";
176  EXPECT_TRUE(matches(code, HasInitializerSimple));
177  EXPECT_TRUE(matches(code, HasInitializerComplex));
178
179  Matcher<Decl> HasParameter =
180      functionDecl(constructMatcher(
181          "hasParameter", 1, constructMatcher("hasName", StringRef("x")))
182                       .getTypedMatcher<FunctionDecl>());
183  EXPECT_TRUE(matches("void f(int a, int x);", HasParameter));
184  EXPECT_FALSE(matches("void f(int x, int a);", HasParameter));
185}
186
187TEST_F(RegistryTest, OverloadedMatchers) {
188  Matcher<Stmt> CallExpr0 = constructMatcher(
189      "callExpr",
190      constructMatcher("callee", constructMatcher("memberExpr",
191                                                  constructMatcher("isArrow"))))
192      .getTypedMatcher<Stmt>();
193
194  Matcher<Stmt> CallExpr1 = constructMatcher(
195      "callExpr",
196      constructMatcher(
197          "callee",
198          constructMatcher("cxxMethodDecl",
199                           constructMatcher("hasName", StringRef("x")))))
200      .getTypedMatcher<Stmt>();
201
202  std::string Code = "class Y { public: void x(); }; void z() { Y y; y.x(); }";
203  EXPECT_FALSE(matches(Code, CallExpr0));
204  EXPECT_TRUE(matches(Code, CallExpr1));
205
206  Code = "class Z { public: void z() { this->z(); } };";
207  EXPECT_TRUE(matches(Code, CallExpr0));
208  EXPECT_FALSE(matches(Code, CallExpr1));
209
210  Matcher<Decl> DeclDecl = declaratorDecl(hasTypeLoc(
211      constructMatcher(
212          "loc", constructMatcher("asString", StringRef("const double *")))
213          .getTypedMatcher<TypeLoc>()));
214
215  Matcher<NestedNameSpecifierLoc> NNSL =
216      constructMatcher(
217          "loc", VariantMatcher::SingleMatcher(nestedNameSpecifier(
218                     specifiesType(hasDeclaration(recordDecl(hasName("A")))))))
219          .getTypedMatcher<NestedNameSpecifierLoc>();
220
221  Code = "const double * x = 0;";
222  EXPECT_TRUE(matches(Code, DeclDecl));
223  EXPECT_FALSE(matches(Code, NNSL));
224
225  Code = "struct A { struct B {}; }; A::B a_b;";
226  EXPECT_FALSE(matches(Code, DeclDecl));
227  EXPECT_TRUE(matches(Code, NNSL));
228}
229
230TEST_F(RegistryTest, PolymorphicMatchers) {
231  const VariantMatcher IsDefinition = constructMatcher("isDefinition");
232  Matcher<Decl> Var =
233      constructMatcher("varDecl", IsDefinition).getTypedMatcher<Decl>();
234  Matcher<Decl> Class =
235      constructMatcher("recordDecl", IsDefinition).getTypedMatcher<Decl>();
236  Matcher<Decl> Func =
237      constructMatcher("functionDecl", IsDefinition).getTypedMatcher<Decl>();
238  EXPECT_TRUE(matches("int a;", Var));
239  EXPECT_FALSE(matches("extern int a;", Var));
240  EXPECT_TRUE(matches("class A {};", Class));
241  EXPECT_FALSE(matches("class A;", Class));
242  EXPECT_TRUE(matches("void f(){};", Func));
243  EXPECT_FALSE(matches("void f();", Func));
244
245  Matcher<Decl> Anything = constructMatcher("anything").getTypedMatcher<Decl>();
246  Matcher<Decl> RecordDecl = constructMatcher(
247      "recordDecl", constructMatcher("hasName", StringRef("Foo")),
248      VariantMatcher::SingleMatcher(Anything)).getTypedMatcher<Decl>();
249
250  EXPECT_TRUE(matches("int Foo;", Anything));
251  EXPECT_TRUE(matches("class Foo {};", Anything));
252  EXPECT_TRUE(matches("void Foo(){};", Anything));
253  EXPECT_FALSE(matches("int Foo;", RecordDecl));
254  EXPECT_TRUE(matches("class Foo {};", RecordDecl));
255  EXPECT_FALSE(matches("void Foo(){};", RecordDecl));
256
257  Matcher<Stmt> ConstructExpr = constructMatcher(
258      "cxxConstructExpr",
259      constructMatcher(
260          "hasDeclaration",
261          constructMatcher(
262              "cxxMethodDecl",
263              constructMatcher(
264                  "ofClass", constructMatcher("hasName", StringRef("Foo"))))))
265                                    .getTypedMatcher<Stmt>();
266  EXPECT_FALSE(matches("class Foo { public: Foo(); };", ConstructExpr));
267  EXPECT_TRUE(
268      matches("class Foo { public: Foo(); }; Foo foo = Foo();", ConstructExpr));
269}
270
271TEST_F(RegistryTest, TemplateArgument) {
272  Matcher<Decl> HasTemplateArgument = constructMatcher(
273      "classTemplateSpecializationDecl",
274      constructMatcher(
275          "hasAnyTemplateArgument",
276          constructMatcher("refersToType",
277                           constructMatcher("asString", StringRef("int")))))
278      .getTypedMatcher<Decl>();
279  EXPECT_TRUE(matches("template<typename T> class A {}; A<int> a;",
280                      HasTemplateArgument));
281  EXPECT_FALSE(matches("template<typename T> class A {}; A<char> a;",
282                       HasTemplateArgument));
283}
284
285TEST_F(RegistryTest, TypeTraversal) {
286  Matcher<Type> M = constructMatcher(
287      "pointerType",
288      constructMatcher("pointee", constructMatcher("isConstQualified"),
289                       constructMatcher("isInteger"))).getTypedMatcher<Type>();
290  EXPECT_FALSE(matches("int *a;", M));
291  EXPECT_TRUE(matches("int const *b;", M));
292
293  M = constructMatcher(
294      "arrayType",
295      constructMatcher("hasElementType", constructMatcher("builtinType")))
296      .getTypedMatcher<Type>();
297  EXPECT_FALSE(matches("struct A{}; A a[7];;", M));
298  EXPECT_TRUE(matches("int b[7];", M));
299}
300
301TEST_F(RegistryTest, CXXCtorInitializer) {
302  Matcher<Decl> CtorDecl = constructMatcher(
303      "cxxConstructorDecl",
304      constructMatcher(
305          "hasAnyConstructorInitializer",
306          constructMatcher("forField",
307                           constructMatcher("hasName", StringRef("foo")))))
308      .getTypedMatcher<Decl>();
309  EXPECT_TRUE(matches("struct Foo { Foo() : foo(1) {} int foo; };", CtorDecl));
310  EXPECT_FALSE(matches("struct Foo { Foo() {} int foo; };", CtorDecl));
311  EXPECT_FALSE(matches("struct Foo { Foo() : bar(1) {} int bar; };", CtorDecl));
312}
313
314TEST_F(RegistryTest, Adaptative) {
315  Matcher<Decl> D = constructMatcher(
316      "recordDecl",
317      constructMatcher(
318          "has",
319          constructMatcher("recordDecl",
320                           constructMatcher("hasName", StringRef("X")))))
321      .getTypedMatcher<Decl>();
322  EXPECT_TRUE(matches("class X {};", D));
323  EXPECT_TRUE(matches("class Y { class X {}; };", D));
324  EXPECT_FALSE(matches("class Y { class Z {}; };", D));
325
326  Matcher<Stmt> S = constructMatcher(
327      "forStmt",
328      constructMatcher(
329          "hasDescendant",
330          constructMatcher("varDecl",
331                           constructMatcher("hasName", StringRef("X")))))
332      .getTypedMatcher<Stmt>();
333  EXPECT_TRUE(matches("void foo() { for(int X;;); }", S));
334  EXPECT_TRUE(matches("void foo() { for(;;) { int X; } }", S));
335  EXPECT_FALSE(matches("void foo() { for(;;); }", S));
336  EXPECT_FALSE(matches("void foo() { if (int X = 0){} }", S));
337
338  S = constructMatcher(
339      "compoundStmt", constructMatcher("hasParent", constructMatcher("ifStmt")))
340      .getTypedMatcher<Stmt>();
341  EXPECT_TRUE(matches("void foo() { if (true) { int x = 42; } }", S));
342  EXPECT_FALSE(matches("void foo() { if (true) return; }", S));
343}
344
345TEST_F(RegistryTest, VariadicOp) {
346  Matcher<Decl> D = constructMatcher(
347      "anyOf",
348      constructMatcher("recordDecl",
349                       constructMatcher("hasName", StringRef("Foo"))),
350      constructMatcher("functionDecl",
351                       constructMatcher("hasName", StringRef("foo"))))
352      .getTypedMatcher<Decl>();
353
354  EXPECT_TRUE(matches("void foo(){}", D));
355  EXPECT_TRUE(matches("struct Foo{};", D));
356  EXPECT_FALSE(matches("int i = 0;", D));
357
358  D = constructMatcher(
359      "allOf", constructMatcher("recordDecl"),
360      constructMatcher(
361          "namedDecl",
362          constructMatcher("anyOf",
363                           constructMatcher("hasName", StringRef("Foo")),
364                           constructMatcher("hasName", StringRef("Bar")))))
365      .getTypedMatcher<Decl>();
366
367  EXPECT_FALSE(matches("void foo(){}", D));
368  EXPECT_TRUE(matches("struct Foo{};", D));
369  EXPECT_FALSE(matches("int i = 0;", D));
370  EXPECT_TRUE(matches("class Bar{};", D));
371  EXPECT_FALSE(matches("class OtherBar{};", D));
372
373  D = recordDecl(
374      has(fieldDecl(hasName("Foo"))),
375      constructMatcher(
376          "unless",
377          constructMatcher("namedDecl",
378                           constructMatcher("hasName", StringRef("Bar"))))
379          .getTypedMatcher<Decl>());
380
381  EXPECT_FALSE(matches("class Bar{ int Foo; };", D));
382  EXPECT_TRUE(matches("class OtherBar{ int Foo; };", D));
383
384  D = constructMatcher(
385          "namedDecl", constructMatcher("hasName", StringRef("Foo")),
386          constructMatcher("unless", constructMatcher("recordDecl")))
387          .getTypedMatcher<Decl>();
388  EXPECT_TRUE(matches("void Foo(){}", D));
389  EXPECT_TRUE(notMatches("struct Foo {};", D));
390}
391
392TEST_F(RegistryTest, Errors) {
393  // Incorrect argument count.
394  std::unique_ptr<Diagnostics> Error(new Diagnostics());
395  EXPECT_TRUE(constructMatcher("hasInitializer", Error.get()).isNull());
396  EXPECT_EQ("Incorrect argument count. (Expected = 1) != (Actual = 0)",
397            Error->toString());
398  Error.reset(new Diagnostics());
399  EXPECT_TRUE(constructMatcher("isArrow", StringRef(), Error.get()).isNull());
400  EXPECT_EQ("Incorrect argument count. (Expected = 0) != (Actual = 1)",
401            Error->toString());
402  Error.reset(new Diagnostics());
403  EXPECT_TRUE(constructMatcher("anyOf", Error.get()).isNull());
404  EXPECT_EQ("Incorrect argument count. (Expected = (2, )) != (Actual = 0)",
405            Error->toString());
406  Error.reset(new Diagnostics());
407  EXPECT_TRUE(constructMatcher("unless", StringRef(), StringRef(),
408                               Error.get()).isNull());
409  EXPECT_EQ("Incorrect argument count. (Expected = (1, 1)) != (Actual = 2)",
410            Error->toString());
411
412  // Bad argument type
413  Error.reset(new Diagnostics());
414  EXPECT_TRUE(constructMatcher("ofClass", StringRef(), Error.get()).isNull());
415  EXPECT_EQ("Incorrect type for arg 1. (Expected = Matcher<CXXRecordDecl>) != "
416            "(Actual = String)",
417            Error->toString());
418  Error.reset(new Diagnostics());
419  EXPECT_TRUE(
420      constructMatcher("cxxRecordDecl", constructMatcher("cxxRecordDecl"),
421                       constructMatcher("parameterCountIs", 3), Error.get())
422          .isNull());
423  EXPECT_EQ("Incorrect type for arg 2. (Expected = Matcher<CXXRecordDecl>) != "
424            "(Actual = Matcher<FunctionDecl>)",
425            Error->toString());
426
427  // Bad argument type with variadic.
428  Error.reset(new Diagnostics());
429  EXPECT_TRUE(constructMatcher("anyOf", StringRef(), StringRef(),
430                               Error.get()).isNull());
431  EXPECT_EQ(
432      "Incorrect type for arg 1. (Expected = Matcher<>) != (Actual = String)",
433      Error->toString());
434  Error.reset(new Diagnostics());
435  EXPECT_TRUE(constructMatcher(
436      "cxxRecordDecl",
437      constructMatcher("allOf",
438                       constructMatcher("isDerivedFrom", StringRef("FOO")),
439                       constructMatcher("isArrow")),
440      Error.get()).isNull());
441  EXPECT_EQ("Incorrect type for arg 1. "
442            "(Expected = Matcher<CXXRecordDecl>) != "
443            "(Actual = Matcher<CXXRecordDecl>&Matcher<MemberExpr>)",
444            Error->toString());
445}
446
447TEST_F(RegistryTest, Completion) {
448  CompVector Comps = getCompletions();
449  // Overloaded
450  EXPECT_TRUE(hasCompletion(
451      Comps, "hasParent(",
452      "Matcher<TemplateArgument|NestedNameSpecifierLoc|Decl|...> "
453      "hasParent(Matcher<TemplateArgument|NestedNameSpecifierLoc|Decl|...>)"));
454  // Variadic.
455  EXPECT_TRUE(hasCompletion(Comps, "whileStmt(",
456                            "Matcher<Stmt> whileStmt(Matcher<WhileStmt>...)"));
457  // Polymorphic.
458  EXPECT_TRUE(hasCompletion(
459      Comps, "hasDescendant(",
460      "Matcher<TemplateArgument|NestedNameSpecifier|NestedNameSpecifierLoc|...>"
461      " hasDescendant(Matcher<TemplateArgument|NestedNameSpecifier|"
462      "NestedNameSpecifierLoc|...>)"));
463
464  CompVector WhileComps = getCompletions("whileStmt", 0);
465
466  EXPECT_TRUE(hasCompletion(WhileComps, "hasBody(",
467                            "Matcher<WhileStmt> hasBody(Matcher<Stmt>)"));
468  EXPECT_TRUE(hasCompletion(WhileComps, "hasParent(",
469                            "Matcher<Stmt> "
470                            "hasParent(Matcher<TemplateArgument|"
471                            "NestedNameSpecifierLoc|Decl|...>)"));
472  EXPECT_TRUE(
473      hasCompletion(WhileComps, "allOf(", "Matcher<T> allOf(Matcher<T>...)"));
474
475  EXPECT_FALSE(hasCompletion(WhileComps, "whileStmt("));
476  EXPECT_FALSE(hasCompletion(WhileComps, "ifStmt("));
477
478  CompVector AllOfWhileComps =
479      getCompletions("allOf", 0, "whileStmt", 0);
480  ASSERT_EQ(AllOfWhileComps.size(), WhileComps.size());
481  EXPECT_TRUE(std::equal(WhileComps.begin(), WhileComps.end(),
482                         AllOfWhileComps.begin()));
483
484  CompVector DeclWhileComps =
485      getCompletions("decl", 0, "whileStmt", 0);
486  EXPECT_EQ(0u, DeclWhileComps.size());
487
488  CompVector NamedDeclComps = getCompletions("namedDecl", 0);
489  EXPECT_TRUE(
490      hasCompletion(NamedDeclComps, "isPublic()", "Matcher<Decl> isPublic()"));
491  EXPECT_TRUE(hasCompletion(NamedDeclComps, "hasName(\"",
492                            "Matcher<NamedDecl> hasName(string)"));
493
494  // Heterogeneous overloads.
495  Comps = getCompletions("classTemplateSpecializationDecl", 0);
496  EXPECT_TRUE(hasCompletion(
497      Comps, "isSameOrDerivedFrom(",
498      "Matcher<CXXRecordDecl> isSameOrDerivedFrom(string|Matcher<NamedDecl>)"));
499}
500
501TEST_F(RegistryTest, HasArgs) {
502  Matcher<Decl> Value = constructMatcher(
503      "decl", constructMatcher("hasAttr", StringRef("attr::WarnUnused")))
504      .getTypedMatcher<Decl>();
505  EXPECT_TRUE(matches("struct __attribute__((warn_unused)) X {};", Value));
506  EXPECT_FALSE(matches("struct X {};", Value));
507}
508
509} // end anonymous namespace
510} // end namespace dynamic
511} // end namespace ast_matchers
512} // end namespace clang
513