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