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, MultiChange) { 443 std::string Input = R"cc( 444 void foo() { 445 if (10 > 1.0) 446 log(1) << "oh no!"; 447 else 448 log(0) << "ok"; 449 } 450 )cc"; 451 std::string Expected = R"( 452 void foo() { 453 if (true) { /* then */ } 454 else { /* else */ } 455 } 456 )"; 457 458 StringRef C = "C", T = "T", E = "E"; 459 testRule( 460 makeRule(ifStmt(hasCondition(expr().bind(C)), hasThen(stmt().bind(T)), 461 hasElse(stmt().bind(E))), 462 {changeTo(node(std::string(C)), cat("true")), 463 changeTo(statement(std::string(T)), cat("{ /* then */ }")), 464 changeTo(statement(std::string(E)), cat("{ /* else */ }"))}), 465 Input, Expected); 466 } 467 468 TEST_F(TransformerTest, OrderedRuleUnrelated) { 469 StringRef Flag = "flag"; 470 RewriteRule FlagRule = makeRule( 471 cxxMemberCallExpr(on(expr(hasType(cxxRecordDecl( 472 hasName("proto::ProtoCommandLineFlag")))) 473 .bind(Flag)), 474 unless(callee(cxxMethodDecl(hasName("GetProto"))))), 475 changeTo(node(std::string(Flag)), cat("PROTO"))); 476 477 std::string Input = R"cc( 478 proto::ProtoCommandLineFlag flag; 479 int x = flag.foo(); 480 int y = flag.GetProto().foo(); 481 int f(string s) { return strlen(s.c_str()); } 482 )cc"; 483 std::string Expected = R"cc( 484 proto::ProtoCommandLineFlag flag; 485 int x = PROTO.foo(); 486 int y = flag.GetProto().foo(); 487 int f(string s) { return REPLACED; } 488 )cc"; 489 490 testRule(applyFirst({ruleStrlenSize(), FlagRule}), Input, Expected); 491 } 492 493 TEST_F(TransformerTest, OrderedRuleRelated) { 494 std::string Input = R"cc( 495 void f1(); 496 void f2(); 497 void call_f1() { f1(); } 498 void call_f2() { f2(); } 499 )cc"; 500 std::string Expected = R"cc( 501 void f1(); 502 void f2(); 503 void call_f1() { REPLACE_F1; } 504 void call_f2() { REPLACE_F1_OR_F2; } 505 )cc"; 506 507 RewriteRule ReplaceF1 = 508 makeRule(callExpr(callee(functionDecl(hasName("f1")))), 509 changeTo(cat("REPLACE_F1"))); 510 RewriteRule ReplaceF1OrF2 = 511 makeRule(callExpr(callee(functionDecl(hasAnyName("f1", "f2")))), 512 changeTo(cat("REPLACE_F1_OR_F2"))); 513 testRule(applyFirst({ReplaceF1, ReplaceF1OrF2}), Input, Expected); 514 } 515 516 // Change the order of the rules to get a different result. When `ReplaceF1OrF2` 517 // comes first, it applies for both uses, so `ReplaceF1` never applies. 518 TEST_F(TransformerTest, OrderedRuleRelatedSwapped) { 519 std::string Input = R"cc( 520 void f1(); 521 void f2(); 522 void call_f1() { f1(); } 523 void call_f2() { f2(); } 524 )cc"; 525 std::string Expected = R"cc( 526 void f1(); 527 void f2(); 528 void call_f1() { REPLACE_F1_OR_F2; } 529 void call_f2() { REPLACE_F1_OR_F2; } 530 )cc"; 531 532 RewriteRule ReplaceF1 = 533 makeRule(callExpr(callee(functionDecl(hasName("f1")))), 534 changeTo(cat("REPLACE_F1"))); 535 RewriteRule ReplaceF1OrF2 = 536 makeRule(callExpr(callee(functionDecl(hasAnyName("f1", "f2")))), 537 changeTo(cat("REPLACE_F1_OR_F2"))); 538 testRule(applyFirst({ReplaceF1OrF2, ReplaceF1}), Input, Expected); 539 } 540 541 // Verify that a set of rules whose matchers have different base kinds works 542 // properly, including that `applyFirst` produces multiple matchers. We test 543 // two different kinds of rules: Expr and Decl. We place the Decl rule in the 544 // middle to test that `buildMatchers` works even when the kinds aren't grouped 545 // together. 546 TEST_F(TransformerTest, OrderedRuleMultipleKinds) { 547 std::string Input = R"cc( 548 void f1(); 549 void f2(); 550 void call_f1() { f1(); } 551 void call_f2() { f2(); } 552 )cc"; 553 std::string Expected = R"cc( 554 void f1(); 555 void DECL_RULE(); 556 void call_f1() { REPLACE_F1; } 557 void call_f2() { REPLACE_F1_OR_F2; } 558 )cc"; 559 560 RewriteRule ReplaceF1 = 561 makeRule(callExpr(callee(functionDecl(hasName("f1")))), 562 changeTo(cat("REPLACE_F1"))); 563 RewriteRule ReplaceF1OrF2 = 564 makeRule(callExpr(callee(functionDecl(hasAnyName("f1", "f2")))), 565 changeTo(cat("REPLACE_F1_OR_F2"))); 566 RewriteRule DeclRule = makeRule(functionDecl(hasName("f2")).bind("fun"), 567 changeTo(name("fun"), cat("DECL_RULE"))); 568 569 RewriteRule Rule = applyFirst({ReplaceF1, DeclRule, ReplaceF1OrF2}); 570 EXPECT_EQ(transformer::detail::buildMatchers(Rule).size(), 2UL); 571 testRule(Rule, Input, Expected); 572 } 573 574 // 575 // Negative tests (where we expect no transformation to occur). 576 // 577 578 // Tests for a conflict in edits from a single match for a rule. 579 TEST_F(TransformerTest, TextGeneratorFailure) { 580 std::string Input = "int conflictOneRule() { return 3 + 7; }"; 581 // Try to change the whole binary-operator expression AND one its operands: 582 StringRef O = "O"; 583 class AlwaysFail : public transformer::MatchComputation<std::string> { 584 llvm::Error eval(const ast_matchers::MatchFinder::MatchResult &, 585 std::string *) const override { 586 return llvm::createStringError(llvm::errc::invalid_argument, "ERROR"); 587 } 588 std::string toString() const override { return "AlwaysFail"; } 589 }; 590 Transformer T( 591 makeRule(binaryOperator().bind(O), 592 changeTo(node(std::string(O)), std::make_shared<AlwaysFail>())), 593 consumer()); 594 T.registerMatchers(&MatchFinder); 595 EXPECT_FALSE(rewrite(Input)); 596 EXPECT_THAT(Changes, IsEmpty()); 597 EXPECT_EQ(ErrorCount, 1); 598 } 599 600 // Tests for a conflict in edits from a single match for a rule. 601 TEST_F(TransformerTest, OverlappingEditsInRule) { 602 std::string Input = "int conflictOneRule() { return 3 + 7; }"; 603 // Try to change the whole binary-operator expression AND one its operands: 604 StringRef O = "O", L = "L"; 605 Transformer T(makeRule(binaryOperator(hasLHS(expr().bind(L))).bind(O), 606 {changeTo(node(std::string(O)), cat("DELETE_OP")), 607 changeTo(node(std::string(L)), cat("DELETE_LHS"))}), 608 consumer()); 609 T.registerMatchers(&MatchFinder); 610 EXPECT_FALSE(rewrite(Input)); 611 EXPECT_THAT(Changes, IsEmpty()); 612 EXPECT_EQ(ErrorCount, 1); 613 } 614 615 // Tests for a conflict in edits across multiple matches (of the same rule). 616 TEST_F(TransformerTest, OverlappingEditsMultipleMatches) { 617 std::string Input = "int conflictOneRule() { return -7; }"; 618 // Try to change the whole binary-operator expression AND one its operands: 619 StringRef E = "E"; 620 Transformer T(makeRule(expr().bind(E), 621 changeTo(node(std::string(E)), cat("DELETE_EXPR"))), 622 consumer()); 623 T.registerMatchers(&MatchFinder); 624 // The rewrite process fails because the changes conflict with each other... 625 EXPECT_FALSE(rewrite(Input)); 626 // ... but two changes were produced. 627 EXPECT_EQ(Changes.size(), 2u); 628 EXPECT_EQ(ErrorCount, 0); 629 } 630 631 TEST_F(TransformerTest, ErrorOccurredMatchSkipped) { 632 // Syntax error in the function body: 633 std::string Input = "void errorOccurred() { 3 }"; 634 Transformer T(makeRule(functionDecl(hasName("errorOccurred")), 635 changeTo(cat("DELETED;"))), 636 consumer()); 637 T.registerMatchers(&MatchFinder); 638 // The rewrite process itself fails... 639 EXPECT_FALSE(rewrite(Input)); 640 // ... and no changes or errors are produced in the process. 641 EXPECT_THAT(Changes, IsEmpty()); 642 EXPECT_EQ(ErrorCount, 0); 643 } 644 645 // Transformation of macro source text when the change encompasses the entirety 646 // of the expanded text. 647 TEST_F(TransformerTest, SimpleMacro) { 648 std::string Input = R"cc( 649 #define ZERO 0 650 int f(string s) { return ZERO; } 651 )cc"; 652 std::string Expected = R"cc( 653 #define ZERO 0 654 int f(string s) { return 999; } 655 )cc"; 656 657 StringRef zero = "zero"; 658 RewriteRule R = makeRule(integerLiteral(equals(0)).bind(zero), 659 changeTo(node(std::string(zero)), cat("999"))); 660 testRule(R, Input, Expected); 661 } 662 663 // Transformation of macro source text when the change encompasses the entirety 664 // of the expanded text, for the case of function-style macros. 665 TEST_F(TransformerTest, FunctionMacro) { 666 std::string Input = R"cc( 667 #define MACRO(str) strlen((str).c_str()) 668 int f(string s) { return MACRO(s); } 669 )cc"; 670 std::string Expected = R"cc( 671 #define MACRO(str) strlen((str).c_str()) 672 int f(string s) { return REPLACED; } 673 )cc"; 674 675 testRule(ruleStrlenSize(), Input, Expected); 676 } 677 678 // Tests that expressions in macro arguments can be rewritten. 679 TEST_F(TransformerTest, MacroArg) { 680 std::string Input = R"cc( 681 #define PLUS(e) e + 1 682 int f(string s) { return PLUS(strlen(s.c_str())); } 683 )cc"; 684 std::string Expected = R"cc( 685 #define PLUS(e) e + 1 686 int f(string s) { return PLUS(REPLACED); } 687 )cc"; 688 689 testRule(ruleStrlenSize(), Input, Expected); 690 } 691 692 // Tests that expressions in macro arguments can be rewritten, even when the 693 // macro call occurs inside another macro's definition. 694 TEST_F(TransformerTest, MacroArgInMacroDef) { 695 std::string Input = R"cc( 696 #define NESTED(e) e 697 #define MACRO(str) NESTED(strlen((str).c_str())) 698 int f(string s) { return MACRO(s); } 699 )cc"; 700 std::string Expected = R"cc( 701 #define NESTED(e) e 702 #define MACRO(str) NESTED(strlen((str).c_str())) 703 int f(string s) { return REPLACED; } 704 )cc"; 705 706 testRule(ruleStrlenSize(), Input, Expected); 707 } 708 709 // Tests the corner case of the identity macro, specifically that it is 710 // discarded in the rewrite rather than preserved (like PLUS is preserved in the 711 // previous test). This behavior is of dubious value (and marked with a FIXME 712 // in the code), but we test it to verify (and demonstrate) how this case is 713 // handled. 714 TEST_F(TransformerTest, IdentityMacro) { 715 std::string Input = R"cc( 716 #define ID(e) e 717 int f(string s) { return ID(strlen(s.c_str())); } 718 )cc"; 719 std::string Expected = R"cc( 720 #define ID(e) e 721 int f(string s) { return REPLACED; } 722 )cc"; 723 724 testRule(ruleStrlenSize(), Input, Expected); 725 } 726 727 // Tests that two changes in a single macro expansion do not lead to conflicts 728 // in applying the changes. 729 TEST_F(TransformerTest, TwoChangesInOneMacroExpansion) { 730 std::string Input = R"cc( 731 #define PLUS(a,b) (a) + (b) 732 int f() { return PLUS(3, 4); } 733 )cc"; 734 std::string Expected = R"cc( 735 #define PLUS(a,b) (a) + (b) 736 int f() { return PLUS(LIT, LIT); } 737 )cc"; 738 739 testRule(makeRule(integerLiteral(), changeTo(cat("LIT"))), Input, Expected); 740 } 741 742 // Tests case where the rule's match spans both source from the macro and its 743 // arg, with the begin location (the "anchor") being the arg. 744 TEST_F(TransformerTest, MatchSpansMacroTextButChangeDoesNot) { 745 std::string Input = R"cc( 746 #define PLUS_ONE(a) a + 1 747 int f() { return PLUS_ONE(3); } 748 )cc"; 749 std::string Expected = R"cc( 750 #define PLUS_ONE(a) a + 1 751 int f() { return PLUS_ONE(LIT); } 752 )cc"; 753 754 StringRef E = "expr"; 755 testRule(makeRule(binaryOperator(hasLHS(expr().bind(E))), 756 changeTo(node(std::string(E)), cat("LIT"))), 757 Input, Expected); 758 } 759 760 // Tests case where the rule's match spans both source from the macro and its 761 // arg, with the begin location (the "anchor") being inside the macro. 762 TEST_F(TransformerTest, MatchSpansMacroTextButChangeDoesNotAnchoredInMacro) { 763 std::string Input = R"cc( 764 #define PLUS_ONE(a) 1 + a 765 int f() { return PLUS_ONE(3); } 766 )cc"; 767 std::string Expected = R"cc( 768 #define PLUS_ONE(a) 1 + a 769 int f() { return PLUS_ONE(LIT); } 770 )cc"; 771 772 StringRef E = "expr"; 773 testRule(makeRule(binaryOperator(hasRHS(expr().bind(E))), 774 changeTo(node(std::string(E)), cat("LIT"))), 775 Input, Expected); 776 } 777 778 // No rewrite is applied when the changed text does not encompass the entirety 779 // of the expanded text. That is, the edit would have to be applied to the 780 // macro's definition to succeed and editing the expansion point would not 781 // suffice. 782 TEST_F(TransformerTest, NoPartialRewriteOMacroExpansion) { 783 std::string Input = R"cc( 784 #define ZERO_PLUS 0 + 3 785 int f(string s) { return ZERO_PLUS; })cc"; 786 787 StringRef zero = "zero"; 788 RewriteRule R = makeRule(integerLiteral(equals(0)).bind(zero), 789 changeTo(node(std::string(zero)), cat("0"))); 790 testRule(R, Input, Input); 791 } 792 793 // This test handles the corner case where a macro expands within another macro 794 // to matching code, but that code is an argument to the nested macro call. A 795 // simple check of isMacroArgExpansion() vs. isMacroBodyExpansion() will get 796 // this wrong, and transform the code. 797 TEST_F(TransformerTest, NoPartialRewriteOfMacroExpansionForMacroArgs) { 798 std::string Input = R"cc( 799 #define NESTED(e) e 800 #define MACRO(str) 1 + NESTED(strlen((str).c_str())) 801 int f(string s) { return MACRO(s); } 802 )cc"; 803 804 testRule(ruleStrlenSize(), Input, Input); 805 } 806 807 #if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST 808 // Verifies that `Type` and `QualType` are not allowed as top-level matchers in 809 // rules. 810 TEST(TransformerDeathTest, OrderedRuleTypes) { 811 RewriteRule QualTypeRule = makeRule(qualType(), changeTo(cat("Q"))); 812 EXPECT_DEATH(transformer::detail::buildMatchers(QualTypeRule), 813 "Matcher must be.*node matcher"); 814 815 RewriteRule TypeRule = makeRule(arrayType(), changeTo(cat("T"))); 816 EXPECT_DEATH(transformer::detail::buildMatchers(TypeRule), 817 "Matcher must be.*node matcher"); 818 } 819 #endif 820 } // namespace 821