xref: /llvm-project/clang-tools-extra/unittests/clang-query/QueryParserTest.cpp (revision 371eccd5dfed88c8e76449233d8388c12be3464b)
1 //===---- QueryParserTest.cpp - clang-query test --------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "QueryParser.h"
10 #include "Query.h"
11 #include "QuerySession.h"
12 #include "llvm/LineEditor/LineEditor.h"
13 #include "gtest/gtest.h"
14 
15 using namespace clang;
16 using namespace clang::query;
17 
18 class QueryParserTest : public ::testing::Test {
19 protected:
QueryParserTest()20   QueryParserTest() : QS(llvm::ArrayRef<std::unique_ptr<ASTUnit>>()) {}
parse(StringRef Code)21   QueryRef parse(StringRef Code) { return QueryParser::parse(Code, QS); }
22 
23   QuerySession QS;
24 };
25 
TEST_F(QueryParserTest,NoOp)26 TEST_F(QueryParserTest, NoOp) {
27   QueryRef Q = parse("");
28   EXPECT_TRUE(isa<NoOpQuery>(Q));
29 
30   Q = parse("\n");
31   EXPECT_TRUE(isa<NoOpQuery>(Q));
32 }
33 
TEST_F(QueryParserTest,Invalid)34 TEST_F(QueryParserTest, Invalid) {
35   QueryRef Q = parse("foo");
36   ASSERT_TRUE(isa<InvalidQuery>(Q));
37   EXPECT_EQ("unknown command: foo", cast<InvalidQuery>(Q)->ErrStr);
38 }
39 
TEST_F(QueryParserTest,Help)40 TEST_F(QueryParserTest, Help) {
41   QueryRef Q = parse("help");
42   ASSERT_TRUE(isa<HelpQuery>(Q));
43 
44   Q = parse("help me");
45   ASSERT_TRUE(isa<InvalidQuery>(Q));
46   EXPECT_EQ("unexpected extra input: ' me'", cast<InvalidQuery>(Q)->ErrStr);
47 }
48 
TEST_F(QueryParserTest,Quit)49 TEST_F(QueryParserTest, Quit) {
50   QueryRef Q = parse("quit");
51   ASSERT_TRUE(isa<QuitQuery>(Q));
52 
53   Q = parse("q");
54   ASSERT_TRUE(isa<QuitQuery>(Q));
55 
56   Q = parse("quit me");
57   ASSERT_TRUE(isa<InvalidQuery>(Q));
58   EXPECT_EQ("unexpected extra input: ' me'", cast<InvalidQuery>(Q)->ErrStr);
59 }
60 
TEST_F(QueryParserTest,Set)61 TEST_F(QueryParserTest, Set) {
62 
63   QueryRef Q = parse("set");
64   ASSERT_TRUE(isa<InvalidQuery>(Q));
65   EXPECT_EQ("expected variable name", cast<InvalidQuery>(Q)->ErrStr);
66 
67   Q = parse("set foo bar");
68   ASSERT_TRUE(isa<InvalidQuery>(Q));
69   EXPECT_EQ("unknown variable: 'foo'", cast<InvalidQuery>(Q)->ErrStr);
70 
71   Q = parse("set output");
72   ASSERT_TRUE(isa<InvalidQuery>(Q));
73   EXPECT_EQ("expected 'diag', 'print', 'detailed-ast' or 'dump', got ''",
74             cast<InvalidQuery>(Q)->ErrStr);
75 
76   Q = parse("set bind-root true foo");
77   ASSERT_TRUE(isa<InvalidQuery>(Q));
78   EXPECT_EQ("unexpected extra input: ' foo'", cast<InvalidQuery>(Q)->ErrStr);
79 
80   Q = parse("set output foo");
81   ASSERT_TRUE(isa<InvalidQuery>(Q));
82   EXPECT_EQ("expected 'diag', 'print', 'detailed-ast' or 'dump', got 'foo'",
83             cast<InvalidQuery>(Q)->ErrStr);
84 
85   Q = parse("set output dump");
86   ASSERT_TRUE(isa<SetExclusiveOutputQuery >(Q));
87   EXPECT_EQ(&QuerySession::DetailedASTOutput, cast<SetExclusiveOutputQuery>(Q)->Var);
88 
89   Q = parse("set output detailed-ast");
90   ASSERT_TRUE(isa<SetExclusiveOutputQuery>(Q));
91   EXPECT_EQ(&QuerySession::DetailedASTOutput, cast<SetExclusiveOutputQuery>(Q)->Var);
92 
93   Q = parse("enable output detailed-ast");
94   ASSERT_TRUE(isa<EnableOutputQuery>(Q));
95   EXPECT_EQ(&QuerySession::DetailedASTOutput, cast<EnableOutputQuery>(Q)->Var);
96 
97   Q = parse("enable");
98   ASSERT_TRUE(isa<InvalidQuery>(Q));
99   EXPECT_EQ("expected variable name", cast<InvalidQuery>(Q)->ErrStr);
100 
101   Q = parse("disable output detailed-ast");
102   ASSERT_TRUE(isa<DisableOutputQuery>(Q));
103   EXPECT_EQ(&QuerySession::DetailedASTOutput, cast<DisableOutputQuery>(Q)->Var);
104 
105   Q = parse("set bind-root foo");
106   ASSERT_TRUE(isa<InvalidQuery>(Q));
107   EXPECT_EQ("expected 'true' or 'false', got 'foo'",
108             cast<InvalidQuery>(Q)->ErrStr);
109 
110   Q = parse("set bind-root true");
111   ASSERT_TRUE(isa<SetQuery<bool> >(Q));
112   EXPECT_EQ(&QuerySession::BindRoot, cast<SetQuery<bool> >(Q)->Var);
113   EXPECT_EQ(true, cast<SetQuery<bool> >(Q)->Value);
114 
115   Q = parse("set traversal AsIs");
116   ASSERT_TRUE(isa<SetQuery<TraversalKind>>(Q));
117   EXPECT_EQ(&QuerySession::TK, cast<SetQuery<TraversalKind>>(Q)->Var);
118   EXPECT_EQ(TK_AsIs, cast<SetQuery<TraversalKind>>(Q)->Value);
119 
120   Q = parse("set traversal NotATraversal");
121   ASSERT_TRUE(isa<InvalidQuery>(Q));
122   EXPECT_EQ("expected traversal kind, got 'NotATraversal'",
123             cast<InvalidQuery>(Q)->ErrStr);
124 }
125 
TEST_F(QueryParserTest,Match)126 TEST_F(QueryParserTest, Match) {
127   QueryRef Q = parse("match decl()");
128   ASSERT_TRUE(isa<MatchQuery>(Q));
129   EXPECT_TRUE(cast<MatchQuery>(Q)->Matcher.canConvertTo<Decl>());
130 
131   Q = parse("m stmt()");
132   ASSERT_TRUE(isa<MatchQuery>(Q));
133   EXPECT_TRUE(cast<MatchQuery>(Q)->Matcher.canConvertTo<Stmt>());
134 }
135 
TEST_F(QueryParserTest,LetUnlet)136 TEST_F(QueryParserTest, LetUnlet) {
137   QueryRef Q = parse("let foo decl()");
138   ASSERT_TRUE(isa<LetQuery>(Q));
139   EXPECT_EQ("foo", cast<LetQuery>(Q)->Name);
140   EXPECT_TRUE(cast<LetQuery>(Q)->Value.isMatcher());
141   EXPECT_TRUE(cast<LetQuery>(Q)->Value.getMatcher().hasTypedMatcher<Decl>());
142 
143   Q = parse("l foo decl()");
144   ASSERT_TRUE(isa<LetQuery>(Q));
145   EXPECT_EQ("foo", cast<LetQuery>(Q)->Name);
146   EXPECT_TRUE(cast<LetQuery>(Q)->Value.isMatcher());
147   EXPECT_TRUE(cast<LetQuery>(Q)->Value.getMatcher().hasTypedMatcher<Decl>());
148 
149   Q = parse("let bar \"str\"");
150   ASSERT_TRUE(isa<LetQuery>(Q));
151   EXPECT_EQ("bar", cast<LetQuery>(Q)->Name);
152   EXPECT_TRUE(cast<LetQuery>(Q)->Value.isString());
153   EXPECT_EQ("str", cast<LetQuery>(Q)->Value.getString());
154 
155   Q = parse("let");
156   ASSERT_TRUE(isa<InvalidQuery>(Q));
157   EXPECT_EQ("expected variable name", cast<InvalidQuery>(Q)->ErrStr);
158 
159   Q = parse("unlet x");
160   ASSERT_TRUE(isa<LetQuery>(Q));
161   EXPECT_EQ("x", cast<LetQuery>(Q)->Name);
162   EXPECT_FALSE(cast<LetQuery>(Q)->Value.hasValue());
163 
164   Q = parse("unlet");
165   ASSERT_TRUE(isa<InvalidQuery>(Q));
166   EXPECT_EQ("expected variable name", cast<InvalidQuery>(Q)->ErrStr);
167 
168   Q = parse("unlet x bad_data");
169   ASSERT_TRUE(isa<InvalidQuery>(Q));
170   EXPECT_EQ("unexpected extra input: ' bad_data'",
171             cast<InvalidQuery>(Q)->ErrStr);
172 }
173 
TEST_F(QueryParserTest,Comment)174 TEST_F(QueryParserTest, Comment) {
175   QueryRef Q = parse("# let foo decl()");
176   ASSERT_TRUE(isa<NoOpQuery>(Q));
177 
178   Q = parse("let foo decl() # creates a decl() matcher called foo");
179   ASSERT_TRUE(isa<LetQuery>(Q));
180 
181   Q = parse("set bind-root false # reduce noise");
182   ASSERT_TRUE(isa<SetQuery<bool>>(Q));
183 }
184 
TEST_F(QueryParserTest,Complete)185 TEST_F(QueryParserTest, Complete) {
186   std::vector<llvm::LineEditor::Completion> Comps =
187       QueryParser::complete("", 0, QS);
188   ASSERT_EQ(9u, Comps.size());
189   EXPECT_EQ("help ", Comps[0].TypedText);
190   EXPECT_EQ("help", Comps[0].DisplayText);
191   EXPECT_EQ("let ", Comps[1].TypedText);
192   EXPECT_EQ("let", Comps[1].DisplayText);
193   EXPECT_EQ("match ", Comps[2].TypedText);
194   EXPECT_EQ("match", Comps[2].DisplayText);
195   EXPECT_EQ("quit ", Comps[3].TypedText);
196   EXPECT_EQ("quit", Comps[3].DisplayText);
197   EXPECT_EQ("set ", Comps[4].TypedText);
198   EXPECT_EQ("set", Comps[4].DisplayText);
199   EXPECT_EQ("enable ", Comps[5].TypedText);
200   EXPECT_EQ("enable", Comps[5].DisplayText);
201   EXPECT_EQ("disable ", Comps[6].TypedText);
202   EXPECT_EQ("disable", Comps[6].DisplayText);
203   EXPECT_EQ("unlet ", Comps[7].TypedText);
204   EXPECT_EQ("unlet", Comps[7].DisplayText);
205   EXPECT_EQ("file ", Comps[8].TypedText);
206   EXPECT_EQ("file", Comps[8].DisplayText);
207 
208   Comps = QueryParser::complete("set o", 5, QS);
209   ASSERT_EQ(1u, Comps.size());
210   EXPECT_EQ("utput ", Comps[0].TypedText);
211   EXPECT_EQ("output", Comps[0].DisplayText);
212 
213   Comps = QueryParser::complete("set t", 5, QS);
214   ASSERT_EQ(1u, Comps.size());
215   EXPECT_EQ("raversal ", Comps[0].TypedText);
216   EXPECT_EQ("traversal", Comps[0].DisplayText);
217 
218   Comps = QueryParser::complete("enable ", 7, QS);
219   ASSERT_EQ(1u, Comps.size());
220   EXPECT_EQ("output ", Comps[0].TypedText);
221   EXPECT_EQ("output", Comps[0].DisplayText);
222 
223   Comps = QueryParser::complete("enable output ", 14, QS);
224   ASSERT_EQ(4u, Comps.size());
225 
226   EXPECT_EQ("diag ", Comps[0].TypedText);
227   EXPECT_EQ("diag", Comps[0].DisplayText);
228   EXPECT_EQ("print ", Comps[1].TypedText);
229   EXPECT_EQ("print", Comps[1].DisplayText);
230   EXPECT_EQ("detailed-ast ", Comps[2].TypedText);
231   EXPECT_EQ("detailed-ast", Comps[2].DisplayText);
232   EXPECT_EQ("dump ", Comps[3].TypedText);
233   EXPECT_EQ("dump", Comps[3].DisplayText);
234 
235   Comps = QueryParser::complete("set traversal ", 14, QS);
236   ASSERT_EQ(2u, Comps.size());
237 
238   EXPECT_EQ("AsIs ", Comps[0].TypedText);
239   EXPECT_EQ("AsIs", Comps[0].DisplayText);
240   EXPECT_EQ("IgnoreUnlessSpelledInSource ", Comps[1].TypedText);
241   EXPECT_EQ("IgnoreUnlessSpelledInSource", Comps[1].DisplayText);
242 
243   Comps = QueryParser::complete("match while", 11, QS);
244   ASSERT_EQ(1u, Comps.size());
245   EXPECT_EQ("Stmt(", Comps[0].TypedText);
246   EXPECT_EQ("Matcher<Stmt> whileStmt(Matcher<WhileStmt>...)",
247             Comps[0].DisplayText);
248 
249   Comps = QueryParser::complete("m", 1, QS);
250   ASSERT_EQ(1u, Comps.size());
251   EXPECT_EQ("atch ", Comps[0].TypedText);
252   EXPECT_EQ("match", Comps[0].DisplayText);
253 
254   Comps = QueryParser::complete("l", 1, QS);
255   ASSERT_EQ(1u, Comps.size());
256   EXPECT_EQ("et ", Comps[0].TypedText);
257   EXPECT_EQ("let", Comps[0].DisplayText);
258 }
259 
TEST_F(QueryParserTest,Multiline)260 TEST_F(QueryParserTest, Multiline) {
261 
262   // Single string with multiple commands
263   QueryRef Q = parse(R"matcher(
264 set bind-root false
265 set output dump
266     )matcher");
267 
268   ASSERT_TRUE(isa<SetQuery<bool>>(Q));
269 
270   Q = parse(Q->RemainingContent);
271   ASSERT_TRUE(isa<SetExclusiveOutputQuery>(Q));
272 
273   // Missing newline
274   Q = parse(R"matcher(
275 set bind-root false set output dump
276     )matcher");
277 
278   ASSERT_TRUE(isa<InvalidQuery>(Q));
279   EXPECT_EQ("unexpected extra input: ' set output dump\n    '",
280             cast<InvalidQuery>(Q)->ErrStr);
281 
282   // Commands which do their own parsing
283   Q = parse(R"matcher(
284 let fn functionDecl(hasName("foo"))
285 match callExpr(callee(functionDecl()))
286     )matcher");
287 
288   ASSERT_TRUE(isa<LetQuery>(Q));
289 
290   Q = parse(Q->RemainingContent);
291   ASSERT_TRUE(isa<MatchQuery>(Q));
292 
293   // Multi-line matcher
294   Q = parse(R"matcher(
295 match callExpr(callee(
296     functionDecl().bind("fn")
297     ))
298 
299     )matcher");
300 
301   ASSERT_TRUE(isa<MatchQuery>(Q));
302 
303   // Comment locations
304   Q = parse(R"matcher(
305 #nospacecomment
306 # Leading comment
307 match callExpr ( # Trailing comment
308             # Comment alone on line
309 
310             callee(
311             functionDecl(
312             ).bind(
313             "fn"
314             )
315             )) # Comment trailing close
316 # Comment after match
317     )matcher");
318 
319   ASSERT_TRUE(isa<MatchQuery>(Q));
320 
321   // \r\n
322   Q = parse("set bind-root false\r\nset output dump");
323 
324   ASSERT_TRUE(isa<SetQuery<bool>>(Q));
325 
326   Q = parse(Q->RemainingContent);
327   ASSERT_TRUE(isa<SetExclusiveOutputQuery>(Q));
328 
329   // Leading and trailing space in lines
330   Q = parse("  set bind-root false  \r\n  set output dump  ");
331 
332   ASSERT_TRUE(isa<SetQuery<bool>>(Q));
333 
334   Q = parse(Q->RemainingContent);
335   ASSERT_TRUE(isa<SetExclusiveOutputQuery>(Q));
336 
337   // Incomplete commands
338   Q = parse("set\nbind-root false");
339 
340   ASSERT_TRUE(isa<InvalidQuery>(Q));
341   EXPECT_EQ("expected variable name", cast<InvalidQuery>(Q)->ErrStr);
342 
343   Q = parse("set bind-root\nfalse");
344 
345   ASSERT_TRUE(isa<InvalidQuery>(Q));
346   EXPECT_EQ("expected 'true' or 'false', got ''",
347             cast<InvalidQuery>(Q)->ErrStr);
348 
349   Q = parse(R"matcher(
350 match callExpr
351 (
352 )
353     )matcher");
354 
355   ASSERT_TRUE(isa<InvalidQuery>(Q));
356   EXPECT_EQ("1:9: Error parsing matcher. Found token <NewLine> "
357             "while looking for '('.",
358             cast<InvalidQuery>(Q)->ErrStr);
359 
360   Q = parse("let someMatcher\nm parmVarDecl()");
361 
362   ASSERT_TRUE(isa<InvalidQuery>(Q));
363   EXPECT_EQ("1:1: Invalid token <NewLine> found when looking for a value.",
364             cast<InvalidQuery>(Q)->ErrStr);
365 
366   Q = parse("\nm parmVarDecl()\nlet someMatcher\nm parmVarDecl()");
367 
368   ASSERT_TRUE(isa<MatchQuery>(Q));
369   Q = parse(Q->RemainingContent);
370 
371   ASSERT_TRUE(isa<InvalidQuery>(Q));
372   EXPECT_EQ("1:1: Invalid token <NewLine> found when looking for a value.",
373             cast<InvalidQuery>(Q)->ErrStr);
374 
375   Q = parse("\nlet someMatcher\n");
376 
377   ASSERT_TRUE(isa<InvalidQuery>(Q));
378   EXPECT_EQ("1:1: Invalid token <NewLine> found when looking for a value.",
379             cast<InvalidQuery>(Q)->ErrStr);
380 
381   Q = parse("\nm parmVarDecl()\nlet someMatcher\n");
382 
383   ASSERT_TRUE(isa<MatchQuery>(Q));
384   Q = parse(Q->RemainingContent);
385 
386   ASSERT_TRUE(isa<InvalidQuery>(Q));
387   EXPECT_EQ("1:1: Invalid token <NewLine> found when looking for a value.",
388             cast<InvalidQuery>(Q)->ErrStr);
389 
390   Q = parse(R"matcher(
391 
392 let Construct parmVarDecl()
393 
394 m parmVarDecl(
395     Construct
396 )
397 )matcher");
398 
399   ASSERT_TRUE(isa<LetQuery>(Q));
400   {
401     llvm::raw_null_ostream NullOutStream;
402     dyn_cast<LetQuery>(Q)->run(NullOutStream, QS);
403   }
404 
405   Q = parse(Q->RemainingContent);
406 
407   ASSERT_TRUE(isa<MatchQuery>(Q));
408 }
409