1 //===- unittest/Tooling/TransformerTest.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/Transformer.h" 10 #include "clang/ASTMatchers/ASTMatchers.h" 11 #include "clang/Tooling/Tooling.h" 12 #include "clang/Tooling/Transformer/RangeSelector.h" 13 #include "clang/Tooling/Transformer/RewriteRule.h" 14 #include "clang/Tooling/Transformer/Stencil.h" 15 #include "llvm/Support/Errc.h" 16 #include "llvm/Support/Error.h" 17 #include "gmock/gmock.h" 18 #include "gtest/gtest.h" 19 20 using namespace clang; 21 using namespace tooling; 22 using namespace ast_matchers; 23 namespace { 24 using ::testing::ElementsAre; 25 using ::testing::IsEmpty; 26 using transformer::cat; 27 using transformer::changeTo; 28 using transformer::RewriteRule; 29 30 constexpr char KHeaderContents[] = R"cc( 31 struct string { 32 string(const char*); 33 char* c_str(); 34 int size(); 35 }; 36 int strlen(const char*); 37 38 namespace proto { 39 struct PCFProto { 40 int foo(); 41 }; 42 struct ProtoCommandLineFlag : PCFProto { 43 PCFProto& GetProto(); 44 }; 45 } // namespace proto 46 class Logger {}; 47 void operator<<(Logger& l, string msg); 48 Logger& log(int level); 49 )cc"; 50 51 static ast_matchers::internal::Matcher<clang::QualType> 52 isOrPointsTo(const clang::ast_matchers::DeclarationMatcher &TypeMatcher) { 53 return anyOf(hasDeclaration(TypeMatcher), pointsTo(TypeMatcher)); 54 } 55 56 static std::string format(StringRef Code) { 57 const std::vector<Range> Ranges(1, Range(0, Code.size())); 58 auto Style = format::getLLVMStyle(); 59 const auto Replacements = format::reformat(Style, Code, Ranges); 60 auto Formatted = applyAllReplacements(Code, Replacements); 61 if (!Formatted) { 62 ADD_FAILURE() << "Could not format code: " 63 << llvm::toString(Formatted.takeError()); 64 return std::string(); 65 } 66 return *Formatted; 67 } 68 69 static void compareSnippets(StringRef Expected, 70 const llvm::Optional<std::string> &MaybeActual) { 71 ASSERT_TRUE(MaybeActual) << "Rewrite failed. Expecting: " << Expected; 72 auto Actual = *MaybeActual; 73 std::string HL = "#include \"header.h\"\n"; 74 auto I = Actual.find(HL); 75 if (I != std::string::npos) 76 Actual.erase(I, HL.size()); 77 EXPECT_EQ(format(Expected), format(Actual)); 78 } 79 80 // FIXME: consider separating this class into its own file(s). 81 class ClangRefactoringTestBase : public testing::Test { 82 protected: 83 void appendToHeader(StringRef S) { FileContents[0].second += S; } 84 85 void addFile(StringRef Filename, StringRef Content) { 86 FileContents.emplace_back(std::string(Filename), std::string(Content)); 87 } 88 89 llvm::Optional<std::string> rewrite(StringRef Input) { 90 std::string Code = ("#include \"header.h\"\n" + Input).str(); 91 auto Factory = newFrontendActionFactory(&MatchFinder); 92 if (!runToolOnCodeWithArgs( 93 Factory->create(), Code, std::vector<std::string>(), "input.cc", 94 "clang-tool", std::make_shared<PCHContainerOperations>(), 95 FileContents)) { 96 llvm::errs() << "Running tool failed.\n"; 97 return None; 98 } 99 if (ErrorCount != 0) { 100 llvm::errs() << "Generating changes failed.\n"; 101 return None; 102 } 103 auto ChangedCode = 104 applyAtomicChanges("input.cc", Code, Changes, ApplyChangesSpec()); 105 if (!ChangedCode) { 106 llvm::errs() << "Applying changes failed: " 107 << llvm::toString(ChangedCode.takeError()) << "\n"; 108 return None; 109 } 110 return *ChangedCode; 111 } 112 113 Transformer::ChangeConsumer consumer() { 114 return [this](Expected<AtomicChange> C) { 115 if (C) { 116 Changes.push_back(std::move(*C)); 117 } else { 118 // FIXME: stash this error rather then printing. 119 llvm::errs() << "Error generating changes: " 120 << llvm::toString(C.takeError()) << "\n"; 121 ++ErrorCount; 122 } 123 }; 124 } 125 126 template <typename R> 127 void testRule(R Rule, StringRef Input, StringRef Expected) { 128 Transformer T(std::move(Rule), consumer()); 129 T.registerMatchers(&MatchFinder); 130 compareSnippets(Expected, rewrite(Input)); 131 } 132 133 clang::ast_matchers::MatchFinder MatchFinder; 134 // Records whether any errors occurred in individual changes. 135 int ErrorCount = 0; 136 AtomicChanges Changes; 137 138 private: 139 FileContentMappings FileContents = {{"header.h", ""}}; 140 }; 141 142 class TransformerTest : public ClangRefactoringTestBase { 143 protected: 144 TransformerTest() { appendToHeader(KHeaderContents); } 145 }; 146 147 // Given string s, change strlen($s.c_str()) to REPLACED. 148 static RewriteRule ruleStrlenSize() { 149 StringRef StringExpr = "strexpr"; 150 auto StringType = namedDecl(hasAnyName("::basic_string", "::string")); 151 auto R = makeRule( 152 callExpr(callee(functionDecl(hasName("strlen"))), 153 hasArgument(0, cxxMemberCallExpr( 154 on(expr(hasType(isOrPointsTo(StringType))) 155 .bind(StringExpr)), 156 callee(cxxMethodDecl(hasName("c_str")))))), 157 changeTo(cat("REPLACED")), cat("Use size() method directly on string.")); 158 return R; 159 } 160 161 TEST_F(TransformerTest, StrlenSize) { 162 std::string Input = "int f(string s) { return strlen(s.c_str()); }"; 163 std::string Expected = "int f(string s) { return REPLACED; }"; 164 testRule(ruleStrlenSize(), Input, Expected); 165 } 166 167 // Tests that no change is applied when a match is not expected. 168 TEST_F(TransformerTest, NoMatch) { 169 std::string Input = "int f(string s) { return s.size(); }"; 170 testRule(ruleStrlenSize(), Input, Input); 171 } 172 173 // Tests replacing an expression. 174 TEST_F(TransformerTest, Flag) { 175 StringRef Flag = "flag"; 176 RewriteRule Rule = makeRule( 177 cxxMemberCallExpr(on(expr(hasType(cxxRecordDecl( 178 hasName("proto::ProtoCommandLineFlag")))) 179 .bind(Flag)), 180 unless(callee(cxxMethodDecl(hasName("GetProto"))))), 181 changeTo(node(std::string(Flag)), cat("EXPR"))); 182 183 std::string Input = R"cc( 184 proto::ProtoCommandLineFlag flag; 185 int x = flag.foo(); 186 int y = flag.GetProto().foo(); 187 )cc"; 188 std::string Expected = R"cc( 189 proto::ProtoCommandLineFlag flag; 190 int x = EXPR.foo(); 191 int y = flag.GetProto().foo(); 192 )cc"; 193 194 testRule(std::move(Rule), Input, Expected); 195 } 196 197 TEST_F(TransformerTest, AddIncludeQuoted) { 198 RewriteRule Rule = 199 makeRule(callExpr(callee(functionDecl(hasName("f")))), 200 {addInclude("clang/OtherLib.h"), changeTo(cat("other()"))}); 201 202 std::string Input = R"cc( 203 int f(int x); 204 int h(int x) { return f(x); } 205 )cc"; 206 std::string Expected = R"cc(#include "clang/OtherLib.h" 207 208 int f(int x); 209 int h(int x) { return other(); } 210 )cc"; 211 212 testRule(Rule, Input, Expected); 213 } 214 215 TEST_F(TransformerTest, AddIncludeAngled) { 216 RewriteRule Rule = makeRule( 217 callExpr(callee(functionDecl(hasName("f")))), 218 {addInclude("clang/OtherLib.h", transformer::IncludeFormat::Angled), 219 changeTo(cat("other()"))}); 220 221 std::string Input = R"cc( 222 int f(int x); 223 int h(int x) { return f(x); } 224 )cc"; 225 std::string Expected = R"cc(#include <clang/OtherLib.h> 226 227 int f(int x); 228 int h(int x) { return other(); } 229 )cc"; 230 231 testRule(Rule, Input, Expected); 232 } 233 234 TEST_F(TransformerTest, AddIncludeQuotedForRule) { 235 RewriteRule Rule = makeRule(callExpr(callee(functionDecl(hasName("f")))), 236 changeTo(cat("other()"))); 237 addInclude(Rule, "clang/OtherLib.h"); 238 239 std::string Input = R"cc( 240 int f(int x); 241 int h(int x) { return f(x); } 242 )cc"; 243 std::string Expected = R"cc(#include "clang/OtherLib.h" 244 245 int f(int x); 246 int h(int x) { return other(); } 247 )cc"; 248 249 testRule(Rule, Input, Expected); 250 } 251 252 TEST_F(TransformerTest, AddIncludeAngledForRule) { 253 RewriteRule Rule = makeRule(callExpr(callee(functionDecl(hasName("f")))), 254 changeTo(cat("other()"))); 255 addInclude(Rule, "clang/OtherLib.h", transformer::IncludeFormat::Angled); 256 257 std::string Input = R"cc( 258 int f(int x); 259 int h(int x) { return f(x); } 260 )cc"; 261 std::string Expected = R"cc(#include <clang/OtherLib.h> 262 263 int f(int x); 264 int h(int x) { return other(); } 265 )cc"; 266 267 testRule(Rule, Input, Expected); 268 } 269 270 TEST_F(TransformerTest, NodePartNameNamedDecl) { 271 StringRef Fun = "fun"; 272 RewriteRule Rule = makeRule(functionDecl(hasName("bad")).bind(Fun), 273 changeTo(name(std::string(Fun)), cat("good"))); 274 275 std::string Input = R"cc( 276 int bad(int x); 277 int bad(int x) { return x * x; } 278 )cc"; 279 std::string Expected = R"cc( 280 int good(int x); 281 int good(int x) { return x * x; } 282 )cc"; 283 284 testRule(Rule, Input, Expected); 285 } 286 287 TEST_F(TransformerTest, NodePartNameDeclRef) { 288 std::string Input = R"cc( 289 template <typename T> 290 T bad(T x) { 291 return x; 292 } 293 int neutral(int x) { return bad<int>(x) * x; } 294 )cc"; 295 std::string Expected = R"cc( 296 template <typename T> 297 T bad(T x) { 298 return x; 299 } 300 int neutral(int x) { return good<int>(x) * x; } 301 )cc"; 302 303 StringRef Ref = "ref"; 304 testRule(makeRule(declRefExpr(to(functionDecl(hasName("bad")))).bind(Ref), 305 changeTo(name(std::string(Ref)), cat("good"))), 306 Input, Expected); 307 } 308 309 TEST_F(TransformerTest, NodePartNameDeclRefFailure) { 310 std::string Input = R"cc( 311 struct Y { 312 int operator*(); 313 }; 314 int neutral(int x) { 315 Y y; 316 int (Y::*ptr)() = &Y::operator*; 317 return *y + x; 318 } 319 )cc"; 320 321 StringRef Ref = "ref"; 322 Transformer T(makeRule(declRefExpr(to(functionDecl())).bind(Ref), 323 changeTo(name(std::string(Ref)), cat("good"))), 324 consumer()); 325 T.registerMatchers(&MatchFinder); 326 EXPECT_FALSE(rewrite(Input)); 327 } 328 329 TEST_F(TransformerTest, NodePartMember) { 330 StringRef E = "expr"; 331 RewriteRule Rule = makeRule(memberExpr(member(hasName("bad"))).bind(E), 332 changeTo(member(std::string(E)), cat("good"))); 333 334 std::string Input = R"cc( 335 struct S { 336 int bad; 337 }; 338 int g() { 339 S s; 340 return s.bad; 341 } 342 )cc"; 343 std::string Expected = R"cc( 344 struct S { 345 int bad; 346 }; 347 int g() { 348 S s; 349 return s.good; 350 } 351 )cc"; 352 353 testRule(Rule, Input, Expected); 354 } 355 356 TEST_F(TransformerTest, NodePartMemberQualified) { 357 std::string Input = R"cc( 358 struct S { 359 int bad; 360 int good; 361 }; 362 struct T : public S { 363 int bad; 364 }; 365 int g() { 366 T t; 367 return t.S::bad; 368 } 369 )cc"; 370 std::string Expected = R"cc( 371 struct S { 372 int bad; 373 int good; 374 }; 375 struct T : public S { 376 int bad; 377 }; 378 int g() { 379 T t; 380 return t.S::good; 381 } 382 )cc"; 383 384 StringRef E = "expr"; 385 testRule(makeRule(memberExpr().bind(E), 386 changeTo(member(std::string(E)), cat("good"))), 387 Input, Expected); 388 } 389 390 TEST_F(TransformerTest, NodePartMemberMultiToken) { 391 std::string Input = R"cc( 392 struct Y { 393 int operator*(); 394 int good(); 395 template <typename T> void foo(T t); 396 }; 397 int neutral(int x) { 398 Y y; 399 y.template foo<int>(3); 400 return y.operator *(); 401 } 402 )cc"; 403 std::string Expected = R"cc( 404 struct Y { 405 int operator*(); 406 int good(); 407 template <typename T> void foo(T t); 408 }; 409 int neutral(int x) { 410 Y y; 411 y.template good<int>(3); 412 return y.good(); 413 } 414 )cc"; 415 416 StringRef MemExpr = "member"; 417 testRule(makeRule(memberExpr().bind(MemExpr), 418 changeTo(member(std::string(MemExpr)), cat("good"))), 419 Input, Expected); 420 } 421 422 TEST_F(TransformerTest, NoEdits) { 423 using transformer::noEdits; 424 std::string Input = "int f(int x) { return x; }"; 425 testRule(makeRule(returnStmt().bind("return"), noEdits()), Input, Input); 426 } 427 428 TEST_F(TransformerTest, IfBound2Args) { 429 using transformer::ifBound; 430 std::string Input = "int f(int x) { return x; }"; 431 std::string Expected = "int f(int x) { CHANGE; }"; 432 testRule(makeRule(returnStmt().bind("return"), 433 ifBound("return", changeTo(cat("CHANGE;")))), 434 Input, Expected); 435 } 436 437 TEST_F(TransformerTest, IfBound3Args) { 438 using transformer::ifBound; 439 std::string Input = "int f(int x) { return x; }"; 440 std::string Expected = "int f(int x) { CHANGE; }"; 441 testRule(makeRule(returnStmt().bind("return"), 442 ifBound("nothing", changeTo(cat("ERROR")), 443 changeTo(cat("CHANGE;")))), 444 Input, Expected); 445 } 446 447 TEST_F(TransformerTest, ShrinkTo) { 448 using transformer::shrinkTo; 449 std::string Input = "int f(int x) { return x; }"; 450 std::string Expected = "return x;"; 451 testRule(makeRule(functionDecl(hasDescendant(returnStmt().bind("return"))) 452 .bind("function"), 453 shrinkTo(node("function"), node("return"))), 454 Input, Expected); 455 } 456 457 // Rewrite various Stmts inside a Decl. 458 TEST_F(TransformerTest, RewriteDescendantsDeclChangeStmt) { 459 std::string Input = 460 "int f(int x) { int y = x; { int z = x * x; } return x; }"; 461 std::string Expected = 462 "int f(int x) { int y = 3; { int z = 3 * 3; } return 3; }"; 463 auto InlineX = 464 makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3"))); 465 testRule(makeRule(functionDecl(hasName("f")).bind("fun"), 466 rewriteDescendants("fun", InlineX)), 467 Input, Expected); 468 } 469 470 // Rewrite various TypeLocs inside a Decl. 471 TEST_F(TransformerTest, RewriteDescendantsDeclChangeTypeLoc) { 472 std::string Input = "int f(int *x) { return *x; }"; 473 std::string Expected = "char f(char *x) { return *x; }"; 474 auto IntToChar = makeRule(typeLoc(loc(qualType(isInteger(), builtinType()))), 475 changeTo(cat("char"))); 476 testRule(makeRule(functionDecl(hasName("f")).bind("fun"), 477 rewriteDescendants("fun", IntToChar)), 478 Input, Expected); 479 } 480 481 TEST_F(TransformerTest, RewriteDescendantsStmt) { 482 // Add an unrelated definition to the header that also has a variable named 483 // "x", to test that the rewrite is limited to the scope we intend. 484 appendToHeader(R"cc(int g(int x) { return x; })cc"); 485 std::string Input = 486 "int f(int x) { int y = x; { int z = x * x; } return x; }"; 487 std::string Expected = 488 "int f(int x) { int y = 3; { int z = 3 * 3; } return 3; }"; 489 auto InlineX = 490 makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3"))); 491 testRule(makeRule(functionDecl(hasName("f"), hasBody(stmt().bind("body"))), 492 rewriteDescendants("body", InlineX)), 493 Input, Expected); 494 } 495 496 TEST_F(TransformerTest, RewriteDescendantsStmtWithAdditionalChange) { 497 std::string Input = 498 "int f(int x) { int y = x; { int z = x * x; } return x; }"; 499 std::string Expected = 500 "int newName(int x) { int y = 3; { int z = 3 * 3; } return 3; }"; 501 auto InlineX = 502 makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3"))); 503 testRule( 504 makeRule( 505 functionDecl(hasName("f"), hasBody(stmt().bind("body"))).bind("f"), 506 flatten(changeTo(name("f"), cat("newName")), 507 rewriteDescendants("body", InlineX))), 508 Input, Expected); 509 } 510 511 TEST_F(TransformerTest, RewriteDescendantsTypeLoc) { 512 std::string Input = "int f(int *x) { return *x; }"; 513 std::string Expected = "int f(char *x) { return *x; }"; 514 auto IntToChar = 515 makeRule(typeLoc(loc(qualType(isInteger(), builtinType()))).bind("loc"), 516 changeTo(cat("char"))); 517 testRule( 518 makeRule(functionDecl(hasName("f"), 519 hasParameter(0, varDecl(hasTypeLoc( 520 typeLoc().bind("parmType"))))), 521 rewriteDescendants("parmType", IntToChar)), 522 Input, Expected); 523 } 524 525 TEST_F(TransformerTest, RewriteDescendantsReferToParentBinding) { 526 std::string Input = 527 "int f(int p) { int y = p; { int z = p * p; } return p; }"; 528 std::string Expected = 529 "int f(int p) { int y = 3; { int z = 3 * 3; } return 3; }"; 530 std::string VarId = "var"; 531 auto InlineVar = makeRule(declRefExpr(to(varDecl(equalsBoundNode(VarId)))), 532 changeTo(cat("3"))); 533 testRule(makeRule(functionDecl(hasName("f"), 534 hasParameter(0, varDecl().bind(VarId))) 535 .bind("fun"), 536 rewriteDescendants("fun", InlineVar)), 537 Input, Expected); 538 } 539 540 TEST_F(TransformerTest, RewriteDescendantsUnboundNode) { 541 std::string Input = 542 "int f(int x) { int y = x; { int z = x * x; } return x; }"; 543 auto InlineX = 544 makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3"))); 545 Transformer T(makeRule(functionDecl(hasName("f")), 546 rewriteDescendants("UNBOUND", InlineX)), 547 consumer()); 548 T.registerMatchers(&MatchFinder); 549 EXPECT_FALSE(rewrite(Input)); 550 EXPECT_THAT(Changes, IsEmpty()); 551 EXPECT_EQ(ErrorCount, 1); 552 } 553 554 TEST_F(TransformerTest, RewriteDescendantsInvalidNodeType) { 555 std::string Input = 556 "int f(int x) { int y = x; { int z = x * x; } return x; }"; 557 auto IntToChar = 558 makeRule(qualType(isInteger(), builtinType()), changeTo(cat("char"))); 559 Transformer T( 560 makeRule(functionDecl( 561 hasName("f"), 562 hasParameter(0, varDecl(hasType(qualType().bind("type"))))), 563 rewriteDescendants("type", IntToChar)), 564 consumer()); 565 T.registerMatchers(&MatchFinder); 566 EXPECT_FALSE(rewrite(Input)); 567 EXPECT_THAT(Changes, IsEmpty()); 568 EXPECT_EQ(ErrorCount, 1); 569 } 570 571 TEST_F(TransformerTest, InsertBeforeEdit) { 572 std::string Input = R"cc( 573 int f() { 574 return 7; 575 } 576 )cc"; 577 std::string Expected = R"cc( 578 int f() { 579 int y = 3; 580 return 7; 581 } 582 )cc"; 583 584 StringRef Ret = "return"; 585 testRule( 586 makeRule(returnStmt().bind(Ret), 587 insertBefore(statement(std::string(Ret)), cat("int y = 3;"))), 588 Input, Expected); 589 } 590 591 TEST_F(TransformerTest, InsertAfterEdit) { 592 std::string Input = R"cc( 593 int f() { 594 int x = 5; 595 return 7; 596 } 597 )cc"; 598 std::string Expected = R"cc( 599 int f() { 600 int x = 5; 601 int y = 3; 602 return 7; 603 } 604 )cc"; 605 606 StringRef Decl = "decl"; 607 testRule( 608 makeRule(declStmt().bind(Decl), 609 insertAfter(statement(std::string(Decl)), cat("int y = 3;"))), 610 Input, Expected); 611 } 612 613 TEST_F(TransformerTest, RemoveEdit) { 614 std::string Input = R"cc( 615 int f() { 616 int x = 5; 617 return 7; 618 } 619 )cc"; 620 std::string Expected = R"cc( 621 int f() { 622 return 7; 623 } 624 )cc"; 625 626 StringRef Decl = "decl"; 627 testRule( 628 makeRule(declStmt().bind(Decl), remove(statement(std::string(Decl)))), 629 Input, Expected); 630 } 631 632 TEST_F(TransformerTest, WithMetadata) { 633 auto makeMetadata = [](const MatchFinder::MatchResult &R) -> llvm::Any { 634 int N = 635 R.Nodes.getNodeAs<IntegerLiteral>("int")->getValue().getLimitedValue(); 636 return N; 637 }; 638 639 std::string Input = R"cc( 640 int f() { 641 int x = 5; 642 return 7; 643 } 644 )cc"; 645 646 Transformer T( 647 makeRule( 648 declStmt(containsDeclaration(0, varDecl(hasInitializer( 649 integerLiteral().bind("int"))))) 650 .bind("decl"), 651 withMetadata(remove(statement(std::string("decl"))), makeMetadata)), 652 consumer()); 653 T.registerMatchers(&MatchFinder); 654 auto Factory = newFrontendActionFactory(&MatchFinder); 655 EXPECT_TRUE(runToolOnCodeWithArgs( 656 Factory->create(), Input, std::vector<std::string>(), "input.cc", 657 "clang-tool", std::make_shared<PCHContainerOperations>(), {})); 658 ASSERT_EQ(Changes.size(), 1u); 659 const llvm::Any &Metadata = Changes[0].getMetadata(); 660 ASSERT_TRUE(llvm::any_isa<int>(Metadata)); 661 EXPECT_THAT(llvm::any_cast<int>(Metadata), 5); 662 } 663 664 TEST_F(TransformerTest, MultiChange) { 665 std::string Input = R"cc( 666 void foo() { 667 if (10 > 1.0) 668 log(1) << "oh no!"; 669 else 670 log(0) << "ok"; 671 } 672 )cc"; 673 std::string Expected = R"( 674 void foo() { 675 if (true) { /* then */ } 676 else { /* else */ } 677 } 678 )"; 679 680 StringRef C = "C", T = "T", E = "E"; 681 testRule( 682 makeRule(ifStmt(hasCondition(expr().bind(C)), hasThen(stmt().bind(T)), 683 hasElse(stmt().bind(E))), 684 {changeTo(node(std::string(C)), cat("true")), 685 changeTo(statement(std::string(T)), cat("{ /* then */ }")), 686 changeTo(statement(std::string(E)), cat("{ /* else */ }"))}), 687 Input, Expected); 688 } 689 690 TEST_F(TransformerTest, EditList) { 691 using clang::transformer::editList; 692 std::string Input = R"cc( 693 void foo() { 694 if (10 > 1.0) 695 log(1) << "oh no!"; 696 else 697 log(0) << "ok"; 698 } 699 )cc"; 700 std::string Expected = R"( 701 void foo() { 702 if (true) { /* then */ } 703 else { /* else */ } 704 } 705 )"; 706 707 StringRef C = "C", T = "T", E = "E"; 708 testRule(makeRule(ifStmt(hasCondition(expr().bind(C)), 709 hasThen(stmt().bind(T)), hasElse(stmt().bind(E))), 710 editList({changeTo(node(std::string(C)), cat("true")), 711 changeTo(statement(std::string(T)), 712 cat("{ /* then */ }")), 713 changeTo(statement(std::string(E)), 714 cat("{ /* else */ }"))})), 715 Input, Expected); 716 } 717 718 TEST_F(TransformerTest, Flatten) { 719 using clang::transformer::editList; 720 std::string Input = R"cc( 721 void foo() { 722 if (10 > 1.0) 723 log(1) << "oh no!"; 724 else 725 log(0) << "ok"; 726 } 727 )cc"; 728 std::string Expected = R"( 729 void foo() { 730 if (true) { /* then */ } 731 else { /* else */ } 732 } 733 )"; 734 735 StringRef C = "C", T = "T", E = "E"; 736 testRule( 737 makeRule( 738 ifStmt(hasCondition(expr().bind(C)), hasThen(stmt().bind(T)), 739 hasElse(stmt().bind(E))), 740 flatten(changeTo(node(std::string(C)), cat("true")), 741 changeTo(statement(std::string(T)), cat("{ /* then */ }")), 742 changeTo(statement(std::string(E)), cat("{ /* else */ }")))), 743 Input, Expected); 744 } 745 746 TEST_F(TransformerTest, FlattenWithMixedArgs) { 747 using clang::transformer::editList; 748 std::string Input = R"cc( 749 void foo() { 750 if (10 > 1.0) 751 log(1) << "oh no!"; 752 else 753 log(0) << "ok"; 754 } 755 )cc"; 756 std::string Expected = R"( 757 void foo() { 758 if (true) { /* then */ } 759 else { /* else */ } 760 } 761 )"; 762 763 StringRef C = "C", T = "T", E = "E"; 764 testRule(makeRule(ifStmt(hasCondition(expr().bind(C)), 765 hasThen(stmt().bind(T)), hasElse(stmt().bind(E))), 766 flatten(changeTo(node(std::string(C)), cat("true")), 767 edit(changeTo(statement(std::string(T)), 768 cat("{ /* then */ }"))), 769 editList({changeTo(statement(std::string(E)), 770 cat("{ /* else */ }"))}))), 771 Input, Expected); 772 } 773 774 TEST_F(TransformerTest, OrderedRuleUnrelated) { 775 StringRef Flag = "flag"; 776 RewriteRule FlagRule = makeRule( 777 cxxMemberCallExpr(on(expr(hasType(cxxRecordDecl( 778 hasName("proto::ProtoCommandLineFlag")))) 779 .bind(Flag)), 780 unless(callee(cxxMethodDecl(hasName("GetProto"))))), 781 changeTo(node(std::string(Flag)), cat("PROTO"))); 782 783 std::string Input = R"cc( 784 proto::ProtoCommandLineFlag flag; 785 int x = flag.foo(); 786 int y = flag.GetProto().foo(); 787 int f(string s) { return strlen(s.c_str()); } 788 )cc"; 789 std::string Expected = R"cc( 790 proto::ProtoCommandLineFlag flag; 791 int x = PROTO.foo(); 792 int y = flag.GetProto().foo(); 793 int f(string s) { return REPLACED; } 794 )cc"; 795 796 testRule(applyFirst({ruleStrlenSize(), FlagRule}), Input, Expected); 797 } 798 799 TEST_F(TransformerTest, OrderedRuleRelated) { 800 std::string Input = R"cc( 801 void f1(); 802 void f2(); 803 void call_f1() { f1(); } 804 void call_f2() { f2(); } 805 )cc"; 806 std::string Expected = R"cc( 807 void f1(); 808 void f2(); 809 void call_f1() { REPLACE_F1; } 810 void call_f2() { REPLACE_F1_OR_F2; } 811 )cc"; 812 813 RewriteRule ReplaceF1 = 814 makeRule(callExpr(callee(functionDecl(hasName("f1")))), 815 changeTo(cat("REPLACE_F1"))); 816 RewriteRule ReplaceF1OrF2 = 817 makeRule(callExpr(callee(functionDecl(hasAnyName("f1", "f2")))), 818 changeTo(cat("REPLACE_F1_OR_F2"))); 819 testRule(applyFirst({ReplaceF1, ReplaceF1OrF2}), Input, Expected); 820 } 821 822 // Change the order of the rules to get a different result. When `ReplaceF1OrF2` 823 // comes first, it applies for both uses, so `ReplaceF1` never applies. 824 TEST_F(TransformerTest, OrderedRuleRelatedSwapped) { 825 std::string Input = R"cc( 826 void f1(); 827 void f2(); 828 void call_f1() { f1(); } 829 void call_f2() { f2(); } 830 )cc"; 831 std::string Expected = R"cc( 832 void f1(); 833 void f2(); 834 void call_f1() { REPLACE_F1_OR_F2; } 835 void call_f2() { REPLACE_F1_OR_F2; } 836 )cc"; 837 838 RewriteRule ReplaceF1 = 839 makeRule(callExpr(callee(functionDecl(hasName("f1")))), 840 changeTo(cat("REPLACE_F1"))); 841 RewriteRule ReplaceF1OrF2 = 842 makeRule(callExpr(callee(functionDecl(hasAnyName("f1", "f2")))), 843 changeTo(cat("REPLACE_F1_OR_F2"))); 844 testRule(applyFirst({ReplaceF1OrF2, ReplaceF1}), Input, Expected); 845 } 846 847 // Verify that a set of rules whose matchers have different base kinds works 848 // properly, including that `applyFirst` produces multiple matchers. We test 849 // two different kinds of rules: Expr and Decl. We place the Decl rule in the 850 // middle to test that `buildMatchers` works even when the kinds aren't grouped 851 // together. 852 TEST_F(TransformerTest, OrderedRuleMultipleKinds) { 853 std::string Input = R"cc( 854 void f1(); 855 void f2(); 856 void call_f1() { f1(); } 857 void call_f2() { f2(); } 858 )cc"; 859 std::string Expected = R"cc( 860 void f1(); 861 void DECL_RULE(); 862 void call_f1() { REPLACE_F1; } 863 void call_f2() { REPLACE_F1_OR_F2; } 864 )cc"; 865 866 RewriteRule ReplaceF1 = 867 makeRule(callExpr(callee(functionDecl(hasName("f1")))), 868 changeTo(cat("REPLACE_F1"))); 869 RewriteRule ReplaceF1OrF2 = 870 makeRule(callExpr(callee(functionDecl(hasAnyName("f1", "f2")))), 871 changeTo(cat("REPLACE_F1_OR_F2"))); 872 RewriteRule DeclRule = makeRule(functionDecl(hasName("f2")).bind("fun"), 873 changeTo(name("fun"), cat("DECL_RULE"))); 874 875 RewriteRule Rule = applyFirst({ReplaceF1, DeclRule, ReplaceF1OrF2}); 876 EXPECT_EQ(transformer::detail::buildMatchers(Rule).size(), 2UL); 877 testRule(Rule, Input, Expected); 878 } 879 880 // Verifies that a rule with a top-level matcher for an implicit node (like 881 // `implicitCastExpr`) does not change the code, when the AST traversal skips 882 // implicit nodes. In this test, only the rule with the explicit-node matcher 883 // will fire. 884 TEST_F(TransformerTest, OrderedRuleImplicitIgnored) { 885 std::string Input = R"cc( 886 void f1(); 887 int f2(); 888 void call_f1() { f1(); } 889 float call_f2() { return f2(); } 890 )cc"; 891 std::string Expected = R"cc( 892 void f1(); 893 int f2(); 894 void call_f1() { REPLACE_F1; } 895 float call_f2() { return f2(); } 896 )cc"; 897 898 RewriteRule ReplaceF1 = 899 makeRule(callExpr(callee(functionDecl(hasName("f1")))), 900 changeTo(cat("REPLACE_F1"))); 901 RewriteRule ReplaceF2 = 902 makeRule(implicitCastExpr(hasSourceExpression(callExpr())), 903 changeTo(cat("REPLACE_F2"))); 904 testRule(applyFirst({ReplaceF1, ReplaceF2}), Input, Expected); 905 } 906 907 // Verifies that explicitly setting the traversal kind fixes the problem in the 908 // previous test. 909 TEST_F(TransformerTest, OrderedRuleImplicitMatched) { 910 std::string Input = R"cc( 911 void f1(); 912 int f2(); 913 void call_f1() { f1(); } 914 float call_f2() { return f2(); } 915 )cc"; 916 std::string Expected = R"cc( 917 void f1(); 918 int f2(); 919 void call_f1() { REPLACE_F1; } 920 float call_f2() { return REPLACE_F2; } 921 )cc"; 922 923 RewriteRule ReplaceF1 = makeRule( 924 traverse(clang::TK_AsIs, callExpr(callee(functionDecl(hasName("f1"))))), 925 changeTo(cat("REPLACE_F1"))); 926 RewriteRule ReplaceF2 = 927 makeRule(traverse(clang::TK_AsIs, 928 implicitCastExpr(hasSourceExpression(callExpr()))), 929 changeTo(cat("REPLACE_F2"))); 930 testRule(applyFirst({ReplaceF1, ReplaceF2}), Input, Expected); 931 } 932 933 // 934 // Negative tests (where we expect no transformation to occur). 935 // 936 937 // Tests for a conflict in edits from a single match for a rule. 938 TEST_F(TransformerTest, TextGeneratorFailure) { 939 std::string Input = "int conflictOneRule() { return 3 + 7; }"; 940 // Try to change the whole binary-operator expression AND one its operands: 941 StringRef O = "O"; 942 class AlwaysFail : public transformer::MatchComputation<std::string> { 943 llvm::Error eval(const ast_matchers::MatchFinder::MatchResult &, 944 std::string *) const override { 945 return llvm::createStringError(llvm::errc::invalid_argument, "ERROR"); 946 } 947 std::string toString() const override { return "AlwaysFail"; } 948 }; 949 Transformer T( 950 makeRule(binaryOperator().bind(O), 951 changeTo(node(std::string(O)), std::make_shared<AlwaysFail>())), 952 consumer()); 953 T.registerMatchers(&MatchFinder); 954 EXPECT_FALSE(rewrite(Input)); 955 EXPECT_THAT(Changes, IsEmpty()); 956 EXPECT_EQ(ErrorCount, 1); 957 } 958 959 // Tests for a conflict in edits from a single match for a rule. 960 TEST_F(TransformerTest, OverlappingEditsInRule) { 961 std::string Input = "int conflictOneRule() { return 3 + 7; }"; 962 // Try to change the whole binary-operator expression AND one its operands: 963 StringRef O = "O", L = "L"; 964 Transformer T(makeRule(binaryOperator(hasLHS(expr().bind(L))).bind(O), 965 {changeTo(node(std::string(O)), cat("DELETE_OP")), 966 changeTo(node(std::string(L)), cat("DELETE_LHS"))}), 967 consumer()); 968 T.registerMatchers(&MatchFinder); 969 EXPECT_FALSE(rewrite(Input)); 970 EXPECT_THAT(Changes, IsEmpty()); 971 EXPECT_EQ(ErrorCount, 1); 972 } 973 974 // Tests for a conflict in edits across multiple matches (of the same rule). 975 TEST_F(TransformerTest, OverlappingEditsMultipleMatches) { 976 std::string Input = "int conflictOneRule() { return -7; }"; 977 // Try to change the whole binary-operator expression AND one its operands: 978 StringRef E = "E"; 979 Transformer T(makeRule(expr().bind(E), 980 changeTo(node(std::string(E)), cat("DELETE_EXPR"))), 981 consumer()); 982 T.registerMatchers(&MatchFinder); 983 // The rewrite process fails because the changes conflict with each other... 984 EXPECT_FALSE(rewrite(Input)); 985 // ... but two changes were produced. 986 EXPECT_EQ(Changes.size(), 2u); 987 EXPECT_EQ(ErrorCount, 0); 988 } 989 990 TEST_F(TransformerTest, ErrorOccurredMatchSkipped) { 991 // Syntax error in the function body: 992 std::string Input = "void errorOccurred() { 3 }"; 993 Transformer T(makeRule(functionDecl(hasName("errorOccurred")), 994 changeTo(cat("DELETED;"))), 995 consumer()); 996 T.registerMatchers(&MatchFinder); 997 // The rewrite process itself fails... 998 EXPECT_FALSE(rewrite(Input)); 999 // ... and no changes or errors are produced in the process. 1000 EXPECT_THAT(Changes, IsEmpty()); 1001 EXPECT_EQ(ErrorCount, 0); 1002 } 1003 1004 // Transformation of macro source text when the change encompasses the entirety 1005 // of the expanded text. 1006 TEST_F(TransformerTest, SimpleMacro) { 1007 std::string Input = R"cc( 1008 #define ZERO 0 1009 int f(string s) { return ZERO; } 1010 )cc"; 1011 std::string Expected = R"cc( 1012 #define ZERO 0 1013 int f(string s) { return 999; } 1014 )cc"; 1015 1016 StringRef zero = "zero"; 1017 RewriteRule R = makeRule(integerLiteral(equals(0)).bind(zero), 1018 changeTo(node(std::string(zero)), cat("999"))); 1019 testRule(R, Input, Expected); 1020 } 1021 1022 // Transformation of macro source text when the change encompasses the entirety 1023 // of the expanded text, for the case of function-style macros. 1024 TEST_F(TransformerTest, FunctionMacro) { 1025 std::string Input = R"cc( 1026 #define MACRO(str) strlen((str).c_str()) 1027 int f(string s) { return MACRO(s); } 1028 )cc"; 1029 std::string Expected = R"cc( 1030 #define MACRO(str) strlen((str).c_str()) 1031 int f(string s) { return REPLACED; } 1032 )cc"; 1033 1034 testRule(ruleStrlenSize(), Input, Expected); 1035 } 1036 1037 // Tests that expressions in macro arguments can be rewritten. 1038 TEST_F(TransformerTest, MacroArg) { 1039 std::string Input = R"cc( 1040 #define PLUS(e) e + 1 1041 int f(string s) { return PLUS(strlen(s.c_str())); } 1042 )cc"; 1043 std::string Expected = R"cc( 1044 #define PLUS(e) e + 1 1045 int f(string s) { return PLUS(REPLACED); } 1046 )cc"; 1047 1048 testRule(ruleStrlenSize(), Input, Expected); 1049 } 1050 1051 // Tests that expressions in macro arguments can be rewritten, even when the 1052 // macro call occurs inside another macro's definition. 1053 TEST_F(TransformerTest, MacroArgInMacroDef) { 1054 std::string Input = R"cc( 1055 #define NESTED(e) e 1056 #define MACRO(str) NESTED(strlen((str).c_str())) 1057 int f(string s) { return MACRO(s); } 1058 )cc"; 1059 std::string Expected = R"cc( 1060 #define NESTED(e) e 1061 #define MACRO(str) NESTED(strlen((str).c_str())) 1062 int f(string s) { return REPLACED; } 1063 )cc"; 1064 1065 testRule(ruleStrlenSize(), Input, Expected); 1066 } 1067 1068 // Tests the corner case of the identity macro, specifically that it is 1069 // discarded in the rewrite rather than preserved (like PLUS is preserved in the 1070 // previous test). This behavior is of dubious value (and marked with a FIXME 1071 // in the code), but we test it to verify (and demonstrate) how this case is 1072 // handled. 1073 TEST_F(TransformerTest, IdentityMacro) { 1074 std::string Input = R"cc( 1075 #define ID(e) e 1076 int f(string s) { return ID(strlen(s.c_str())); } 1077 )cc"; 1078 std::string Expected = R"cc( 1079 #define ID(e) e 1080 int f(string s) { return REPLACED; } 1081 )cc"; 1082 1083 testRule(ruleStrlenSize(), Input, Expected); 1084 } 1085 1086 // Tests that two changes in a single macro expansion do not lead to conflicts 1087 // in applying the changes. 1088 TEST_F(TransformerTest, TwoChangesInOneMacroExpansion) { 1089 std::string Input = R"cc( 1090 #define PLUS(a,b) (a) + (b) 1091 int f() { return PLUS(3, 4); } 1092 )cc"; 1093 std::string Expected = R"cc( 1094 #define PLUS(a,b) (a) + (b) 1095 int f() { return PLUS(LIT, LIT); } 1096 )cc"; 1097 1098 testRule(makeRule(integerLiteral(), changeTo(cat("LIT"))), Input, Expected); 1099 } 1100 1101 // Tests case where the rule's match spans both source from the macro and its 1102 // arg, with the begin location (the "anchor") being the arg. 1103 TEST_F(TransformerTest, MatchSpansMacroTextButChangeDoesNot) { 1104 std::string Input = R"cc( 1105 #define PLUS_ONE(a) a + 1 1106 int f() { return PLUS_ONE(3); } 1107 )cc"; 1108 std::string Expected = R"cc( 1109 #define PLUS_ONE(a) a + 1 1110 int f() { return PLUS_ONE(LIT); } 1111 )cc"; 1112 1113 StringRef E = "expr"; 1114 testRule(makeRule(binaryOperator(hasLHS(expr().bind(E))), 1115 changeTo(node(std::string(E)), cat("LIT"))), 1116 Input, Expected); 1117 } 1118 1119 // Tests case where the rule's match spans both source from the macro and its 1120 // arg, with the begin location (the "anchor") being inside the macro. 1121 TEST_F(TransformerTest, MatchSpansMacroTextButChangeDoesNotAnchoredInMacro) { 1122 std::string Input = R"cc( 1123 #define PLUS_ONE(a) 1 + a 1124 int f() { return PLUS_ONE(3); } 1125 )cc"; 1126 std::string Expected = R"cc( 1127 #define PLUS_ONE(a) 1 + a 1128 int f() { return PLUS_ONE(LIT); } 1129 )cc"; 1130 1131 StringRef E = "expr"; 1132 testRule(makeRule(binaryOperator(hasRHS(expr().bind(E))), 1133 changeTo(node(std::string(E)), cat("LIT"))), 1134 Input, Expected); 1135 } 1136 1137 // No rewrite is applied when the changed text does not encompass the entirety 1138 // of the expanded text. That is, the edit would have to be applied to the 1139 // macro's definition to succeed and editing the expansion point would not 1140 // suffice. 1141 TEST_F(TransformerTest, NoPartialRewriteOMacroExpansion) { 1142 std::string Input = R"cc( 1143 #define ZERO_PLUS 0 + 3 1144 int f(string s) { return ZERO_PLUS; })cc"; 1145 1146 StringRef zero = "zero"; 1147 RewriteRule R = makeRule(integerLiteral(equals(0)).bind(zero), 1148 changeTo(node(std::string(zero)), cat("0"))); 1149 testRule(R, Input, Input); 1150 } 1151 1152 // This test handles the corner case where a macro expands within another macro 1153 // to matching code, but that code is an argument to the nested macro call. A 1154 // simple check of isMacroArgExpansion() vs. isMacroBodyExpansion() will get 1155 // this wrong, and transform the code. 1156 TEST_F(TransformerTest, NoPartialRewriteOfMacroExpansionForMacroArgs) { 1157 std::string Input = R"cc( 1158 #define NESTED(e) e 1159 #define MACRO(str) 1 + NESTED(strlen((str).c_str())) 1160 int f(string s) { return MACRO(s); } 1161 )cc"; 1162 1163 testRule(ruleStrlenSize(), Input, Input); 1164 } 1165 1166 #if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST 1167 // Verifies that `Type` and `QualType` are not allowed as top-level matchers in 1168 // rules. 1169 TEST(TransformerDeathTest, OrderedRuleTypes) { 1170 RewriteRule QualTypeRule = makeRule(qualType(), changeTo(cat("Q"))); 1171 EXPECT_DEATH(transformer::detail::buildMatchers(QualTypeRule), 1172 "Matcher must be.*node matcher"); 1173 1174 RewriteRule TypeRule = makeRule(arrayType(), changeTo(cat("T"))); 1175 EXPECT_DEATH(transformer::detail::buildMatchers(TypeRule), 1176 "Matcher must be.*node matcher"); 1177 } 1178 #endif 1179 1180 // Edits are able to span multiple files; in this case, a header and an 1181 // implementation file. 1182 TEST_F(TransformerTest, MultipleFiles) { 1183 std::string Header = R"cc(void RemoveThisFunction();)cc"; 1184 std::string Source = R"cc(#include "input.h" 1185 void RemoveThisFunction();)cc"; 1186 Transformer T( 1187 makeRule(functionDecl(hasName("RemoveThisFunction")), changeTo(cat(""))), 1188 consumer()); 1189 T.registerMatchers(&MatchFinder); 1190 auto Factory = newFrontendActionFactory(&MatchFinder); 1191 EXPECT_TRUE(runToolOnCodeWithArgs( 1192 Factory->create(), Source, std::vector<std::string>(), "input.cc", 1193 "clang-tool", std::make_shared<PCHContainerOperations>(), 1194 {{"input.h", Header}})); 1195 1196 std::sort(Changes.begin(), Changes.end(), 1197 [](const AtomicChange &L, const AtomicChange &R) { 1198 return L.getFilePath() < R.getFilePath(); 1199 }); 1200 1201 ASSERT_EQ(Changes[0].getFilePath(), "./input.h"); 1202 EXPECT_THAT(Changes[0].getInsertedHeaders(), IsEmpty()); 1203 EXPECT_THAT(Changes[0].getRemovedHeaders(), IsEmpty()); 1204 llvm::Expected<std::string> UpdatedCode = 1205 clang::tooling::applyAllReplacements(Header, 1206 Changes[0].getReplacements()); 1207 ASSERT_TRUE(static_cast<bool>(UpdatedCode)) 1208 << "Could not update code: " << llvm::toString(UpdatedCode.takeError()); 1209 EXPECT_EQ(format(*UpdatedCode), format(R"cc(;)cc")); 1210 1211 ASSERT_EQ(Changes[1].getFilePath(), "input.cc"); 1212 EXPECT_THAT(Changes[1].getInsertedHeaders(), IsEmpty()); 1213 EXPECT_THAT(Changes[1].getRemovedHeaders(), IsEmpty()); 1214 UpdatedCode = clang::tooling::applyAllReplacements( 1215 Source, Changes[1].getReplacements()); 1216 ASSERT_TRUE(static_cast<bool>(UpdatedCode)) 1217 << "Could not update code: " << llvm::toString(UpdatedCode.takeError()); 1218 EXPECT_EQ(format(*UpdatedCode), format(R"cc(#include "input.h" 1219 ;)cc")); 1220 } 1221 1222 TEST_F(TransformerTest, AddIncludeMultipleFiles) { 1223 std::string Header = R"cc(void RemoveThisFunction();)cc"; 1224 std::string Source = R"cc(#include "input.h" 1225 void Foo() {RemoveThisFunction();})cc"; 1226 Transformer T( 1227 makeRule(callExpr(callee( 1228 functionDecl(hasName("RemoveThisFunction")).bind("fun"))), 1229 addInclude(node("fun"), "header.h")), 1230 consumer()); 1231 T.registerMatchers(&MatchFinder); 1232 auto Factory = newFrontendActionFactory(&MatchFinder); 1233 EXPECT_TRUE(runToolOnCodeWithArgs( 1234 Factory->create(), Source, std::vector<std::string>(), "input.cc", 1235 "clang-tool", std::make_shared<PCHContainerOperations>(), 1236 {{"input.h", Header}})); 1237 1238 ASSERT_EQ(Changes.size(), 1U); 1239 ASSERT_EQ(Changes[0].getFilePath(), "./input.h"); 1240 EXPECT_THAT(Changes[0].getInsertedHeaders(), ElementsAre("header.h")); 1241 EXPECT_THAT(Changes[0].getRemovedHeaders(), IsEmpty()); 1242 llvm::Expected<std::string> UpdatedCode = 1243 clang::tooling::applyAllReplacements(Header, 1244 Changes[0].getReplacements()); 1245 ASSERT_TRUE(static_cast<bool>(UpdatedCode)) 1246 << "Could not update code: " << llvm::toString(UpdatedCode.takeError()); 1247 EXPECT_EQ(format(*UpdatedCode), format(Header)); 1248 } 1249 } // namespace 1250