RegistryTest.cpp revision 3f84bb341bfb1312842b09db71d76bc3898ba247
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, 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
160TEST_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
176TEST_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