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: 20 QueryParserTest() : QS(llvm::ArrayRef<std::unique_ptr<ASTUnit>>()) {} 21 QueryRef parse(StringRef Code) { return QueryParser::parse(Code, QS); } 22 23 QuerySession QS; 24 }; 25 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 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 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 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 61 TEST_F(QueryParserTest, Set) { 62 QueryRef Q = parse("set"); 63 ASSERT_TRUE(isa<InvalidQuery>(Q)); 64 EXPECT_EQ("expected variable name", cast<InvalidQuery>(Q)->ErrStr); 65 66 Q = parse("set foo bar"); 67 ASSERT_TRUE(isa<InvalidQuery>(Q)); 68 EXPECT_EQ("unknown variable: 'foo'", cast<InvalidQuery>(Q)->ErrStr); 69 70 Q = parse("set output"); 71 ASSERT_TRUE(isa<InvalidQuery>(Q)); 72 EXPECT_EQ("expected 'diag', 'print', 'detailed-ast' or 'dump', got ''", 73 cast<InvalidQuery>(Q)->ErrStr); 74 75 Q = parse("set bind-root true foo"); 76 ASSERT_TRUE(isa<InvalidQuery>(Q)); 77 EXPECT_EQ("unexpected extra input: ' foo'", cast<InvalidQuery>(Q)->ErrStr); 78 79 Q = parse("set output foo"); 80 ASSERT_TRUE(isa<InvalidQuery>(Q)); 81 EXPECT_EQ("expected 'diag', 'print', 'detailed-ast' or 'dump', got 'foo'", 82 cast<InvalidQuery>(Q)->ErrStr); 83 84 Q = parse("set output dump"); 85 ASSERT_TRUE(isa<SetExclusiveOutputQuery >(Q)); 86 EXPECT_EQ(&QuerySession::DetailedASTOutput, cast<SetExclusiveOutputQuery>(Q)->Var); 87 88 Q = parse("set output detailed-ast"); 89 ASSERT_TRUE(isa<SetExclusiveOutputQuery>(Q)); 90 EXPECT_EQ(&QuerySession::DetailedASTOutput, cast<SetExclusiveOutputQuery>(Q)->Var); 91 92 Q = parse("enable output detailed-ast"); 93 ASSERT_TRUE(isa<EnableOutputQuery>(Q)); 94 EXPECT_EQ(&QuerySession::DetailedASTOutput, cast<EnableOutputQuery>(Q)->Var); 95 96 Q = parse("enable"); 97 ASSERT_TRUE(isa<InvalidQuery>(Q)); 98 EXPECT_EQ("expected variable name", cast<InvalidQuery>(Q)->ErrStr); 99 100 Q = parse("disable output detailed-ast"); 101 ASSERT_TRUE(isa<DisableOutputQuery>(Q)); 102 EXPECT_EQ(&QuerySession::DetailedASTOutput, cast<DisableOutputQuery>(Q)->Var); 103 104 Q = parse("set bind-root foo"); 105 ASSERT_TRUE(isa<InvalidQuery>(Q)); 106 EXPECT_EQ("expected 'true' or 'false', got 'foo'", 107 cast<InvalidQuery>(Q)->ErrStr); 108 109 Q = parse("set bind-root true"); 110 ASSERT_TRUE(isa<SetQuery<bool> >(Q)); 111 EXPECT_EQ(&QuerySession::BindRoot, cast<SetQuery<bool> >(Q)->Var); 112 EXPECT_EQ(true, cast<SetQuery<bool> >(Q)->Value); 113 } 114 115 TEST_F(QueryParserTest, Match) { 116 QueryRef Q = parse("match decl()"); 117 ASSERT_TRUE(isa<MatchQuery>(Q)); 118 EXPECT_TRUE(cast<MatchQuery>(Q)->Matcher.canConvertTo<Decl>()); 119 120 Q = parse("m stmt()"); 121 ASSERT_TRUE(isa<MatchQuery>(Q)); 122 EXPECT_TRUE(cast<MatchQuery>(Q)->Matcher.canConvertTo<Stmt>()); 123 } 124 125 TEST_F(QueryParserTest, LetUnlet) { 126 QueryRef Q = parse("let foo decl()"); 127 ASSERT_TRUE(isa<LetQuery>(Q)); 128 EXPECT_EQ("foo", cast<LetQuery>(Q)->Name); 129 EXPECT_TRUE(cast<LetQuery>(Q)->Value.isMatcher()); 130 EXPECT_TRUE(cast<LetQuery>(Q)->Value.getMatcher().hasTypedMatcher<Decl>()); 131 132 Q = parse("l foo decl()"); 133 ASSERT_TRUE(isa<LetQuery>(Q)); 134 EXPECT_EQ("foo", cast<LetQuery>(Q)->Name); 135 EXPECT_TRUE(cast<LetQuery>(Q)->Value.isMatcher()); 136 EXPECT_TRUE(cast<LetQuery>(Q)->Value.getMatcher().hasTypedMatcher<Decl>()); 137 138 Q = parse("let bar \"str\""); 139 ASSERT_TRUE(isa<LetQuery>(Q)); 140 EXPECT_EQ("bar", cast<LetQuery>(Q)->Name); 141 EXPECT_TRUE(cast<LetQuery>(Q)->Value.isString()); 142 EXPECT_EQ("str", cast<LetQuery>(Q)->Value.getString()); 143 144 Q = parse("let"); 145 ASSERT_TRUE(isa<InvalidQuery>(Q)); 146 EXPECT_EQ("expected variable name", cast<InvalidQuery>(Q)->ErrStr); 147 148 Q = parse("unlet x"); 149 ASSERT_TRUE(isa<LetQuery>(Q)); 150 EXPECT_EQ("x", cast<LetQuery>(Q)->Name); 151 EXPECT_FALSE(cast<LetQuery>(Q)->Value.hasValue()); 152 153 Q = parse("unlet"); 154 ASSERT_TRUE(isa<InvalidQuery>(Q)); 155 EXPECT_EQ("expected variable name", cast<InvalidQuery>(Q)->ErrStr); 156 157 Q = parse("unlet x bad_data"); 158 ASSERT_TRUE(isa<InvalidQuery>(Q)); 159 EXPECT_EQ("unexpected extra input: ' bad_data'", 160 cast<InvalidQuery>(Q)->ErrStr); 161 } 162 163 TEST_F(QueryParserTest, Comment) { 164 QueryRef Q = parse("# let foo decl()"); 165 ASSERT_TRUE(isa<NoOpQuery>(Q)); 166 167 Q = parse("let foo decl() # creates a decl() matcher called foo"); 168 ASSERT_TRUE(isa<LetQuery>(Q)); 169 170 Q = parse("set bind-root false # reduce noise"); 171 ASSERT_TRUE(isa<SetQuery<bool>>(Q)); 172 } 173 174 TEST_F(QueryParserTest, Complete) { 175 std::vector<llvm::LineEditor::Completion> Comps = 176 QueryParser::complete("", 0, QS); 177 ASSERT_EQ(8u, Comps.size()); 178 EXPECT_EQ("help ", Comps[0].TypedText); 179 EXPECT_EQ("help", Comps[0].DisplayText); 180 EXPECT_EQ("let ", Comps[1].TypedText); 181 EXPECT_EQ("let", Comps[1].DisplayText); 182 EXPECT_EQ("match ", Comps[2].TypedText); 183 EXPECT_EQ("match", Comps[2].DisplayText); 184 EXPECT_EQ("quit ", Comps[3].TypedText); 185 EXPECT_EQ("quit", Comps[3].DisplayText); 186 EXPECT_EQ("set ", Comps[4].TypedText); 187 EXPECT_EQ("set", Comps[4].DisplayText); 188 EXPECT_EQ("enable ", Comps[5].TypedText); 189 EXPECT_EQ("enable", Comps[5].DisplayText); 190 EXPECT_EQ("disable ", Comps[6].TypedText); 191 EXPECT_EQ("disable", Comps[6].DisplayText); 192 EXPECT_EQ("unlet ", Comps[7].TypedText); 193 EXPECT_EQ("unlet", Comps[7].DisplayText); 194 195 Comps = QueryParser::complete("set o", 5, QS); 196 ASSERT_EQ(1u, Comps.size()); 197 EXPECT_EQ("utput ", Comps[0].TypedText); 198 EXPECT_EQ("output", Comps[0].DisplayText); 199 200 Comps = QueryParser::complete("enable ", 7, QS); 201 ASSERT_EQ(1u, Comps.size()); 202 EXPECT_EQ("output ", Comps[0].TypedText); 203 EXPECT_EQ("output", Comps[0].DisplayText); 204 205 Comps = QueryParser::complete("enable output ", 14, QS); 206 ASSERT_EQ(4u, Comps.size()); 207 208 EXPECT_EQ("diag ", Comps[0].TypedText); 209 EXPECT_EQ("diag", Comps[0].DisplayText); 210 EXPECT_EQ("print ", Comps[1].TypedText); 211 EXPECT_EQ("print", Comps[1].DisplayText); 212 EXPECT_EQ("detailed-ast ", Comps[2].TypedText); 213 EXPECT_EQ("detailed-ast", Comps[2].DisplayText); 214 EXPECT_EQ("dump ", Comps[3].TypedText); 215 EXPECT_EQ("dump", Comps[3].DisplayText); 216 217 Comps = QueryParser::complete("match while", 11, QS); 218 ASSERT_EQ(1u, Comps.size()); 219 EXPECT_EQ("Stmt(", Comps[0].TypedText); 220 EXPECT_EQ("Matcher<Stmt> whileStmt(Matcher<WhileStmt>...)", 221 Comps[0].DisplayText); 222 223 Comps = QueryParser::complete("m", 1, QS); 224 ASSERT_EQ(1u, Comps.size()); 225 EXPECT_EQ("atch ", Comps[0].TypedText); 226 EXPECT_EQ("match", Comps[0].DisplayText); 227 228 Comps = QueryParser::complete("l", 1, QS); 229 ASSERT_EQ(1u, Comps.size()); 230 EXPECT_EQ("et ", Comps[0].TypedText); 231 EXPECT_EQ("let", Comps[0].DisplayText); 232 } 233 234 TEST_F(QueryParserTest, Multiline) { 235 236 // Single string with multiple commands 237 QueryRef Q = parse(R"matcher( 238 set bind-root false 239 set output dump 240 )matcher"); 241 242 ASSERT_TRUE(isa<SetQuery<bool>>(Q)); 243 244 Q = parse(Q->RemainingContent); 245 ASSERT_TRUE(isa<SetExclusiveOutputQuery>(Q)); 246 247 // Missing newline 248 Q = parse(R"matcher( 249 set bind-root false set output dump 250 )matcher"); 251 252 ASSERT_TRUE(isa<InvalidQuery>(Q)); 253 EXPECT_EQ("unexpected extra input: ' set output dump\n '", 254 cast<InvalidQuery>(Q)->ErrStr); 255 256 // Commands which do their own parsing 257 Q = parse(R"matcher( 258 let fn functionDecl(hasName("foo")) 259 match callExpr(callee(functionDecl())) 260 )matcher"); 261 262 ASSERT_TRUE(isa<LetQuery>(Q)); 263 264 Q = parse(Q->RemainingContent); 265 ASSERT_TRUE(isa<MatchQuery>(Q)); 266 267 // Multi-line matcher 268 Q = parse(R"matcher( 269 match callExpr(callee( 270 functionDecl().bind("fn") 271 )) 272 273 )matcher"); 274 275 ASSERT_TRUE(isa<MatchQuery>(Q)); 276 277 // Comment locations 278 Q = parse(R"matcher( 279 #nospacecomment 280 # Leading comment 281 match callExpr ( # Trailing comment 282 # Comment alone on line 283 284 callee( 285 functionDecl( 286 ).bind( 287 "fn" 288 ) 289 )) # Comment trailing close 290 # Comment after match 291 )matcher"); 292 293 ASSERT_TRUE(isa<MatchQuery>(Q)); 294 295 // \r\n 296 Q = parse("set bind-root false\r\nset output dump"); 297 298 ASSERT_TRUE(isa<SetQuery<bool>>(Q)); 299 300 Q = parse(Q->RemainingContent); 301 ASSERT_TRUE(isa<SetExclusiveOutputQuery>(Q)); 302 303 // Leading and trailing space in lines 304 Q = parse(" set bind-root false \r\n set output dump "); 305 306 ASSERT_TRUE(isa<SetQuery<bool>>(Q)); 307 308 Q = parse(Q->RemainingContent); 309 ASSERT_TRUE(isa<SetExclusiveOutputQuery>(Q)); 310 311 // Incomplete commands 312 Q = parse("set\nbind-root false"); 313 314 ASSERT_TRUE(isa<InvalidQuery>(Q)); 315 EXPECT_EQ("expected variable name", cast<InvalidQuery>(Q)->ErrStr); 316 317 Q = parse("set bind-root\nfalse"); 318 319 ASSERT_TRUE(isa<InvalidQuery>(Q)); 320 EXPECT_EQ("expected 'true' or 'false', got ''", 321 cast<InvalidQuery>(Q)->ErrStr); 322 323 Q = parse(R"matcher( 324 match callExpr 325 ( 326 ) 327 )matcher"); 328 329 ASSERT_TRUE(isa<InvalidQuery>(Q)); 330 EXPECT_EQ("1:9: Error parsing matcher. Found token <NewLine> " 331 "while looking for '('.", 332 cast<InvalidQuery>(Q)->ErrStr); 333 334 Q = parse("let someMatcher\nm parmVarDecl()"); 335 336 ASSERT_TRUE(isa<InvalidQuery>(Q)); 337 EXPECT_EQ("1:1: Invalid token <NewLine> found when looking for a value.", cast<InvalidQuery>(Q)->ErrStr); 338 339 Q = parse("\nm parmVarDecl()\nlet someMatcher\nm parmVarDecl()"); 340 341 ASSERT_TRUE(isa<MatchQuery>(Q)); 342 Q = parse(Q->RemainingContent); 343 344 ASSERT_TRUE(isa<InvalidQuery>(Q)); 345 EXPECT_EQ("1:1: Invalid token <NewLine> found when looking for a value.", cast<InvalidQuery>(Q)->ErrStr); 346 347 Q = parse("\nlet someMatcher\n"); 348 349 ASSERT_TRUE(isa<InvalidQuery>(Q)); 350 EXPECT_EQ("1:1: Invalid token <NewLine> found when looking for a value.", cast<InvalidQuery>(Q)->ErrStr); 351 352 Q = parse("\nm parmVarDecl()\nlet someMatcher\n"); 353 354 ASSERT_TRUE(isa<MatchQuery>(Q)); 355 Q = parse(Q->RemainingContent); 356 357 ASSERT_TRUE(isa<InvalidQuery>(Q)); 358 EXPECT_EQ("1:1: Invalid token <NewLine> found when looking for a value.", cast<InvalidQuery>(Q)->ErrStr); 359 360 Q = parse(R"matcher( 361 362 let Construct parmVarDecl() 363 364 m parmVarDecl( 365 Construct 366 ) 367 )matcher"); 368 369 ASSERT_TRUE(isa<LetQuery>(Q)); 370 { 371 llvm::raw_null_ostream NullOutStream; 372 dyn_cast<LetQuery>(Q)->run(NullOutStream, QS); 373 } 374 375 Q = parse(Q->RemainingContent); 376 377 ASSERT_TRUE(isa<MatchQuery>(Q)); 378 } 379