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/Stencil.h" 14 #include "llvm/Support/Errc.h" 15 #include "llvm/Support/Error.h" 16 #include "gmock/gmock.h" 17 #include "gtest/gtest.h" 18 19 using namespace clang; 20 using namespace tooling; 21 using namespace ast_matchers; 22 namespace { 23 using ::testing::IsEmpty; 24 using transformer::cat; 25 using transformer::changeTo; 26 using transformer::RewriteRule; 27 28 constexpr char KHeaderContents[] = R"cc( 29 struct string { 30 string(const char*); 31 char* c_str(); 32 int size(); 33 }; 34 int strlen(const char*); 35 36 namespace proto { 37 struct PCFProto { 38 int foo(); 39 }; 40 struct ProtoCommandLineFlag : PCFProto { 41 PCFProto& GetProto(); 42 }; 43 } // namespace proto 44 class Logger {}; 45 void operator<<(Logger& l, string msg); 46 Logger& log(int level); 47 )cc"; 48 49 static ast_matchers::internal::Matcher<clang::QualType> 50 isOrPointsTo(const clang::ast_matchers::DeclarationMatcher &TypeMatcher) { 51 return anyOf(hasDeclaration(TypeMatcher), pointsTo(TypeMatcher)); 52 } 53 54 static std::string format(StringRef Code) { 55 const std::vector<Range> Ranges(1, Range(0, Code.size())); 56 auto Style = format::getLLVMStyle(); 57 const auto Replacements = format::reformat(Style, Code, Ranges); 58 auto Formatted = applyAllReplacements(Code, Replacements); 59 if (!Formatted) { 60 ADD_FAILURE() << "Could not format code: " 61 << llvm::toString(Formatted.takeError()); 62 return std::string(); 63 } 64 return *Formatted; 65 } 66 67 static void compareSnippets(StringRef Expected, 68 const llvm::Optional<std::string> &MaybeActual) { 69 ASSERT_TRUE(MaybeActual) << "Rewrite failed. Expecting: " << Expected; 70 auto Actual = *MaybeActual; 71 std::string HL = "#include \"header.h\"\n"; 72 auto I = Actual.find(HL); 73 if (I != std::string::npos) 74 Actual.erase(I, HL.size()); 75 EXPECT_EQ(format(Expected), format(Actual)); 76 } 77 78 // FIXME: consider separating this class into its own file(s). 79 class ClangRefactoringTestBase : public testing::Test { 80 protected: 81 void appendToHeader(StringRef S) { FileContents[0].second += S; } 82 83 void addFile(StringRef Filename, StringRef Content) { 84 FileContents.emplace_back(std::string(Filename), std::string(Content)); 85 } 86 87 llvm::Optional<std::string> rewrite(StringRef Input) { 88 std::string Code = ("#include \"header.h\"\n" + Input).str(); 89 auto Factory = newFrontendActionFactory(&MatchFinder); 90 if (!runToolOnCodeWithArgs( 91 Factory->create(), Code, std::vector<std::string>(), "input.cc", 92 "clang-tool", std::make_shared<PCHContainerOperations>(), 93 FileContents)) { 94 llvm::errs() << "Running tool failed.\n"; 95 return None; 96 } 97 if (ErrorCount != 0) { 98 llvm::errs() << "Generating changes failed.\n"; 99 return None; 100 } 101 auto ChangedCode = 102 applyAtomicChanges("input.cc", Code, Changes, ApplyChangesSpec()); 103 if (!ChangedCode) { 104 llvm::errs() << "Applying changes failed: " 105 << llvm::toString(ChangedCode.takeError()) << "\n"; 106 return None; 107 } 108 return *ChangedCode; 109 } 110 111 Transformer::ChangeConsumer consumer() { 112 return [this](Expected<AtomicChange> C) { 113 if (C) { 114 Changes.push_back(std::move(*C)); 115 } else { 116 consumeError(C.takeError()); 117 ++ErrorCount; 118 } 119 }; 120 } 121 122 template <typename R> 123 void testRule(R Rule, StringRef Input, StringRef Expected) { 124 Transformer T(std::move(Rule), consumer()); 125 T.registerMatchers(&MatchFinder); 126 compareSnippets(Expected, rewrite(Input)); 127 } 128 129 clang::ast_matchers::MatchFinder MatchFinder; 130 // Records whether any errors occurred in individual changes. 131 int ErrorCount = 0; 132 AtomicChanges Changes; 133 134 private: 135 FileContentMappings FileContents = {{"header.h", ""}}; 136 }; 137 138 class TransformerTest : public ClangRefactoringTestBase { 139 protected: 140 TransformerTest() { appendToHeader(KHeaderContents); } 141 }; 142 143 // Given string s, change strlen($s.c_str()) to REPLACED. 144 static RewriteRule ruleStrlenSize() { 145 StringRef StringExpr = "strexpr"; 146 auto StringType = namedDecl(hasAnyName("::basic_string", "::string")); 147 auto R = makeRule( 148 callExpr(callee(functionDecl(hasName("strlen"))), 149 hasArgument(0, cxxMemberCallExpr( 150 on(expr(hasType(isOrPointsTo(StringType))) 151 .bind(StringExpr)), 152 callee(cxxMethodDecl(hasName("c_str")))))), 153 changeTo(cat("REPLACED")), cat("Use size() method directly on string.")); 154 return R; 155 } 156 157 TEST_F(TransformerTest, StrlenSize) { 158 std::string Input = "int f(string s) { return strlen(s.c_str()); }"; 159 std::string Expected = "int f(string s) { return REPLACED; }"; 160 testRule(ruleStrlenSize(), Input, Expected); 161 } 162 163 // Tests that no change is applied when a match is not expected. 164 TEST_F(TransformerTest, NoMatch) { 165 std::string Input = "int f(string s) { return s.size(); }"; 166 testRule(ruleStrlenSize(), Input, Input); 167 } 168 169 // Tests replacing an expression. 170 TEST_F(TransformerTest, Flag) { 171 StringRef Flag = "flag"; 172 RewriteRule Rule = makeRule( 173 cxxMemberCallExpr(on(expr(hasType(cxxRecordDecl( 174 hasName("proto::ProtoCommandLineFlag")))) 175 .bind(Flag)), 176 unless(callee(cxxMethodDecl(hasName("GetProto"))))), 177 changeTo(node(std::string(Flag)), cat("EXPR"))); 178 179 std::string Input = R"cc( 180 proto::ProtoCommandLineFlag flag; 181 int x = flag.foo(); 182 int y = flag.GetProto().foo(); 183 )cc"; 184 std::string Expected = R"cc( 185 proto::ProtoCommandLineFlag flag; 186 int x = EXPR.foo(); 187 int y = flag.GetProto().foo(); 188 )cc"; 189 190 testRule(std::move(Rule), Input, Expected); 191 } 192 193 TEST_F(TransformerTest, AddIncludeQuoted) { 194 RewriteRule Rule = makeRule(callExpr(callee(functionDecl(hasName("f")))), 195 changeTo(cat("other()"))); 196 addInclude(Rule, "clang/OtherLib.h"); 197 198 std::string Input = R"cc( 199 int f(int x); 200 int h(int x) { return f(x); } 201 )cc"; 202 std::string Expected = R"cc(#include "clang/OtherLib.h" 203 204 int f(int x); 205 int h(int x) { return other(); } 206 )cc"; 207 208 testRule(Rule, Input, Expected); 209 } 210 211 TEST_F(TransformerTest, AddIncludeAngled) { 212 RewriteRule Rule = makeRule(callExpr(callee(functionDecl(hasName("f")))), 213 changeTo(cat("other()"))); 214 addInclude(Rule, "clang/OtherLib.h", transformer::IncludeFormat::Angled); 215 216 std::string Input = R"cc( 217 int f(int x); 218 int h(int x) { return f(x); } 219 )cc"; 220 std::string Expected = R"cc(#include <clang/OtherLib.h> 221 222 int f(int x); 223 int h(int x) { return other(); } 224 )cc"; 225 226 testRule(Rule, Input, Expected); 227 } 228 229 TEST_F(TransformerTest, NodePartNameNamedDecl) { 230 StringRef Fun = "fun"; 231 RewriteRule Rule = makeRule(functionDecl(hasName("bad")).bind(Fun), 232 changeTo(name(std::string(Fun)), cat("good"))); 233 234 std::string Input = R"cc( 235 int bad(int x); 236 int bad(int x) { return x * x; } 237 )cc"; 238 std::string Expected = R"cc( 239 int good(int x); 240 int good(int x) { return x * x; } 241 )cc"; 242 243 testRule(Rule, Input, Expected); 244 } 245 246 TEST_F(TransformerTest, NodePartNameDeclRef) { 247 std::string Input = R"cc( 248 template <typename T> 249 T bad(T x) { 250 return x; 251 } 252 int neutral(int x) { return bad<int>(x) * x; } 253 )cc"; 254 std::string Expected = R"cc( 255 template <typename T> 256 T bad(T x) { 257 return x; 258 } 259 int neutral(int x) { return good<int>(x) * x; } 260 )cc"; 261 262 StringRef Ref = "ref"; 263 testRule(makeRule(declRefExpr(to(functionDecl(hasName("bad")))).bind(Ref), 264 changeTo(name(std::string(Ref)), cat("good"))), 265 Input, Expected); 266 } 267 268 TEST_F(TransformerTest, NodePartNameDeclRefFailure) { 269 std::string Input = R"cc( 270 struct Y { 271 int operator*(); 272 }; 273 int neutral(int x) { 274 Y y; 275 int (Y::*ptr)() = &Y::operator*; 276 return *y + x; 277 } 278 )cc"; 279 280 StringRef Ref = "ref"; 281 Transformer T(makeRule(declRefExpr(to(functionDecl())).bind(Ref), 282 changeTo(name(std::string(Ref)), cat("good"))), 283 consumer()); 284 T.registerMatchers(&MatchFinder); 285 EXPECT_FALSE(rewrite(Input)); 286 } 287 288 TEST_F(TransformerTest, NodePartMember) { 289 StringRef E = "expr"; 290 RewriteRule Rule = makeRule(memberExpr(member(hasName("bad"))).bind(E), 291 changeTo(member(std::string(E)), cat("good"))); 292 293 std::string Input = R"cc( 294 struct S { 295 int bad; 296 }; 297 int g() { 298 S s; 299 return s.bad; 300 } 301 )cc"; 302 std::string Expected = R"cc( 303 struct S { 304 int bad; 305 }; 306 int g() { 307 S s; 308 return s.good; 309 } 310 )cc"; 311 312 testRule(Rule, Input, Expected); 313 } 314 315 TEST_F(TransformerTest, NodePartMemberQualified) { 316 std::string Input = R"cc( 317 struct S { 318 int bad; 319 int good; 320 }; 321 struct T : public S { 322 int bad; 323 }; 324 int g() { 325 T t; 326 return t.S::bad; 327 } 328 )cc"; 329 std::string Expected = R"cc( 330 struct S { 331 int bad; 332 int good; 333 }; 334 struct T : public S { 335 int bad; 336 }; 337 int g() { 338 T t; 339 return t.S::good; 340 } 341 )cc"; 342 343 StringRef E = "expr"; 344 testRule(makeRule(memberExpr().bind(E), 345 changeTo(member(std::string(E)), cat("good"))), 346 Input, Expected); 347 } 348 349 TEST_F(TransformerTest, NodePartMemberMultiToken) { 350 std::string Input = R"cc( 351 struct Y { 352 int operator*(); 353 int good(); 354 template <typename T> void foo(T t); 355 }; 356 int neutral(int x) { 357 Y y; 358 y.template foo<int>(3); 359 return y.operator *(); 360 } 361 )cc"; 362 std::string Expected = R"cc( 363 struct Y { 364 int operator*(); 365 int good(); 366 template <typename T> void foo(T t); 367 }; 368 int neutral(int x) { 369 Y y; 370 y.template good<int>(3); 371 return y.good(); 372 } 373 )cc"; 374 375 StringRef MemExpr = "member"; 376 testRule(makeRule(memberExpr().bind(MemExpr), 377 changeTo(member(std::string(MemExpr)), cat("good"))), 378 Input, Expected); 379 } 380 381 TEST_F(TransformerTest, InsertBeforeEdit) { 382 std::string Input = R"cc( 383 int f() { 384 return 7; 385 } 386 )cc"; 387 std::string Expected = R"cc( 388 int f() { 389 int y = 3; 390 return 7; 391 } 392 )cc"; 393 394 StringRef Ret = "return"; 395 testRule( 396 makeRule(returnStmt().bind(Ret), 397 insertBefore(statement(std::string(Ret)), cat("int y = 3;"))), 398 Input, Expected); 399 } 400 401 TEST_F(TransformerTest, InsertAfterEdit) { 402 std::string Input = R"cc( 403 int f() { 404 int x = 5; 405 return 7; 406 } 407 )cc"; 408 std::string Expected = R"cc( 409 int f() { 410 int x = 5; 411 int y = 3; 412 return 7; 413 } 414 )cc"; 415 416 StringRef Decl = "decl"; 417 testRule( 418 makeRule(declStmt().bind(Decl), 419 insertAfter(statement(std::string(Decl)), cat("int y = 3;"))), 420 Input, Expected); 421 } 422 423 TEST_F(TransformerTest, RemoveEdit) { 424 std::string Input = R"cc( 425 int f() { 426 int x = 5; 427 return 7; 428 } 429 )cc"; 430 std::string Expected = R"cc( 431 int f() { 432 return 7; 433 } 434 )cc"; 435 436 StringRef Decl = "decl"; 437 testRule( 438 makeRule(declStmt().bind(Decl), remove(statement(std::string(Decl)))), 439 Input, Expected); 440 } 441 442 TEST_F(TransformerTest, WithMetadata) { 443 std::string Input = R"cc( 444 int f() { 445 int x = 5; 446 return 7; 447 } 448 )cc"; 449 450 Transformer T( 451 makeRule(declStmt().bind("decl"), 452 withMetadata(remove(statement(std::string("decl"))), 17)), 453 consumer()); 454 T.registerMatchers(&MatchFinder); 455 auto Factory = newFrontendActionFactory(&MatchFinder); 456 EXPECT_TRUE(runToolOnCodeWithArgs( 457 Factory->create(), Input, std::vector<std::string>(), "input.cc", 458 "clang-tool", std::make_shared<PCHContainerOperations>(), {})); 459 ASSERT_EQ(Changes.size(), 1u); 460 const llvm::Any &Metadata = Changes[0].getMetadata(); 461 ASSERT_TRUE(llvm::any_isa<int>(Metadata)); 462 EXPECT_THAT(llvm::any_cast<int>(Metadata), 17); 463 } 464 465 TEST_F(TransformerTest, MultiChange) { 466 std::string Input = R"cc( 467 void foo() { 468 if (10 > 1.0) 469 log(1) << "oh no!"; 470 else 471 log(0) << "ok"; 472 } 473 )cc"; 474 std::string Expected = R"( 475 void foo() { 476 if (true) { /* then */ } 477 else { /* else */ } 478 } 479 )"; 480 481 StringRef C = "C", T = "T", E = "E"; 482 testRule( 483 makeRule(ifStmt(hasCondition(expr().bind(C)), hasThen(stmt().bind(T)), 484 hasElse(stmt().bind(E))), 485 {changeTo(node(std::string(C)), cat("true")), 486 changeTo(statement(std::string(T)), cat("{ /* then */ }")), 487 changeTo(statement(std::string(E)), cat("{ /* else */ }"))}), 488 Input, Expected); 489 } 490 491 TEST_F(TransformerTest, OrderedRuleUnrelated) { 492 StringRef Flag = "flag"; 493 RewriteRule FlagRule = makeRule( 494 cxxMemberCallExpr(on(expr(hasType(cxxRecordDecl( 495 hasName("proto::ProtoCommandLineFlag")))) 496 .bind(Flag)), 497 unless(callee(cxxMethodDecl(hasName("GetProto"))))), 498 changeTo(node(std::string(Flag)), cat("PROTO"))); 499 500 std::string Input = R"cc( 501 proto::ProtoCommandLineFlag flag; 502 int x = flag.foo(); 503 int y = flag.GetProto().foo(); 504 int f(string s) { return strlen(s.c_str()); } 505 )cc"; 506 std::string Expected = R"cc( 507 proto::ProtoCommandLineFlag flag; 508 int x = PROTO.foo(); 509 int y = flag.GetProto().foo(); 510 int f(string s) { return REPLACED; } 511 )cc"; 512 513 testRule(applyFirst({ruleStrlenSize(), FlagRule}), Input, Expected); 514 } 515 516 TEST_F(TransformerTest, OrderedRuleRelated) { 517 std::string Input = R"cc( 518 void f1(); 519 void f2(); 520 void call_f1() { f1(); } 521 void call_f2() { f2(); } 522 )cc"; 523 std::string Expected = R"cc( 524 void f1(); 525 void f2(); 526 void call_f1() { REPLACE_F1; } 527 void call_f2() { REPLACE_F1_OR_F2; } 528 )cc"; 529 530 RewriteRule ReplaceF1 = 531 makeRule(callExpr(callee(functionDecl(hasName("f1")))), 532 changeTo(cat("REPLACE_F1"))); 533 RewriteRule ReplaceF1OrF2 = 534 makeRule(callExpr(callee(functionDecl(hasAnyName("f1", "f2")))), 535 changeTo(cat("REPLACE_F1_OR_F2"))); 536 testRule(applyFirst({ReplaceF1, ReplaceF1OrF2}), Input, Expected); 537 } 538 539 // Change the order of the rules to get a different result. When `ReplaceF1OrF2` 540 // comes first, it applies for both uses, so `ReplaceF1` never applies. 541 TEST_F(TransformerTest, OrderedRuleRelatedSwapped) { 542 std::string Input = R"cc( 543 void f1(); 544 void f2(); 545 void call_f1() { f1(); } 546 void call_f2() { f2(); } 547 )cc"; 548 std::string Expected = R"cc( 549 void f1(); 550 void f2(); 551 void call_f1() { REPLACE_F1_OR_F2; } 552 void call_f2() { REPLACE_F1_OR_F2; } 553 )cc"; 554 555 RewriteRule ReplaceF1 = 556 makeRule(callExpr(callee(functionDecl(hasName("f1")))), 557 changeTo(cat("REPLACE_F1"))); 558 RewriteRule ReplaceF1OrF2 = 559 makeRule(callExpr(callee(functionDecl(hasAnyName("f1", "f2")))), 560 changeTo(cat("REPLACE_F1_OR_F2"))); 561 testRule(applyFirst({ReplaceF1OrF2, ReplaceF1}), Input, Expected); 562 } 563 564 // Verify that a set of rules whose matchers have different base kinds works 565 // properly, including that `applyFirst` produces multiple matchers. We test 566 // two different kinds of rules: Expr and Decl. We place the Decl rule in the 567 // middle to test that `buildMatchers` works even when the kinds aren't grouped 568 // together. 569 TEST_F(TransformerTest, OrderedRuleMultipleKinds) { 570 std::string Input = R"cc( 571 void f1(); 572 void f2(); 573 void call_f1() { f1(); } 574 void call_f2() { f2(); } 575 )cc"; 576 std::string Expected = R"cc( 577 void f1(); 578 void DECL_RULE(); 579 void call_f1() { REPLACE_F1; } 580 void call_f2() { REPLACE_F1_OR_F2; } 581 )cc"; 582 583 RewriteRule ReplaceF1 = 584 makeRule(callExpr(callee(functionDecl(hasName("f1")))), 585 changeTo(cat("REPLACE_F1"))); 586 RewriteRule ReplaceF1OrF2 = 587 makeRule(callExpr(callee(functionDecl(hasAnyName("f1", "f2")))), 588 changeTo(cat("REPLACE_F1_OR_F2"))); 589 RewriteRule DeclRule = makeRule(functionDecl(hasName("f2")).bind("fun"), 590 changeTo(name("fun"), cat("DECL_RULE"))); 591 592 RewriteRule Rule = applyFirst({ReplaceF1, DeclRule, ReplaceF1OrF2}); 593 EXPECT_EQ(transformer::detail::buildMatchers(Rule).size(), 2UL); 594 testRule(Rule, Input, Expected); 595 } 596 597 // Verifies that a rule with a top-level matcher for an implicit node (like 598 // `implicitCastExpr`) does not change the code, when the AST traversal skips 599 // implicit nodes. In this test, only the rule with the explicit-node matcher 600 // will fire. 601 TEST_F(TransformerTest, OrderedRuleImplicitIgnored) { 602 std::string Input = R"cc( 603 void f1(); 604 int f2(); 605 void call_f1() { f1(); } 606 float call_f2() { return f2(); } 607 )cc"; 608 std::string Expected = R"cc( 609 void f1(); 610 int f2(); 611 void call_f1() { REPLACE_F1; } 612 float call_f2() { return f2(); } 613 )cc"; 614 615 RewriteRule ReplaceF1 = 616 makeRule(callExpr(callee(functionDecl(hasName("f1")))), 617 changeTo(cat("REPLACE_F1"))); 618 RewriteRule ReplaceF2 = 619 makeRule(implicitCastExpr(hasSourceExpression(callExpr())), 620 changeTo(cat("REPLACE_F2"))); 621 testRule(applyFirst({ReplaceF1, ReplaceF2}), Input, Expected); 622 } 623 624 // Verifies that explicitly setting the traversal kind fixes the problem in the 625 // previous test. 626 TEST_F(TransformerTest, OrderedRuleImplicitMatched) { 627 std::string Input = R"cc( 628 void f1(); 629 int f2(); 630 void call_f1() { f1(); } 631 float call_f2() { return f2(); } 632 )cc"; 633 std::string Expected = R"cc( 634 void f1(); 635 int f2(); 636 void call_f1() { REPLACE_F1; } 637 float call_f2() { return REPLACE_F2; } 638 )cc"; 639 640 RewriteRule ReplaceF1 = makeRule( 641 traverse(clang::TK_AsIs, callExpr(callee(functionDecl(hasName("f1"))))), 642 changeTo(cat("REPLACE_F1"))); 643 RewriteRule ReplaceF2 = 644 makeRule(traverse(clang::TK_AsIs, 645 implicitCastExpr(hasSourceExpression(callExpr()))), 646 changeTo(cat("REPLACE_F2"))); 647 testRule(applyFirst({ReplaceF1, ReplaceF2}), Input, Expected); 648 } 649 650 // 651 // Negative tests (where we expect no transformation to occur). 652 // 653 654 // Tests for a conflict in edits from a single match for a rule. 655 TEST_F(TransformerTest, TextGeneratorFailure) { 656 std::string Input = "int conflictOneRule() { return 3 + 7; }"; 657 // Try to change the whole binary-operator expression AND one its operands: 658 StringRef O = "O"; 659 class AlwaysFail : public transformer::MatchComputation<std::string> { 660 llvm::Error eval(const ast_matchers::MatchFinder::MatchResult &, 661 std::string *) const override { 662 return llvm::createStringError(llvm::errc::invalid_argument, "ERROR"); 663 } 664 std::string toString() const override { return "AlwaysFail"; } 665 }; 666 Transformer T( 667 makeRule(binaryOperator().bind(O), 668 changeTo(node(std::string(O)), std::make_shared<AlwaysFail>())), 669 consumer()); 670 T.registerMatchers(&MatchFinder); 671 EXPECT_FALSE(rewrite(Input)); 672 EXPECT_THAT(Changes, IsEmpty()); 673 EXPECT_EQ(ErrorCount, 1); 674 } 675 676 // Tests for a conflict in edits from a single match for a rule. 677 TEST_F(TransformerTest, OverlappingEditsInRule) { 678 std::string Input = "int conflictOneRule() { return 3 + 7; }"; 679 // Try to change the whole binary-operator expression AND one its operands: 680 StringRef O = "O", L = "L"; 681 Transformer T(makeRule(binaryOperator(hasLHS(expr().bind(L))).bind(O), 682 {changeTo(node(std::string(O)), cat("DELETE_OP")), 683 changeTo(node(std::string(L)), cat("DELETE_LHS"))}), 684 consumer()); 685 T.registerMatchers(&MatchFinder); 686 EXPECT_FALSE(rewrite(Input)); 687 EXPECT_THAT(Changes, IsEmpty()); 688 EXPECT_EQ(ErrorCount, 1); 689 } 690 691 // Tests for a conflict in edits across multiple matches (of the same rule). 692 TEST_F(TransformerTest, OverlappingEditsMultipleMatches) { 693 std::string Input = "int conflictOneRule() { return -7; }"; 694 // Try to change the whole binary-operator expression AND one its operands: 695 StringRef E = "E"; 696 Transformer T(makeRule(expr().bind(E), 697 changeTo(node(std::string(E)), cat("DELETE_EXPR"))), 698 consumer()); 699 T.registerMatchers(&MatchFinder); 700 // The rewrite process fails because the changes conflict with each other... 701 EXPECT_FALSE(rewrite(Input)); 702 // ... but two changes were produced. 703 EXPECT_EQ(Changes.size(), 2u); 704 EXPECT_EQ(ErrorCount, 0); 705 } 706 707 TEST_F(TransformerTest, ErrorOccurredMatchSkipped) { 708 // Syntax error in the function body: 709 std::string Input = "void errorOccurred() { 3 }"; 710 Transformer T(makeRule(functionDecl(hasName("errorOccurred")), 711 changeTo(cat("DELETED;"))), 712 consumer()); 713 T.registerMatchers(&MatchFinder); 714 // The rewrite process itself fails... 715 EXPECT_FALSE(rewrite(Input)); 716 // ... and no changes or errors are produced in the process. 717 EXPECT_THAT(Changes, IsEmpty()); 718 EXPECT_EQ(ErrorCount, 0); 719 } 720 721 // Transformation of macro source text when the change encompasses the entirety 722 // of the expanded text. 723 TEST_F(TransformerTest, SimpleMacro) { 724 std::string Input = R"cc( 725 #define ZERO 0 726 int f(string s) { return ZERO; } 727 )cc"; 728 std::string Expected = R"cc( 729 #define ZERO 0 730 int f(string s) { return 999; } 731 )cc"; 732 733 StringRef zero = "zero"; 734 RewriteRule R = makeRule(integerLiteral(equals(0)).bind(zero), 735 changeTo(node(std::string(zero)), cat("999"))); 736 testRule(R, Input, Expected); 737 } 738 739 // Transformation of macro source text when the change encompasses the entirety 740 // of the expanded text, for the case of function-style macros. 741 TEST_F(TransformerTest, FunctionMacro) { 742 std::string Input = R"cc( 743 #define MACRO(str) strlen((str).c_str()) 744 int f(string s) { return MACRO(s); } 745 )cc"; 746 std::string Expected = R"cc( 747 #define MACRO(str) strlen((str).c_str()) 748 int f(string s) { return REPLACED; } 749 )cc"; 750 751 testRule(ruleStrlenSize(), Input, Expected); 752 } 753 754 // Tests that expressions in macro arguments can be rewritten. 755 TEST_F(TransformerTest, MacroArg) { 756 std::string Input = R"cc( 757 #define PLUS(e) e + 1 758 int f(string s) { return PLUS(strlen(s.c_str())); } 759 )cc"; 760 std::string Expected = R"cc( 761 #define PLUS(e) e + 1 762 int f(string s) { return PLUS(REPLACED); } 763 )cc"; 764 765 testRule(ruleStrlenSize(), Input, Expected); 766 } 767 768 // Tests that expressions in macro arguments can be rewritten, even when the 769 // macro call occurs inside another macro's definition. 770 TEST_F(TransformerTest, MacroArgInMacroDef) { 771 std::string Input = R"cc( 772 #define NESTED(e) e 773 #define MACRO(str) NESTED(strlen((str).c_str())) 774 int f(string s) { return MACRO(s); } 775 )cc"; 776 std::string Expected = R"cc( 777 #define NESTED(e) e 778 #define MACRO(str) NESTED(strlen((str).c_str())) 779 int f(string s) { return REPLACED; } 780 )cc"; 781 782 testRule(ruleStrlenSize(), Input, Expected); 783 } 784 785 // Tests the corner case of the identity macro, specifically that it is 786 // discarded in the rewrite rather than preserved (like PLUS is preserved in the 787 // previous test). This behavior is of dubious value (and marked with a FIXME 788 // in the code), but we test it to verify (and demonstrate) how this case is 789 // handled. 790 TEST_F(TransformerTest, IdentityMacro) { 791 std::string Input = R"cc( 792 #define ID(e) e 793 int f(string s) { return ID(strlen(s.c_str())); } 794 )cc"; 795 std::string Expected = R"cc( 796 #define ID(e) e 797 int f(string s) { return REPLACED; } 798 )cc"; 799 800 testRule(ruleStrlenSize(), Input, Expected); 801 } 802 803 // Tests that two changes in a single macro expansion do not lead to conflicts 804 // in applying the changes. 805 TEST_F(TransformerTest, TwoChangesInOneMacroExpansion) { 806 std::string Input = R"cc( 807 #define PLUS(a,b) (a) + (b) 808 int f() { return PLUS(3, 4); } 809 )cc"; 810 std::string Expected = R"cc( 811 #define PLUS(a,b) (a) + (b) 812 int f() { return PLUS(LIT, LIT); } 813 )cc"; 814 815 testRule(makeRule(integerLiteral(), changeTo(cat("LIT"))), Input, Expected); 816 } 817 818 // Tests case where the rule's match spans both source from the macro and its 819 // arg, with the begin location (the "anchor") being the arg. 820 TEST_F(TransformerTest, MatchSpansMacroTextButChangeDoesNot) { 821 std::string Input = R"cc( 822 #define PLUS_ONE(a) a + 1 823 int f() { return PLUS_ONE(3); } 824 )cc"; 825 std::string Expected = R"cc( 826 #define PLUS_ONE(a) a + 1 827 int f() { return PLUS_ONE(LIT); } 828 )cc"; 829 830 StringRef E = "expr"; 831 testRule(makeRule(binaryOperator(hasLHS(expr().bind(E))), 832 changeTo(node(std::string(E)), cat("LIT"))), 833 Input, Expected); 834 } 835 836 // Tests case where the rule's match spans both source from the macro and its 837 // arg, with the begin location (the "anchor") being inside the macro. 838 TEST_F(TransformerTest, MatchSpansMacroTextButChangeDoesNotAnchoredInMacro) { 839 std::string Input = R"cc( 840 #define PLUS_ONE(a) 1 + a 841 int f() { return PLUS_ONE(3); } 842 )cc"; 843 std::string Expected = R"cc( 844 #define PLUS_ONE(a) 1 + a 845 int f() { return PLUS_ONE(LIT); } 846 )cc"; 847 848 StringRef E = "expr"; 849 testRule(makeRule(binaryOperator(hasRHS(expr().bind(E))), 850 changeTo(node(std::string(E)), cat("LIT"))), 851 Input, Expected); 852 } 853 854 // No rewrite is applied when the changed text does not encompass the entirety 855 // of the expanded text. That is, the edit would have to be applied to the 856 // macro's definition to succeed and editing the expansion point would not 857 // suffice. 858 TEST_F(TransformerTest, NoPartialRewriteOMacroExpansion) { 859 std::string Input = R"cc( 860 #define ZERO_PLUS 0 + 3 861 int f(string s) { return ZERO_PLUS; })cc"; 862 863 StringRef zero = "zero"; 864 RewriteRule R = makeRule(integerLiteral(equals(0)).bind(zero), 865 changeTo(node(std::string(zero)), cat("0"))); 866 testRule(R, Input, Input); 867 } 868 869 // This test handles the corner case where a macro expands within another macro 870 // to matching code, but that code is an argument to the nested macro call. A 871 // simple check of isMacroArgExpansion() vs. isMacroBodyExpansion() will get 872 // this wrong, and transform the code. 873 TEST_F(TransformerTest, NoPartialRewriteOfMacroExpansionForMacroArgs) { 874 std::string Input = R"cc( 875 #define NESTED(e) e 876 #define MACRO(str) 1 + NESTED(strlen((str).c_str())) 877 int f(string s) { return MACRO(s); } 878 )cc"; 879 880 testRule(ruleStrlenSize(), Input, Input); 881 } 882 883 #if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST 884 // Verifies that `Type` and `QualType` are not allowed as top-level matchers in 885 // rules. 886 TEST(TransformerDeathTest, OrderedRuleTypes) { 887 RewriteRule QualTypeRule = makeRule(qualType(), changeTo(cat("Q"))); 888 EXPECT_DEATH(transformer::detail::buildMatchers(QualTypeRule), 889 "Matcher must be.*node matcher"); 890 891 RewriteRule TypeRule = makeRule(arrayType(), changeTo(cat("T"))); 892 EXPECT_DEATH(transformer::detail::buildMatchers(TypeRule), 893 "Matcher must be.*node matcher"); 894 } 895 #endif 896 897 // Edits are able to span multiple files; in this case, a header and an 898 // implementation file. 899 TEST_F(TransformerTest, MultipleFiles) { 900 std::string Header = R"cc(void RemoveThisFunction();)cc"; 901 std::string Source = R"cc(#include "input.h" 902 void RemoveThisFunction();)cc"; 903 Transformer T( 904 makeRule(functionDecl(hasName("RemoveThisFunction")), changeTo(cat(""))), 905 consumer()); 906 T.registerMatchers(&MatchFinder); 907 auto Factory = newFrontendActionFactory(&MatchFinder); 908 EXPECT_TRUE(runToolOnCodeWithArgs( 909 Factory->create(), Source, std::vector<std::string>(), "input.cc", 910 "clang-tool", std::make_shared<PCHContainerOperations>(), 911 {{"input.h", Header}})); 912 913 std::sort(Changes.begin(), Changes.end(), 914 [](const AtomicChange &L, const AtomicChange &R) { 915 return L.getFilePath() < R.getFilePath(); 916 }); 917 918 ASSERT_EQ(Changes[0].getFilePath(), "./input.h"); 919 EXPECT_THAT(Changes[0].getInsertedHeaders(), IsEmpty()); 920 EXPECT_THAT(Changes[0].getRemovedHeaders(), IsEmpty()); 921 llvm::Expected<std::string> UpdatedCode = 922 clang::tooling::applyAllReplacements(Header, 923 Changes[0].getReplacements()); 924 ASSERT_TRUE(static_cast<bool>(UpdatedCode)) 925 << "Could not update code: " << llvm::toString(UpdatedCode.takeError()); 926 EXPECT_EQ(format(*UpdatedCode), format(R"cc(;)cc")); 927 928 ASSERT_EQ(Changes[1].getFilePath(), "input.cc"); 929 EXPECT_THAT(Changes[1].getInsertedHeaders(), IsEmpty()); 930 EXPECT_THAT(Changes[1].getRemovedHeaders(), IsEmpty()); 931 UpdatedCode = clang::tooling::applyAllReplacements( 932 Source, Changes[1].getReplacements()); 933 ASSERT_TRUE(static_cast<bool>(UpdatedCode)) 934 << "Could not update code: " << llvm::toString(UpdatedCode.takeError()); 935 EXPECT_EQ(format(*UpdatedCode), format(R"cc(#include "input.h" 936 ;)cc")); 937 } 938 } // namespace 939