xref: /llvm-project/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp (revision 79656e19c8b8919f461367f5c03c3eb27be5548b)
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, PolymorphicMatchers) {
128   const MatcherList IsDefinition = constructMatcher("isDefinition");
129   Matcher<Decl> Var =
130       constructMatcher("varDecl", IsDefinition).getTypedMatcher<Decl>();
131   Matcher<Decl> Class =
132       constructMatcher("recordDecl", IsDefinition).getTypedMatcher<Decl>();
133   Matcher<Decl> Func =
134       constructMatcher("functionDecl", IsDefinition).getTypedMatcher<Decl>();
135   EXPECT_TRUE(matches("int a;", Var));
136   EXPECT_FALSE(matches("extern int a;", Var));
137   EXPECT_TRUE(matches("class A {};", Class));
138   EXPECT_FALSE(matches("class A;", Class));
139   EXPECT_TRUE(matches("void f(){};", Func));
140   EXPECT_FALSE(matches("void f();", Func));
141 
142   Matcher<Decl> Anything = constructMatcher("anything").getTypedMatcher<Decl>();
143   Matcher<Decl> RecordDecl =
144       constructMatcher("recordDecl", Anything).getTypedMatcher<Decl>();
145 
146   EXPECT_TRUE(matches("int a;", Anything));
147   EXPECT_TRUE(matches("class A {};", Anything));
148   EXPECT_TRUE(matches("void f(){};", Anything));
149   // FIXME: A couple of tests have been suppressed.
150   // I know it'd be bad with _MSC_VER here, though.
151 #if !defined(_MSC_VER)
152   EXPECT_FALSE(matches("int a;", RecordDecl));
153 #endif
154   EXPECT_TRUE(matches("class A {};", RecordDecl));
155 #if !defined(_MSC_VER)
156   EXPECT_FALSE(matches("void f(){};", RecordDecl));
157 #endif
158 }
159 
160 TEST_F(RegistryTest, TypeTraversal) {
161   Matcher<Type> M = constructMatcher(
162       "pointerType",
163       constructMatcher("pointee", constructMatcher("isConstQualified"),
164                        constructMatcher("isInteger"))).getTypedMatcher<Type>();
165   EXPECT_FALSE(matches("int *a;", M));
166   EXPECT_TRUE(matches("int const *b;", M));
167 
168   M = constructMatcher(
169       "arrayType",
170       constructMatcher("hasElementType", constructMatcher("builtinType")))
171       .getTypedMatcher<Type>();
172   EXPECT_FALSE(matches("struct A{}; A a[7];;", M));
173   EXPECT_TRUE(matches("int b[7];", M));
174 }
175 
176 TEST_F(RegistryTest, Errors) {
177   // Incorrect argument count.
178   OwningPtr<Diagnostics> Error(new Diagnostics());
179   EXPECT_TRUE(constructMatcher("hasInitializer", Error.get()).empty());
180   EXPECT_EQ("Incorrect argument count. (Expected = 1) != (Actual = 0)",
181             Error->ToString());
182   Error.reset(new Diagnostics());
183   EXPECT_TRUE(constructMatcher("isArrow", std::string(), Error.get()).empty());
184   EXPECT_EQ("Incorrect argument count. (Expected = 0) != (Actual = 1)",
185             Error->ToString());
186 
187   // Bad argument type
188   Error.reset(new Diagnostics());
189   EXPECT_TRUE(constructMatcher("ofClass", std::string(), Error.get()).empty());
190   EXPECT_EQ("Incorrect type for arg 1. (Expected = Matcher<CXXRecordDecl>) != "
191             "(Actual = String)",
192             Error->ToString());
193   Error.reset(new Diagnostics());
194   EXPECT_TRUE(constructMatcher("recordDecl", recordDecl(), parameterCountIs(3),
195                                Error.get()).empty());
196   EXPECT_EQ("Incorrect type for arg 2. (Expected = Matcher<CXXRecordDecl>) != "
197             "(Actual = Matcher<FunctionDecl>)",
198             Error->ToString());
199 }
200 
201 } // end anonymous namespace
202 } // end namespace dynamic
203 } // end namespace ast_matchers
204 } // end namespace clang
205