1 //===- unittest/Tooling/RangeSelectorTest.cpp -----------------------------===// 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 "clang/Tooling/Transformer/RangeSelector.h" 10 #include "clang/ASTMatchers/ASTMatchers.h" 11 #include "clang/Frontend/ASTUnit.h" 12 #include "clang/Tooling/Tooling.h" 13 #include "clang/Tooling/Transformer/SourceCode.h" 14 #include "llvm/Support/Error.h" 15 #include "llvm/Testing/Support/Error.h" 16 #include "gmock/gmock.h" 17 #include "gtest/gtest.h" 18 19 using namespace clang; 20 using namespace transformer; 21 using namespace ast_matchers; 22 23 namespace { 24 using ::llvm::Expected; 25 using ::llvm::Failed; 26 using ::llvm::HasValue; 27 using ::llvm::StringError; 28 using ::testing::AllOf; 29 using ::testing::HasSubstr; 30 using ::testing::Property; 31 32 using MatchResult = MatchFinder::MatchResult; 33 34 struct TestMatch { 35 // The AST unit from which `result` is built. We bundle it because it backs 36 // the result. Users are not expected to access it. 37 std::unique_ptr<clang::ASTUnit> ASTUnit; 38 // The result to use in the test. References `ast_unit`. 39 MatchResult Result; 40 }; 41 42 template <typename M> TestMatch matchCode(StringRef Code, M Matcher) { 43 auto ASTUnit = tooling::buildASTFromCode(Code); 44 assert(ASTUnit != nullptr && "AST construction failed"); 45 46 ASTContext &Context = ASTUnit->getASTContext(); 47 assert(!Context.getDiagnostics().hasErrorOccurred() && "Compilation error"); 48 49 auto Matches = ast_matchers::match(Matcher, Context); 50 // We expect a single, exact match. 51 assert(Matches.size() != 0 && "no matches found"); 52 assert(Matches.size() == 1 && "too many matches"); 53 54 return TestMatch{std::move(ASTUnit), MatchResult(Matches[0], &Context)}; 55 } 56 57 // Applies \p Selector to \p Match and, on success, returns the selected source. 58 Expected<StringRef> select(RangeSelector Selector, const TestMatch &Match) { 59 Expected<CharSourceRange> Range = Selector(Match.Result); 60 if (!Range) 61 return Range.takeError(); 62 return tooling::getText(*Range, *Match.Result.Context); 63 } 64 65 // Applies \p Selector to a trivial match with only a single bound node with id 66 // "bound_node_id". For use in testing unbound-node errors. 67 Expected<CharSourceRange> selectFromTrivial(const RangeSelector &Selector) { 68 // We need to bind the result to something, or the match will fail. Use a 69 // binding that is not used in the unbound node tests. 70 TestMatch Match = 71 matchCode("static int x = 0;", varDecl().bind("bound_node_id")); 72 return Selector(Match.Result); 73 } 74 75 // Matches the message expected for unbound-node failures. 76 testing::Matcher<StringError> withUnboundNodeMessage() { 77 return testing::Property( 78 &StringError::getMessage, 79 AllOf(HasSubstr("unbound_id"), HasSubstr("not bound"))); 80 } 81 82 // Applies \p Selector to code containing assorted node types, where the match 83 // binds each one: a statement ("stmt"), a (non-member) ctor-initializer 84 // ("init"), an expression ("expr") and a (nameless) declaration ("decl"). Used 85 // to test failures caused by applying selectors to nodes of the wrong type. 86 Expected<CharSourceRange> selectFromAssorted(RangeSelector Selector) { 87 StringRef Code = R"cc( 88 struct A {}; 89 class F : public A { 90 public: 91 F(int) {} 92 }; 93 void g() { F f(1); } 94 )cc"; 95 96 auto Matcher = 97 compoundStmt( 98 hasDescendant( 99 cxxConstructExpr( 100 hasDeclaration( 101 decl(hasDescendant(cxxCtorInitializer(isBaseInitializer()) 102 .bind("init"))) 103 .bind("decl"))) 104 .bind("expr"))) 105 .bind("stmt"); 106 107 return Selector(matchCode(Code, Matcher).Result); 108 } 109 110 // Matches the message expected for type-error failures. 111 testing::Matcher<StringError> withTypeErrorMessage(const std::string &NodeID) { 112 return testing::Property( 113 &StringError::getMessage, 114 AllOf(HasSubstr(NodeID), HasSubstr("mismatched type"))); 115 } 116 117 TEST(RangeSelectorTest, UnboundNode) { 118 EXPECT_THAT_EXPECTED(selectFromTrivial(node("unbound_id")), 119 Failed<StringError>(withUnboundNodeMessage())); 120 } 121 122 MATCHER_P(EqualsCharSourceRange, Range, "") { 123 return Range.getAsRange() == arg.getAsRange() && 124 Range.isTokenRange() == arg.isTokenRange(); 125 } 126 127 // FIXME: here and elsewhere: use llvm::Annotations library to explicitly mark 128 // points and ranges of interest, enabling more readable tests. 129 TEST(RangeSelectorTest, BeforeOp) { 130 StringRef Code = R"cc( 131 int f(int x, int y, int z) { return 3; } 132 int g() { return f(/* comment */ 3, 7 /* comment */, 9); } 133 )cc"; 134 const char *Call = "call"; 135 TestMatch Match = matchCode(Code, callExpr().bind(Call)); 136 const auto* E = Match.Result.Nodes.getNodeAs<Expr>(Call); 137 assert(E != nullptr); 138 auto ExprBegin = E->getSourceRange().getBegin(); 139 EXPECT_THAT_EXPECTED( 140 before(node(Call))(Match.Result), 141 HasValue(EqualsCharSourceRange( 142 CharSourceRange::getCharRange(ExprBegin, ExprBegin)))); 143 } 144 145 TEST(RangeSelectorTest, AfterOp) { 146 StringRef Code = R"cc( 147 int f(int x, int y, int z) { return 3; } 148 int g() { return f(/* comment */ 3, 7 /* comment */, 9); } 149 )cc"; 150 StringRef Call = "call"; 151 TestMatch Match = matchCode(Code, callExpr().bind(Call)); 152 const auto* E = Match.Result.Nodes.getNodeAs<Expr>(Call); 153 assert(E != nullptr); 154 const SourceRange Range = E->getSourceRange(); 155 // The end token, a right paren, is one character wide, so advance by one, 156 // bringing us to the semicolon. 157 const SourceLocation SemiLoc = Range.getEnd().getLocWithOffset(1); 158 const auto ExpectedAfter = CharSourceRange::getCharRange(SemiLoc, SemiLoc); 159 160 // Test with a char range. 161 auto CharRange = CharSourceRange::getCharRange(Range.getBegin(), SemiLoc); 162 EXPECT_THAT_EXPECTED(after(charRange(CharRange))(Match.Result), 163 HasValue(EqualsCharSourceRange(ExpectedAfter))); 164 165 // Test with a token range. 166 auto TokenRange = CharSourceRange::getTokenRange(Range); 167 EXPECT_THAT_EXPECTED(after(charRange(TokenRange))(Match.Result), 168 HasValue(EqualsCharSourceRange(ExpectedAfter))); 169 } 170 171 TEST(RangeSelectorTest, RangeOp) { 172 StringRef Code = R"cc( 173 int f(int x, int y, int z) { return 3; } 174 int g() { return f(/* comment */ 3, 7 /* comment */, 9); } 175 )cc"; 176 const char *Arg0 = "a0"; 177 const char *Arg1 = "a1"; 178 StringRef Call = "call"; 179 auto Matcher = callExpr(hasArgument(0, expr().bind(Arg0)), 180 hasArgument(1, expr().bind(Arg1))) 181 .bind(Call); 182 TestMatch Match = matchCode(Code, Matcher); 183 184 // Node-id specific version: 185 EXPECT_THAT_EXPECTED(select(range(Arg0, Arg1), Match), HasValue("3, 7")); 186 // General version: 187 EXPECT_THAT_EXPECTED(select(range(node(Arg0), node(Arg1)), Match), 188 HasValue("3, 7")); 189 } 190 191 TEST(RangeSelectorTest, NodeOpStatement) { 192 StringRef Code = "int f() { return 3; }"; 193 const char *ID = "id"; 194 TestMatch Match = matchCode(Code, returnStmt().bind(ID)); 195 EXPECT_THAT_EXPECTED(select(node(ID), Match), HasValue("return 3;")); 196 } 197 198 TEST(RangeSelectorTest, NodeOpExpression) { 199 StringRef Code = "int f() { return 3; }"; 200 const char *ID = "id"; 201 TestMatch Match = matchCode(Code, expr().bind(ID)); 202 EXPECT_THAT_EXPECTED(select(node(ID), Match), HasValue("3")); 203 } 204 205 TEST(RangeSelectorTest, StatementOp) { 206 StringRef Code = "int f() { return 3; }"; 207 const char *ID = "id"; 208 TestMatch Match = matchCode(Code, expr().bind(ID)); 209 EXPECT_THAT_EXPECTED(select(statement(ID), Match), HasValue("3;")); 210 } 211 212 TEST(RangeSelectorTest, MemberOp) { 213 StringRef Code = R"cc( 214 struct S { 215 int member; 216 }; 217 int g() { 218 S s; 219 return s.member; 220 } 221 )cc"; 222 const char *ID = "id"; 223 TestMatch Match = matchCode(Code, memberExpr().bind(ID)); 224 EXPECT_THAT_EXPECTED(select(member(ID), Match), HasValue("member")); 225 } 226 227 // Tests that member does not select any qualifiers on the member name. 228 TEST(RangeSelectorTest, MemberOpQualified) { 229 StringRef Code = R"cc( 230 struct S { 231 int member; 232 }; 233 struct T : public S { 234 int field; 235 }; 236 int g() { 237 T t; 238 return t.S::member; 239 } 240 )cc"; 241 const char *ID = "id"; 242 TestMatch Match = matchCode(Code, memberExpr().bind(ID)); 243 EXPECT_THAT_EXPECTED(select(member(ID), Match), HasValue("member")); 244 } 245 246 TEST(RangeSelectorTest, MemberOpTemplate) { 247 StringRef Code = R"cc( 248 struct S { 249 template <typename T> T foo(T t); 250 }; 251 int f(int x) { 252 S s; 253 return s.template foo<int>(3); 254 } 255 )cc"; 256 257 const char *ID = "id"; 258 TestMatch Match = matchCode(Code, memberExpr().bind(ID)); 259 EXPECT_THAT_EXPECTED(select(member(ID), Match), HasValue("foo")); 260 } 261 262 TEST(RangeSelectorTest, MemberOpOperator) { 263 StringRef Code = R"cc( 264 struct S { 265 int operator*(); 266 }; 267 int f(int x) { 268 S s; 269 return s.operator *(); 270 } 271 )cc"; 272 273 const char *ID = "id"; 274 TestMatch Match = matchCode(Code, memberExpr().bind(ID)); 275 EXPECT_THAT_EXPECTED(select(member(ID), Match), HasValue("operator *")); 276 } 277 278 TEST(RangeSelectorTest, NameOpNamedDecl) { 279 StringRef Code = R"cc( 280 int myfun() { 281 return 3; 282 } 283 )cc"; 284 const char *ID = "id"; 285 TestMatch Match = matchCode(Code, functionDecl().bind(ID)); 286 EXPECT_THAT_EXPECTED(select(name(ID), Match), HasValue("myfun")); 287 } 288 289 TEST(RangeSelectorTest, NameOpDeclRef) { 290 StringRef Code = R"cc( 291 int foo(int x) { 292 return x; 293 } 294 int g(int x) { return foo(x) * x; } 295 )cc"; 296 const char *Ref = "ref"; 297 TestMatch Match = matchCode(Code, declRefExpr(to(functionDecl())).bind(Ref)); 298 EXPECT_THAT_EXPECTED(select(name(Ref), Match), HasValue("foo")); 299 } 300 301 TEST(RangeSelectorTest, NameOpCtorInitializer) { 302 StringRef Code = R"cc( 303 class C { 304 public: 305 C() : field(3) {} 306 int field; 307 }; 308 )cc"; 309 const char *Init = "init"; 310 TestMatch Match = matchCode(Code, cxxCtorInitializer().bind(Init)); 311 EXPECT_THAT_EXPECTED(select(name(Init), Match), HasValue("field")); 312 } 313 314 TEST(RangeSelectorTest, NameOpErrors) { 315 EXPECT_THAT_EXPECTED(selectFromTrivial(name("unbound_id")), 316 Failed<StringError>(withUnboundNodeMessage())); 317 EXPECT_THAT_EXPECTED(selectFromAssorted(name("stmt")), 318 Failed<StringError>(withTypeErrorMessage("stmt"))); 319 } 320 321 TEST(RangeSelectorTest, NameOpDeclRefError) { 322 StringRef Code = R"cc( 323 struct S { 324 int operator*(); 325 }; 326 int f(int x) { 327 S s; 328 return *s + x; 329 } 330 )cc"; 331 const char *Ref = "ref"; 332 TestMatch Match = matchCode(Code, declRefExpr(to(functionDecl())).bind(Ref)); 333 EXPECT_THAT_EXPECTED( 334 name(Ref)(Match.Result), 335 Failed<StringError>(testing::Property( 336 &StringError::getMessage, 337 AllOf(HasSubstr(Ref), HasSubstr("requires property 'identifier'"))))); 338 } 339 340 TEST(RangeSelectorTest, CallArgsOp) { 341 const StringRef Code = R"cc( 342 struct C { 343 int bar(int, int); 344 }; 345 int f() { 346 C x; 347 return x.bar(3, 4); 348 } 349 )cc"; 350 const char *ID = "id"; 351 TestMatch Match = matchCode(Code, callExpr().bind(ID)); 352 EXPECT_THAT_EXPECTED(select(callArgs(ID), Match), HasValue("3, 4")); 353 } 354 355 TEST(RangeSelectorTest, CallArgsOpNoArgs) { 356 const StringRef Code = R"cc( 357 struct C { 358 int bar(); 359 }; 360 int f() { 361 C x; 362 return x.bar(); 363 } 364 )cc"; 365 const char *ID = "id"; 366 TestMatch Match = matchCode(Code, callExpr().bind(ID)); 367 EXPECT_THAT_EXPECTED(select(callArgs(ID), Match), HasValue("")); 368 } 369 370 TEST(RangeSelectorTest, CallArgsOpNoArgsWithComments) { 371 const StringRef Code = R"cc( 372 struct C { 373 int bar(); 374 }; 375 int f() { 376 C x; 377 return x.bar(/*empty*/); 378 } 379 )cc"; 380 const char *ID = "id"; 381 TestMatch Match = matchCode(Code, callExpr().bind(ID)); 382 EXPECT_THAT_EXPECTED(select(callArgs(ID), Match), HasValue("/*empty*/")); 383 } 384 385 // Tests that arguments are extracted correctly when a temporary (with parens) 386 // is used. 387 TEST(RangeSelectorTest, CallArgsOpWithParens) { 388 const StringRef Code = R"cc( 389 struct C { 390 int bar(int, int) { return 3; } 391 }; 392 int f() { 393 C x; 394 return C().bar(3, 4); 395 } 396 )cc"; 397 const char *ID = "id"; 398 TestMatch Match = 399 matchCode(Code, callExpr(callee(functionDecl(hasName("bar")))).bind(ID)); 400 EXPECT_THAT_EXPECTED(select(callArgs(ID), Match), HasValue("3, 4")); 401 } 402 403 TEST(RangeSelectorTest, CallArgsOpLeadingComments) { 404 const StringRef Code = R"cc( 405 struct C { 406 int bar(int, int) { return 3; } 407 }; 408 int f() { 409 C x; 410 return x.bar(/*leading*/ 3, 4); 411 } 412 )cc"; 413 const char *ID = "id"; 414 TestMatch Match = matchCode(Code, callExpr().bind(ID)); 415 EXPECT_THAT_EXPECTED(select(callArgs(ID), Match), 416 HasValue("/*leading*/ 3, 4")); 417 } 418 419 TEST(RangeSelectorTest, CallArgsOpTrailingComments) { 420 const StringRef Code = R"cc( 421 struct C { 422 int bar(int, int) { return 3; } 423 }; 424 int f() { 425 C x; 426 return x.bar(3 /*trailing*/, 4); 427 } 428 )cc"; 429 const char *ID = "id"; 430 TestMatch Match = matchCode(Code, callExpr().bind(ID)); 431 EXPECT_THAT_EXPECTED(select(callArgs(ID), Match), 432 HasValue("3 /*trailing*/, 4")); 433 } 434 435 TEST(RangeSelectorTest, CallArgsOpEolComments) { 436 const StringRef Code = R"cc( 437 struct C { 438 int bar(int, int) { return 3; } 439 }; 440 int f() { 441 C x; 442 return x.bar( // Header 443 1, // foo 444 2 // bar 445 ); 446 } 447 )cc"; 448 const char *ID = "id"; 449 TestMatch Match = matchCode(Code, callExpr().bind(ID)); 450 std::string ExpectedString = R"( // Header 451 1, // foo 452 2 // bar 453 )"; 454 EXPECT_THAT_EXPECTED(select(callArgs(ID), Match), HasValue(ExpectedString)); 455 } 456 457 TEST(RangeSelectorTest, CallArgsErrors) { 458 EXPECT_THAT_EXPECTED(selectFromTrivial(callArgs("unbound_id")), 459 Failed<StringError>(withUnboundNodeMessage())); 460 EXPECT_THAT_EXPECTED(selectFromAssorted(callArgs("stmt")), 461 Failed<StringError>(withTypeErrorMessage("stmt"))); 462 } 463 464 TEST(RangeSelectorTest, StatementsOp) { 465 StringRef Code = R"cc( 466 void g(); 467 void f() { /* comment */ g(); /* comment */ g(); /* comment */ } 468 )cc"; 469 const char *ID = "id"; 470 TestMatch Match = matchCode(Code, compoundStmt().bind(ID)); 471 EXPECT_THAT_EXPECTED( 472 select(statements(ID), Match), 473 HasValue(" /* comment */ g(); /* comment */ g(); /* comment */ ")); 474 } 475 476 TEST(RangeSelectorTest, StatementsOpEmptyList) { 477 StringRef Code = "void f() {}"; 478 const char *ID = "id"; 479 TestMatch Match = matchCode(Code, compoundStmt().bind(ID)); 480 EXPECT_THAT_EXPECTED(select(statements(ID), Match), HasValue("")); 481 } 482 483 TEST(RangeSelectorTest, StatementsOpErrors) { 484 EXPECT_THAT_EXPECTED(selectFromTrivial(statements("unbound_id")), 485 Failed<StringError>(withUnboundNodeMessage())); 486 EXPECT_THAT_EXPECTED(selectFromAssorted(statements("decl")), 487 Failed<StringError>(withTypeErrorMessage("decl"))); 488 } 489 490 TEST(RangeSelectorTest, ElementsOp) { 491 StringRef Code = R"cc( 492 void f() { 493 int v[] = {/* comment */ 3, /* comment*/ 4 /* comment */}; 494 (void)v; 495 } 496 )cc"; 497 const char *ID = "id"; 498 TestMatch Match = matchCode(Code, initListExpr().bind(ID)); 499 EXPECT_THAT_EXPECTED( 500 select(initListElements(ID), Match), 501 HasValue("/* comment */ 3, /* comment*/ 4 /* comment */")); 502 } 503 504 TEST(RangeSelectorTest, ElementsOpEmptyList) { 505 StringRef Code = R"cc( 506 void f() { 507 int v[] = {}; 508 (void)v; 509 } 510 )cc"; 511 const char *ID = "id"; 512 TestMatch Match = matchCode(Code, initListExpr().bind(ID)); 513 EXPECT_THAT_EXPECTED(select(initListElements(ID), Match), HasValue("")); 514 } 515 516 TEST(RangeSelectorTest, ElementsOpErrors) { 517 EXPECT_THAT_EXPECTED(selectFromTrivial(initListElements("unbound_id")), 518 Failed<StringError>(withUnboundNodeMessage())); 519 EXPECT_THAT_EXPECTED(selectFromAssorted(initListElements("stmt")), 520 Failed<StringError>(withTypeErrorMessage("stmt"))); 521 } 522 523 TEST(RangeSelectorTest, ElseBranchOpSingleStatement) { 524 StringRef Code = R"cc( 525 int f() { 526 int x = 0; 527 if (true) x = 3; 528 else x = 4; 529 return x + 5; 530 } 531 )cc"; 532 const char *ID = "id"; 533 TestMatch Match = matchCode(Code, ifStmt().bind(ID)); 534 EXPECT_THAT_EXPECTED(select(elseBranch(ID), Match), HasValue("else x = 4;")); 535 } 536 537 TEST(RangeSelectorTest, ElseBranchOpCompoundStatement) { 538 StringRef Code = R"cc( 539 int f() { 540 int x = 0; 541 if (true) x = 3; 542 else { x = 4; } 543 return x + 5; 544 } 545 )cc"; 546 const char *ID = "id"; 547 TestMatch Match = matchCode(Code, ifStmt().bind(ID)); 548 EXPECT_THAT_EXPECTED(select(elseBranch(ID), Match), 549 HasValue("else { x = 4; }")); 550 } 551 552 // Tests case where the matched node is the complete expanded text. 553 TEST(RangeSelectorTest, ExpansionOp) { 554 StringRef Code = R"cc( 555 #define BADDECL(E) int bad(int x) { return E; } 556 BADDECL(x * x) 557 )cc"; 558 559 const char *Fun = "Fun"; 560 TestMatch Match = matchCode(Code, functionDecl(hasName("bad")).bind(Fun)); 561 EXPECT_THAT_EXPECTED(select(expansion(node(Fun)), Match), 562 HasValue("BADDECL(x * x)")); 563 } 564 565 // Tests case where the matched node is (only) part of the expanded text. 566 TEST(RangeSelectorTest, ExpansionOpPartial) { 567 StringRef Code = R"cc( 568 #define BADDECL(E) int bad(int x) { return E; } 569 BADDECL(x * x) 570 )cc"; 571 572 const char *Ret = "Ret"; 573 TestMatch Match = matchCode(Code, returnStmt().bind(Ret)); 574 EXPECT_THAT_EXPECTED(select(expansion(node(Ret)), Match), 575 HasValue("BADDECL(x * x)")); 576 } 577 578 TEST(RangeSelectorTest, IfBoundOpBound) { 579 StringRef Code = R"cc( 580 int f() { 581 return 3 + 5; 582 } 583 )cc"; 584 const char *ID = "id", *Op = "op"; 585 TestMatch Match = 586 matchCode(Code, binaryOperator(hasLHS(expr().bind(ID))).bind(Op)); 587 EXPECT_THAT_EXPECTED(select(ifBound(ID, node(ID), node(Op)), Match), 588 HasValue("3")); 589 } 590 591 TEST(RangeSelectorTest, IfBoundOpUnbound) { 592 StringRef Code = R"cc( 593 int f() { 594 return 3 + 5; 595 } 596 )cc"; 597 const char *ID = "id", *Op = "op"; 598 TestMatch Match = matchCode(Code, binaryOperator().bind(Op)); 599 EXPECT_THAT_EXPECTED(select(ifBound(ID, node(ID), node(Op)), Match), 600 HasValue("3 + 5")); 601 } 602 603 } // namespace 604