1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | #include "../ASTMatchersTest.h" |
10 | #include "clang/ASTMatchers/Dynamic/Parser.h" |
11 | #include "clang/ASTMatchers/Dynamic/Registry.h" |
12 | #include "llvm/ADT/Optional.h" |
13 | #include "gtest/gtest.h" |
14 | #include <string> |
15 | #include <vector> |
16 | |
17 | namespace clang { |
18 | namespace ast_matchers { |
19 | namespace dynamic { |
20 | namespace { |
21 | |
22 | class MockSema : public Parser::Sema { |
23 | public: |
24 | ~MockSema() override {} |
25 | |
26 | uint64_t expectMatcher(StringRef MatcherName) { |
27 | |
28 | |
29 | |
30 | ast_matchers::internal::Matcher<Stmt> M = stmt(stmt(), stmt()); |
31 | ExpectedMatchers.insert(std::make_pair(MatcherName, M)); |
32 | return M.getID().second; |
33 | } |
34 | |
35 | void parse(StringRef Code) { |
36 | Diagnostics Error; |
37 | VariantValue Value; |
38 | Parser::parseExpression(Code, this, &Value, &Error); |
39 | Values.push_back(Value); |
40 | Errors.push_back(Error.toStringFull()); |
41 | } |
42 | |
43 | llvm::Optional<MatcherCtor> |
44 | lookupMatcherCtor(StringRef MatcherName) override { |
45 | const ExpectedMatchersTy::value_type *Matcher = |
46 | &*ExpectedMatchers.find(MatcherName); |
47 | return reinterpret_cast<MatcherCtor>(Matcher); |
48 | } |
49 | |
50 | VariantMatcher actOnMatcherExpression(MatcherCtor Ctor, |
51 | SourceRange NameRange, |
52 | StringRef BindID, |
53 | ArrayRef<ParserValue> Args, |
54 | Diagnostics *Error) override { |
55 | const ExpectedMatchersTy::value_type *Matcher = |
56 | reinterpret_cast<const ExpectedMatchersTy::value_type *>(Ctor); |
57 | MatcherInfo ToStore = { Matcher->first, NameRange, Args, BindID }; |
58 | Matchers.push_back(ToStore); |
59 | return VariantMatcher::SingleMatcher(Matcher->second); |
60 | } |
61 | |
62 | struct MatcherInfo { |
63 | StringRef MatcherName; |
64 | SourceRange NameRange; |
65 | std::vector<ParserValue> Args; |
66 | std::string BoundID; |
67 | }; |
68 | |
69 | std::vector<std::string> Errors; |
70 | std::vector<VariantValue> Values; |
71 | std::vector<MatcherInfo> Matchers; |
72 | typedef std::map<std::string, ast_matchers::internal::Matcher<Stmt> > |
73 | ExpectedMatchersTy; |
74 | ExpectedMatchersTy ExpectedMatchers; |
75 | }; |
76 | |
77 | TEST(ParserTest, ParseBoolean) { |
78 | MockSema Sema; |
79 | Sema.parse("true"); |
80 | Sema.parse("false"); |
81 | EXPECT_EQ(2U, Sema.Values.size()); |
82 | EXPECT_TRUE(Sema.Values[0].getBoolean()); |
83 | EXPECT_FALSE(Sema.Values[1].getBoolean()); |
84 | } |
85 | |
86 | TEST(ParserTest, ParseDouble) { |
87 | MockSema Sema; |
88 | Sema.parse("1.0"); |
89 | Sema.parse("2.0f"); |
90 | Sema.parse("34.56e-78"); |
91 | Sema.parse("4.E+6"); |
92 | Sema.parse("1"); |
93 | EXPECT_EQ(5U, Sema.Values.size()); |
94 | EXPECT_EQ(1.0, Sema.Values[0].getDouble()); |
95 | EXPECT_EQ("1:1: Error parsing numeric literal: <2.0f>", Sema.Errors[1]); |
96 | EXPECT_EQ(34.56e-78, Sema.Values[2].getDouble()); |
97 | EXPECT_EQ(4e+6, Sema.Values[3].getDouble()); |
98 | EXPECT_FALSE(Sema.Values[4].isDouble()); |
99 | } |
100 | |
101 | TEST(ParserTest, ParseUnsigned) { |
102 | MockSema Sema; |
103 | Sema.parse("0"); |
104 | Sema.parse("123"); |
105 | Sema.parse("0x1f"); |
106 | Sema.parse("12345678901"); |
107 | Sema.parse("1a1"); |
108 | EXPECT_EQ(5U, Sema.Values.size()); |
109 | EXPECT_EQ(0U, Sema.Values[0].getUnsigned()); |
110 | EXPECT_EQ(123U, Sema.Values[1].getUnsigned()); |
111 | EXPECT_EQ(31U, Sema.Values[2].getUnsigned()); |
112 | EXPECT_EQ("1:1: Error parsing numeric literal: <12345678901>", Sema.Errors[3]); |
113 | EXPECT_EQ("1:1: Error parsing numeric literal: <1a1>", Sema.Errors[4]); |
114 | } |
115 | |
116 | TEST(ParserTest, ParseString) { |
117 | MockSema Sema; |
118 | Sema.parse("\"Foo\""); |
119 | Sema.parse("\"\""); |
120 | Sema.parse("\"Baz"); |
121 | EXPECT_EQ(3ULL, Sema.Values.size()); |
122 | EXPECT_EQ("Foo", Sema.Values[0].getString()); |
123 | EXPECT_EQ("", Sema.Values[1].getString()); |
124 | EXPECT_EQ("1:1: Error parsing string token: <\"Baz>", Sema.Errors[2]); |
125 | } |
126 | |
127 | bool matchesRange(SourceRange Range, unsigned StartLine, |
128 | unsigned EndLine, unsigned StartColumn, unsigned EndColumn) { |
129 | EXPECT_EQ(StartLine, Range.Start.Line); |
130 | EXPECT_EQ(EndLine, Range.End.Line); |
131 | EXPECT_EQ(StartColumn, Range.Start.Column); |
132 | EXPECT_EQ(EndColumn, Range.End.Column); |
133 | return Range.Start.Line == StartLine && Range.End.Line == EndLine && |
134 | Range.Start.Column == StartColumn && Range.End.Column == EndColumn; |
135 | } |
136 | |
137 | llvm::Optional<DynTypedMatcher> getSingleMatcher(const VariantValue &Value) { |
138 | llvm::Optional<DynTypedMatcher> Result = |
139 | Value.getMatcher().getSingleMatcher(); |
140 | EXPECT_TRUE(Result.hasValue()); |
141 | return Result; |
142 | } |
143 | |
144 | TEST(ParserTest, ParseMatcher) { |
145 | MockSema Sema; |
146 | const uint64_t ExpectedFoo = Sema.expectMatcher("Foo"); |
147 | const uint64_t ExpectedBar = Sema.expectMatcher("Bar"); |
148 | const uint64_t ExpectedBaz = Sema.expectMatcher("Baz"); |
149 | Sema.parse(" Foo ( Bar ( 17), Baz( \n \"B A,Z\") ) .bind( \"Yo!\") "); |
150 | for (const auto &E : Sema.Errors) { |
151 | EXPECT_EQ("", E); |
152 | } |
153 | |
154 | EXPECT_NE(ExpectedFoo, ExpectedBar); |
155 | EXPECT_NE(ExpectedFoo, ExpectedBaz); |
156 | EXPECT_NE(ExpectedBar, ExpectedBaz); |
157 | |
158 | EXPECT_EQ(1ULL, Sema.Values.size()); |
159 | EXPECT_EQ(ExpectedFoo, getSingleMatcher(Sema.Values[0])->getID().second); |
160 | |
161 | EXPECT_EQ(3ULL, Sema.Matchers.size()); |
162 | const MockSema::MatcherInfo Bar = Sema.Matchers[0]; |
163 | EXPECT_EQ("Bar", Bar.MatcherName); |
164 | EXPECT_TRUE(matchesRange(Bar.NameRange, 1, 1, 8, 17)); |
165 | EXPECT_EQ(1ULL, Bar.Args.size()); |
166 | EXPECT_EQ(17U, Bar.Args[0].Value.getUnsigned()); |
167 | |
168 | const MockSema::MatcherInfo Baz = Sema.Matchers[1]; |
169 | EXPECT_EQ("Baz", Baz.MatcherName); |
170 | EXPECT_TRUE(matchesRange(Baz.NameRange, 1, 2, 19, 10)); |
171 | EXPECT_EQ(1ULL, Baz.Args.size()); |
172 | EXPECT_EQ("B A,Z", Baz.Args[0].Value.getString()); |
173 | |
174 | const MockSema::MatcherInfo Foo = Sema.Matchers[2]; |
175 | EXPECT_EQ("Foo", Foo.MatcherName); |
176 | EXPECT_TRUE(matchesRange(Foo.NameRange, 1, 2, 2, 12)); |
177 | EXPECT_EQ(2ULL, Foo.Args.size()); |
178 | EXPECT_EQ(ExpectedBar, getSingleMatcher(Foo.Args[0].Value)->getID().second); |
179 | EXPECT_EQ(ExpectedBaz, getSingleMatcher(Foo.Args[1].Value)->getID().second); |
180 | EXPECT_EQ("Yo!", Foo.BoundID); |
181 | } |
182 | |
183 | TEST(ParserTest, ParseComment) { |
184 | MockSema Sema; |
185 | Sema.expectMatcher("Foo"); |
186 | Sema.parse(" Foo() # Bar() "); |
187 | for (const auto &E : Sema.Errors) { |
188 | EXPECT_EQ("", E); |
189 | } |
190 | |
191 | EXPECT_EQ(1ULL, Sema.Matchers.size()); |
192 | |
193 | Sema.parse("Foo(#) "); |
194 | |
195 | EXPECT_EQ("1:4: Error parsing matcher. Found end-of-code while looking for ')'.", Sema.Errors[1]); |
196 | } |
197 | |
198 | using ast_matchers::internal::Matcher; |
199 | |
200 | Parser::NamedValueMap getTestNamedValues() { |
201 | Parser::NamedValueMap Values; |
202 | Values["nameX"] = llvm::StringRef("x"); |
203 | Values["hasParamA"] = VariantMatcher::SingleMatcher( |
204 | functionDecl(hasParameter(0, hasName("a")))); |
205 | return Values; |
206 | } |
207 | |
208 | TEST(ParserTest, FullParserTest) { |
209 | Diagnostics Error; |
210 | llvm::Optional<DynTypedMatcher> VarDecl(Parser::parseMatcherExpression( |
211 | "varDecl(hasInitializer(binaryOperator(hasLHS(integerLiteral())," |
212 | " hasOperatorName(\"+\"))))", |
213 | &Error)); |
214 | EXPECT_EQ("", Error.toStringFull()); |
215 | Matcher<Decl> M = VarDecl->unconditionalConvertTo<Decl>(); |
216 | EXPECT_TRUE(matches("int x = 1 + false;", M)); |
217 | EXPECT_FALSE(matches("int x = true + 1;", M)); |
218 | EXPECT_FALSE(matches("int x = 1 - false;", M)); |
219 | EXPECT_FALSE(matches("int x = true - 1;", M)); |
220 | |
221 | llvm::Optional<DynTypedMatcher> HasParameter(Parser::parseMatcherExpression( |
222 | "functionDecl(hasParameter(1, hasName(\"x\")))", &Error)); |
223 | EXPECT_EQ("", Error.toStringFull()); |
224 | M = HasParameter->unconditionalConvertTo<Decl>(); |
225 | |
226 | EXPECT_TRUE(matches("void f(int a, int x);", M)); |
227 | EXPECT_FALSE(matches("void f(int x, int a);", M)); |
228 | |
229 | |
230 | auto NamedValues = getTestNamedValues(); |
231 | llvm::Optional<DynTypedMatcher> HasParameterWithNamedValues( |
232 | Parser::parseMatcherExpression( |
233 | "functionDecl(hasParamA, hasParameter(1, hasName(nameX)))", |
234 | nullptr, &NamedValues, &Error)); |
235 | EXPECT_EQ("", Error.toStringFull()); |
236 | M = HasParameterWithNamedValues->unconditionalConvertTo<Decl>(); |
237 | |
238 | EXPECT_TRUE(matches("void f(int a, int x);", M)); |
239 | EXPECT_FALSE(matches("void f(int x, int a);", M)); |
240 | |
241 | |
242 | EXPECT_TRUE(!Parser::parseMatcherExpression( |
243 | "hasInitializer(\n binaryOperator(hasLHS(\"A\")))", |
244 | &Error).hasValue()); |
245 | EXPECT_EQ("1:1: Error parsing argument 1 for matcher hasInitializer.\n" |
246 | "2:5: Error parsing argument 1 for matcher binaryOperator.\n" |
247 | "2:20: Error building matcher hasLHS.\n" |
248 | "2:27: Incorrect type for arg 1. " |
249 | "(Expected = Matcher<Expr>) != (Actual = String)", |
250 | Error.toStringFull()); |
251 | } |
252 | |
253 | TEST(ParserTest, VariadicMatchTest) { |
254 | Diagnostics Error; |
255 | llvm::Optional<DynTypedMatcher> OM(Parser::parseMatcherExpression( |
256 | "stmt(objcMessageExpr(hasAnySelector(\"methodA\", \"methodB:\")))", |
257 | &Error)); |
258 | EXPECT_EQ("", Error.toStringFull()); |
259 | auto M = OM->unconditionalConvertTo<Stmt>(); |
260 | EXPECT_TRUE(matchesObjC("@interface I @end " |
261 | "void foo(I* i) { [i methodA]; }", M)); |
262 | } |
263 | |
264 | std::string ParseWithError(StringRef Code) { |
265 | Diagnostics Error; |
266 | VariantValue Value; |
267 | Parser::parseExpression(Code, &Value, &Error); |
268 | return Error.toStringFull(); |
269 | } |
270 | |
271 | std::string ParseMatcherWithError(StringRef Code) { |
272 | Diagnostics Error; |
273 | Parser::parseMatcherExpression(Code, &Error); |
274 | return Error.toStringFull(); |
275 | } |
276 | |
277 | TEST(ParserTest, Errors) { |
278 | EXPECT_EQ( |
279 | "1:5: Error parsing matcher. Found token <123> while looking for '('.", |
280 | ParseWithError("Foo 123")); |
281 | EXPECT_EQ( |
282 | "1:1: Matcher not found: Foo\n" |
283 | "1:9: Error parsing matcher. Found token <123> while looking for ','.", |
284 | ParseWithError("Foo(\"A\" 123)")); |
285 | EXPECT_EQ( |
286 | "1:1: Error parsing argument 1 for matcher stmt.\n" |
287 | "1:6: Value not found: someValue", |
288 | ParseWithError("stmt(someValue)")); |
289 | EXPECT_EQ( |
290 | "1:1: Matcher not found: Foo\n" |
291 | "1:4: Error parsing matcher. Found end-of-code while looking for ')'.", |
292 | ParseWithError("Foo(")); |
293 | EXPECT_EQ("1:1: End of code found while looking for token.", |
294 | ParseWithError("")); |
295 | EXPECT_EQ("Input value is not a matcher expression.", |
296 | ParseMatcherWithError("\"A\"")); |
297 | EXPECT_EQ("1:1: Matcher not found: Foo\n" |
298 | "1:1: Error parsing argument 1 for matcher Foo.\n" |
299 | "1:5: Invalid token <(> found when looking for a value.", |
300 | ParseWithError("Foo((")); |
301 | EXPECT_EQ("1:7: Expected end of code.", ParseWithError("expr()a")); |
302 | EXPECT_EQ("1:11: Malformed bind() expression.", |
303 | ParseWithError("isArrow().biind")); |
304 | EXPECT_EQ("1:15: Malformed bind() expression.", |
305 | ParseWithError("isArrow().bind")); |
306 | EXPECT_EQ("1:16: Malformed bind() expression.", |
307 | ParseWithError("isArrow().bind(foo")); |
308 | EXPECT_EQ("1:21: Malformed bind() expression.", |
309 | ParseWithError("isArrow().bind(\"foo\"")); |
310 | EXPECT_EQ("1:1: Error building matcher isArrow.\n" |
311 | "1:1: Matcher does not support binding.", |
312 | ParseWithError("isArrow().bind(\"foo\")")); |
313 | EXPECT_EQ("Input value has unresolved overloaded type: " |
314 | "Matcher<DoStmt|ForStmt|WhileStmt|CXXForRangeStmt|FunctionDecl>", |
315 | ParseMatcherWithError("hasBody(stmt())")); |
316 | } |
317 | |
318 | TEST(ParserTest, OverloadErrors) { |
319 | EXPECT_EQ("1:1: Error building matcher callee.\n" |
320 | "1:8: Candidate 1: Incorrect type for arg 1. " |
321 | "(Expected = Matcher<Stmt>) != (Actual = String)\n" |
322 | "1:8: Candidate 2: Incorrect type for arg 1. " |
323 | "(Expected = Matcher<Decl>) != (Actual = String)", |
324 | ParseWithError("callee(\"A\")")); |
325 | } |
326 | |
327 | TEST(ParserTest, CompletionRegistry) { |
328 | std::vector<MatcherCompletion> Comps = |
329 | Parser::completeExpression("while", 5); |
330 | ASSERT_EQ(1u, Comps.size()); |
331 | EXPECT_EQ("Stmt(", Comps[0].TypedText); |
332 | EXPECT_EQ("Matcher<Stmt> whileStmt(Matcher<WhileStmt>...)", |
333 | Comps[0].MatcherDecl); |
334 | |
335 | Comps = Parser::completeExpression("whileStmt().", 12); |
336 | ASSERT_EQ(1u, Comps.size()); |
337 | EXPECT_EQ("bind(\"", Comps[0].TypedText); |
338 | EXPECT_EQ("bind", Comps[0].MatcherDecl); |
339 | } |
340 | |
341 | TEST(ParserTest, CompletionNamedValues) { |
342 | |
343 | auto NamedValues = getTestNamedValues(); |
344 | StringRef Code = "functionDecl(hasName("; |
345 | std::vector<MatcherCompletion> Comps = |
346 | Parser::completeExpression(Code, Code.size(), nullptr, &NamedValues); |
347 | ASSERT_EQ(1u, Comps.size()); |
348 | EXPECT_EQ("nameX", Comps[0].TypedText); |
349 | EXPECT_EQ("String nameX", Comps[0].MatcherDecl); |
350 | |
351 | |
352 | Code = "cxxMethodDecl(hasName(nameX), "; |
353 | Comps = Parser::completeExpression(Code, Code.size(), nullptr, &NamedValues); |
354 | EXPECT_LT(0u, Comps.size()); |
355 | |
356 | |
357 | Code = "functionDecl(hasP"; |
358 | Comps = Parser::completeExpression(Code, Code.size(), nullptr, &NamedValues); |
359 | ASSERT_EQ(3u, Comps.size()); |
360 | |
361 | EXPECT_EQ("arameter(", Comps[0].TypedText); |
362 | EXPECT_EQ( |
363 | "Matcher<FunctionDecl> hasParameter(unsigned, Matcher<ParmVarDecl>)", |
364 | Comps[0].MatcherDecl); |
365 | |
366 | EXPECT_EQ("aramA", Comps[1].TypedText); |
367 | EXPECT_EQ("Matcher<Decl> hasParamA", Comps[1].MatcherDecl); |
368 | |
369 | EXPECT_EQ("arent(", Comps[2].TypedText); |
370 | EXPECT_EQ( |
371 | "Matcher<Decl> " |
372 | "hasParent(Matcher<NestedNameSpecifierLoc|TypeLoc|Decl|...>)", |
373 | Comps[2].MatcherDecl); |
374 | } |
375 | |
376 | TEST(ParserTest, ParseBindOnLet) { |
377 | |
378 | auto NamedValues = getTestNamedValues(); |
379 | |
380 | Diagnostics Error; |
381 | |
382 | { |
383 | llvm::Optional<DynTypedMatcher> TopLevelLetBinding( |
384 | Parser::parseMatcherExpression("hasParamA.bind(\"parmABinding\")", |
385 | nullptr, &NamedValues, &Error)); |
386 | EXPECT_EQ("", Error.toStringFull()); |
387 | auto M = TopLevelLetBinding->unconditionalConvertTo<Decl>(); |
388 | |
389 | EXPECT_TRUE(matchAndVerifyResultTrue( |
390 | "void foo(int a);", M, |
391 | llvm::make_unique<VerifyIdIsBoundTo<FunctionDecl>>("parmABinding"))); |
392 | EXPECT_TRUE(matchAndVerifyResultFalse( |
393 | "void foo(int b);", M, |
394 | llvm::make_unique<VerifyIdIsBoundTo<FunctionDecl>>("parmABinding"))); |
395 | } |
396 | |
397 | { |
398 | llvm::Optional<DynTypedMatcher> NestedLetBinding( |
399 | Parser::parseMatcherExpression( |
400 | "functionDecl(hasParamA.bind(\"parmABinding\"))", nullptr, |
401 | &NamedValues, &Error)); |
402 | EXPECT_EQ("", Error.toStringFull()); |
403 | auto M = NestedLetBinding->unconditionalConvertTo<Decl>(); |
404 | |
405 | EXPECT_TRUE(matchAndVerifyResultTrue( |
406 | "void foo(int a);", M, |
407 | llvm::make_unique<VerifyIdIsBoundTo<FunctionDecl>>("parmABinding"))); |
408 | EXPECT_TRUE(matchAndVerifyResultFalse( |
409 | "void foo(int b);", M, |
410 | llvm::make_unique<VerifyIdIsBoundTo<FunctionDecl>>("parmABinding"))); |
411 | } |
412 | } |
413 | |
414 | } |
415 | } |
416 | } |
417 | } |
418 | |