blob: 310108a38ce47766ba1bc722fbeafcc4216581b4 [file] [log] [blame]
Manuel Klimekf7f295f2013-05-14 09:13:00 +00001//===- unittest/ASTMatchers/Dynamic/ParserTest.cpp - Parser 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 <string>
11#include <vector>
12
13#include "../ASTMatchersTest.h"
14#include "clang/ASTMatchers/Dynamic/Parser.h"
15#include "clang/ASTMatchers/Dynamic/Registry.h"
16#include "gtest/gtest.h"
17#include "llvm/ADT/StringMap.h"
18
19namespace clang {
20namespace ast_matchers {
21namespace dynamic {
22namespace {
23
24class DummyDynTypedMatcher : public DynTypedMatcher {
25public:
26 DummyDynTypedMatcher(uint64_t ID) : ID(ID) {}
Samuel Benzaquen4f37d922013-06-03 19:31:08 +000027 DummyDynTypedMatcher(uint64_t ID, StringRef BoundID)
28 : ID(ID), BoundID(BoundID) {}
Manuel Klimekf7f295f2013-05-14 09:13:00 +000029
30 typedef ast_matchers::internal::ASTMatchFinder ASTMatchFinder;
31 typedef ast_matchers::internal::BoundNodesTreeBuilder BoundNodesTreeBuilder;
32 virtual bool matches(const ast_type_traits::DynTypedNode DynNode,
33 ASTMatchFinder *Finder,
34 BoundNodesTreeBuilder *Builder) const {
35 return false;
36 }
37
38 /// \brief Makes a copy of this matcher object.
39 virtual DynTypedMatcher *clone() const {
Samuel Benzaquen4f37d922013-06-03 19:31:08 +000040 return new DummyDynTypedMatcher(*this);
Manuel Klimekf7f295f2013-05-14 09:13:00 +000041 }
42
43 /// \brief Returns a unique ID for the matcher.
44 virtual uint64_t getID() const { return ID; }
45
Samuel Benzaquen4f37d922013-06-03 19:31:08 +000046 virtual DynTypedMatcher* tryBind(StringRef BoundID) const {
47 return new DummyDynTypedMatcher(ID, BoundID);
48 }
49
50 StringRef boundID() const { return BoundID; }
51
Manuel Klimekf7f295f2013-05-14 09:13:00 +000052private:
53 uint64_t ID;
Samuel Benzaquen4f37d922013-06-03 19:31:08 +000054 std::string BoundID;
Manuel Klimekf7f295f2013-05-14 09:13:00 +000055};
56
57class MockSema : public Parser::Sema {
58public:
59 virtual ~MockSema() {}
60
61 uint64_t expectMatcher(StringRef MatcherName) {
62 uint64_t ID = ExpectedMatchers.size() + 1;
63 ExpectedMatchers[MatcherName] = ID;
64 return ID;
65 }
66
67 void parse(StringRef Code) {
68 Diagnostics Error;
69 VariantValue Value;
70 Parser::parseExpression(Code, this, &Value, &Error);
71 Values.push_back(Value);
72 Errors.push_back(Error.ToStringFull());
73 }
74
75 DynTypedMatcher *actOnMatcherExpression(StringRef MatcherName,
76 const SourceRange &NameRange,
Samuel Benzaquen4f37d922013-06-03 19:31:08 +000077 StringRef BindID,
Manuel Klimekf7f295f2013-05-14 09:13:00 +000078 ArrayRef<ParserValue> Args,
79 Diagnostics *Error) {
Samuel Benzaquen4f37d922013-06-03 19:31:08 +000080 MatcherInfo ToStore = { MatcherName, NameRange, Args, BindID };
Manuel Klimekf7f295f2013-05-14 09:13:00 +000081 Matchers.push_back(ToStore);
Samuel Benzaquen4f37d922013-06-03 19:31:08 +000082 DummyDynTypedMatcher Matcher(ExpectedMatchers[MatcherName]);
83 return Matcher.tryBind(BindID);
Manuel Klimekf7f295f2013-05-14 09:13:00 +000084 }
85
86 struct MatcherInfo {
87 StringRef MatcherName;
88 SourceRange NameRange;
89 std::vector<ParserValue> Args;
Samuel Benzaquen4f37d922013-06-03 19:31:08 +000090 std::string BoundID;
Manuel Klimekf7f295f2013-05-14 09:13:00 +000091 };
92
93 std::vector<std::string> Errors;
94 std::vector<VariantValue> Values;
95 std::vector<MatcherInfo> Matchers;
96 llvm::StringMap<uint64_t> ExpectedMatchers;
97};
98
99TEST(ParserTest, ParseString) {
100 MockSema Sema;
101 Sema.parse("\"Foo\"");
102 Sema.parse("\"\"");
103 Sema.parse("\"Baz");
104 EXPECT_EQ(3ULL, Sema.Values.size());
105 EXPECT_EQ("Foo", Sema.Values[0].getString());
106 EXPECT_EQ("", Sema.Values[1].getString());
107 EXPECT_EQ("1:1: Error parsing string token: <\"Baz>", Sema.Errors[2]);
108}
109
110bool matchesRange(const SourceRange &Range, unsigned StartLine,
111 unsigned EndLine, unsigned StartColumn, unsigned EndColumn) {
112 EXPECT_EQ(StartLine, Range.Start.Line);
113 EXPECT_EQ(EndLine, Range.End.Line);
114 EXPECT_EQ(StartColumn, Range.Start.Column);
115 EXPECT_EQ(EndColumn, Range.End.Column);
116 return Range.Start.Line == StartLine && Range.End.Line == EndLine &&
117 Range.Start.Column == StartColumn && Range.End.Column == EndColumn;
118}
119
120TEST(ParserTest, ParseMatcher) {
121 MockSema Sema;
122 const uint64_t ExpectedFoo = Sema.expectMatcher("Foo");
123 const uint64_t ExpectedBar = Sema.expectMatcher("Bar");
124 const uint64_t ExpectedBaz = Sema.expectMatcher("Baz");
Samuel Benzaquen4f37d922013-06-03 19:31:08 +0000125 Sema.parse(" Foo ( Bar (), Baz( \n \"B A,Z\") ) .bind( \"Yo!\") ");
Manuel Klimekf7f295f2013-05-14 09:13:00 +0000126 for (size_t i = 0, e = Sema.Errors.size(); i != e; ++i) {
127 EXPECT_EQ("", Sema.Errors[i]);
128 }
129
130 EXPECT_EQ(1ULL, Sema.Values.size());
131 EXPECT_EQ(ExpectedFoo, Sema.Values[0].getMatcher().getID());
Samuel Benzaquen4f37d922013-06-03 19:31:08 +0000132 EXPECT_EQ("Yo!", static_cast<const DummyDynTypedMatcher &>(
133 Sema.Values[0].getMatcher()).boundID());
Manuel Klimekf7f295f2013-05-14 09:13:00 +0000134
135 EXPECT_EQ(3ULL, Sema.Matchers.size());
136 const MockSema::MatcherInfo Bar = Sema.Matchers[0];
137 EXPECT_EQ("Bar", Bar.MatcherName);
138 EXPECT_TRUE(matchesRange(Bar.NameRange, 1, 1, 8, 14));
139 EXPECT_EQ(0ULL, Bar.Args.size());
140
141 const MockSema::MatcherInfo Baz = Sema.Matchers[1];
142 EXPECT_EQ("Baz", Baz.MatcherName);
143 EXPECT_TRUE(matchesRange(Baz.NameRange, 1, 2, 16, 10));
144 EXPECT_EQ(1ULL, Baz.Args.size());
145 EXPECT_EQ("B A,Z", Baz.Args[0].Value.getString());
146
147 const MockSema::MatcherInfo Foo = Sema.Matchers[2];
148 EXPECT_EQ("Foo", Foo.MatcherName);
149 EXPECT_TRUE(matchesRange(Foo.NameRange, 1, 2, 2, 12));
150 EXPECT_EQ(2ULL, Foo.Args.size());
151 EXPECT_EQ(ExpectedBar, Foo.Args[0].Value.getMatcher().getID());
152 EXPECT_EQ(ExpectedBaz, Foo.Args[1].Value.getMatcher().getID());
Samuel Benzaquen4f37d922013-06-03 19:31:08 +0000153 EXPECT_EQ("Yo!", Foo.BoundID);
Manuel Klimekf7f295f2013-05-14 09:13:00 +0000154}
155
156using ast_matchers::internal::Matcher;
157
158TEST(ParserTest, FullParserTest) {
159 OwningPtr<DynTypedMatcher> Matcher(Parser::parseMatcherExpression(
160 "hasInitializer(binaryOperator(hasLHS(integerLiteral())))", NULL));
161 EXPECT_TRUE(matchesDynamic("int x = 1 + false;", *Matcher));
162 EXPECT_FALSE(matchesDynamic("int x = true + 1;", *Matcher));
163
164 Diagnostics Error;
165 EXPECT_TRUE(Parser::parseMatcherExpression(
166 "hasInitializer(\n binaryOperator(hasLHS(\"A\")))", &Error) == NULL);
167 EXPECT_EQ("1:1: Error parsing argument 1 for matcher hasInitializer.\n"
168 "2:5: Error parsing argument 1 for matcher binaryOperator.\n"
169 "2:20: Error building matcher hasLHS.\n"
170 "2:27: Incorrect type on function hasLHS for arg 1.",
171 Error.ToStringFull());
172}
173
174std::string ParseWithError(StringRef Code) {
175 Diagnostics Error;
176 VariantValue Value;
177 Parser::parseExpression(Code, &Value, &Error);
178 return Error.ToStringFull();
179}
180
181std::string ParseMatcherWithError(StringRef Code) {
182 Diagnostics Error;
183 Parser::parseMatcherExpression(Code, &Error);
184 return Error.ToStringFull();
185}
186
187TEST(ParserTest, Errors) {
188 EXPECT_EQ(
189 "1:5: Error parsing matcher. Found token <123> while looking for '('.",
190 ParseWithError("Foo 123"));
191 EXPECT_EQ(
192 "1:9: Error parsing matcher. Found token <123> while looking for ','.",
193 ParseWithError("Foo(\"A\" 123)"));
194 EXPECT_EQ(
195 "1:4: Error parsing matcher. Found end-of-code while looking for ')'.",
196 ParseWithError("Foo("));
197 EXPECT_EQ("1:1: End of code found while looking for token.",
198 ParseWithError(""));
199 EXPECT_EQ("Input value is not a matcher expression.",
200 ParseMatcherWithError("\"A\""));
201 EXPECT_EQ("1:1: Error parsing argument 1 for matcher Foo.\n"
202 "1:5: Invalid token <(> found when looking for a value.",
203 ParseWithError("Foo(("));
Samuel Benzaquen4f37d922013-06-03 19:31:08 +0000204 EXPECT_EQ("1:7: Expected end of code.", ParseWithError("expr()a"));
205 EXPECT_EQ("1:11: Malformed bind() expression.",
206 ParseWithError("isArrow().biind"));
207 EXPECT_EQ("1:15: Malformed bind() expression.",
208 ParseWithError("isArrow().bind"));
209 EXPECT_EQ("1:16: Malformed bind() expression.",
210 ParseWithError("isArrow().bind(foo"));
211 EXPECT_EQ("1:21: Malformed bind() expression.",
212 ParseWithError("isArrow().bind(\"foo\""));
213 EXPECT_EQ("1:1: Error building matcher isArrow.\n"
214 "1:1: Matcher does not support binding.",
215 ParseWithError("isArrow().bind(\"foo\")"));
Manuel Klimekf7f295f2013-05-14 09:13:00 +0000216}
217
218} // end anonymous namespace
219} // end namespace dynamic
220} // end namespace ast_matchers
221} // end namespace clang