xref: /llvm-project/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp (revision e0b2c8e478bea77088f8c1d2fdc2cbfa61ac59b1)
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, Errors) {
226   // Incorrect argument count.
227   OwningPtr<Diagnostics> Error(new Diagnostics());
228   EXPECT_TRUE(constructMatcher("hasInitializer", Error.get()).empty());
229   EXPECT_EQ("Incorrect argument count. (Expected = 1) != (Actual = 0)",
230             Error->toString());
231   Error.reset(new Diagnostics());
232   EXPECT_TRUE(constructMatcher("isArrow", std::string(), Error.get()).empty());
233   EXPECT_EQ("Incorrect argument count. (Expected = 0) != (Actual = 1)",
234             Error->toString());
235 
236   // Bad argument type
237   Error.reset(new Diagnostics());
238   EXPECT_TRUE(constructMatcher("ofClass", std::string(), Error.get()).empty());
239   EXPECT_EQ("Incorrect type for arg 1. (Expected = Matcher<CXXRecordDecl>) != "
240             "(Actual = String)",
241             Error->toString());
242   Error.reset(new Diagnostics());
243   EXPECT_TRUE(constructMatcher("recordDecl", recordDecl(), parameterCountIs(3),
244                                Error.get()).empty());
245   EXPECT_EQ("Incorrect type for arg 2. (Expected = Matcher<CXXRecordDecl>) != "
246             "(Actual = Matcher<FunctionDecl>)",
247             Error->toString());
248 }
249 
250 } // end anonymous namespace
251 } // end namespace dynamic
252 } // end namespace ast_matchers
253 } // end namespace clang
254