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::rewriteDescendants; 29 using transformer::RewriteRule; 30 31 constexpr char KHeaderContents[] = R"cc( 32 struct string { 33 string(const char*); 34 char* c_str(); 35 int size(); 36 }; 37 int strlen(const char*); 38 39 namespace proto { 40 struct PCFProto { 41 int foo(); 42 }; 43 struct ProtoCommandLineFlag : PCFProto { 44 PCFProto& GetProto(); 45 }; 46 } // namespace proto 47 class Logger {}; 48 void operator<<(Logger& l, string msg); 49 Logger& log(int level); 50 )cc"; 51 52 static ast_matchers::internal::Matcher<clang::QualType> 53 isOrPointsTo(const clang::ast_matchers::DeclarationMatcher &TypeMatcher) { 54 return anyOf(hasDeclaration(TypeMatcher), pointsTo(TypeMatcher)); 55 } 56 57 static std::string format(StringRef Code) { 58 const std::vector<Range> Ranges(1, Range(0, Code.size())); 59 auto Style = format::getLLVMStyle(); 60 const auto Replacements = format::reformat(Style, Code, Ranges); 61 auto Formatted = applyAllReplacements(Code, Replacements); 62 if (!Formatted) { 63 ADD_FAILURE() << "Could not format code: " 64 << llvm::toString(Formatted.takeError()); 65 return std::string(); 66 } 67 return *Formatted; 68 } 69 70 static void compareSnippets(StringRef Expected, 71 const llvm::Optional<std::string> &MaybeActual) { 72 ASSERT_TRUE(MaybeActual) << "Rewrite failed. Expecting: " << Expected; 73 auto Actual = *MaybeActual; 74 std::string HL = "#include \"header.h\"\n"; 75 auto I = Actual.find(HL); 76 if (I != std::string::npos) 77 Actual.erase(I, HL.size()); 78 EXPECT_EQ(format(Expected), format(Actual)); 79 } 80 81 // FIXME: consider separating this class into its own file(s). 82 class ClangRefactoringTestBase : public testing::Test { 83 protected: 84 void appendToHeader(StringRef S) { FileContents[0].second += S; } 85 86 void addFile(StringRef Filename, StringRef Content) { 87 FileContents.emplace_back(std::string(Filename), std::string(Content)); 88 } 89 90 llvm::Optional<std::string> rewrite(StringRef Input) { 91 std::string Code = ("#include \"header.h\"\n" + Input).str(); 92 auto Factory = newFrontendActionFactory(&MatchFinder); 93 if (!runToolOnCodeWithArgs( 94 Factory->create(), Code, std::vector<std::string>(), "input.cc", 95 "clang-tool", std::make_shared<PCHContainerOperations>(), 96 FileContents)) { 97 llvm::errs() << "Running tool failed.\n"; 98 return None; 99 } 100 if (ErrorCount != 0) { 101 llvm::errs() << "Generating changes failed.\n"; 102 return None; 103 } 104 auto ChangedCode = 105 applyAtomicChanges("input.cc", Code, Changes, ApplyChangesSpec()); 106 if (!ChangedCode) { 107 llvm::errs() << "Applying changes failed: " 108 << llvm::toString(ChangedCode.takeError()) << "\n"; 109 return None; 110 } 111 return *ChangedCode; 112 } 113 114 Transformer::ChangeConsumer consumer() { 115 return [this](Expected<AtomicChange> C) { 116 if (C) { 117 Changes.push_back(std::move(*C)); 118 } else { 119 // FIXME: stash this error rather then printing. 120 llvm::errs() << "Error generating changes: " 121 << llvm::toString(C.takeError()) << "\n"; 122 ++ErrorCount; 123 } 124 }; 125 } 126 127 template <typename R> 128 void testRule(R Rule, StringRef Input, StringRef Expected) { 129 Transformers.push_back( 130 std::make_unique<Transformer>(std::move(Rule), consumer())); 131 Transformers.back()->registerMatchers(&MatchFinder); 132 compareSnippets(Expected, rewrite(Input)); 133 } 134 135 template <typename R> void testRuleFailure(R Rule, StringRef Input) { 136 Transformers.push_back( 137 std::make_unique<Transformer>(std::move(Rule), consumer())); 138 Transformers.back()->registerMatchers(&MatchFinder); 139 ASSERT_FALSE(rewrite(Input)) << "Expected failure to rewrite code"; 140 } 141 142 // Transformers are referenced by MatchFinder. 143 std::vector<std::unique_ptr<Transformer>> Transformers; 144 clang::ast_matchers::MatchFinder MatchFinder; 145 // Records whether any errors occurred in individual changes. 146 int ErrorCount = 0; 147 AtomicChanges Changes; 148 149 private: 150 FileContentMappings FileContents = {{"header.h", ""}}; 151 }; 152 153 class TransformerTest : public ClangRefactoringTestBase { 154 protected: 155 TransformerTest() { appendToHeader(KHeaderContents); } 156 }; 157 158 // Given string s, change strlen($s.c_str()) to REPLACED. 159 static RewriteRule ruleStrlenSize() { 160 StringRef StringExpr = "strexpr"; 161 auto StringType = namedDecl(hasAnyName("::basic_string", "::string")); 162 auto R = makeRule( 163 callExpr(callee(functionDecl(hasName("strlen"))), 164 hasArgument(0, cxxMemberCallExpr( 165 on(expr(hasType(isOrPointsTo(StringType))) 166 .bind(StringExpr)), 167 callee(cxxMethodDecl(hasName("c_str")))))), 168 changeTo(cat("REPLACED")), cat("Use size() method directly on string.")); 169 return R; 170 } 171 172 TEST_F(TransformerTest, StrlenSize) { 173 std::string Input = "int f(string s) { return strlen(s.c_str()); }"; 174 std::string Expected = "int f(string s) { return REPLACED; }"; 175 testRule(ruleStrlenSize(), Input, Expected); 176 } 177 178 // Tests that no change is applied when a match is not expected. 179 TEST_F(TransformerTest, NoMatch) { 180 std::string Input = "int f(string s) { return s.size(); }"; 181 testRule(ruleStrlenSize(), Input, Input); 182 } 183 184 // Tests replacing an expression. 185 TEST_F(TransformerTest, Flag) { 186 StringRef Flag = "flag"; 187 RewriteRule Rule = makeRule( 188 cxxMemberCallExpr(on(expr(hasType(cxxRecordDecl( 189 hasName("proto::ProtoCommandLineFlag")))) 190 .bind(Flag)), 191 unless(callee(cxxMethodDecl(hasName("GetProto"))))), 192 changeTo(node(std::string(Flag)), cat("EXPR"))); 193 194 std::string Input = R"cc( 195 proto::ProtoCommandLineFlag flag; 196 int x = flag.foo(); 197 int y = flag.GetProto().foo(); 198 )cc"; 199 std::string Expected = R"cc( 200 proto::ProtoCommandLineFlag flag; 201 int x = EXPR.foo(); 202 int y = flag.GetProto().foo(); 203 )cc"; 204 205 testRule(std::move(Rule), Input, Expected); 206 } 207 208 TEST_F(TransformerTest, AddIncludeQuoted) { 209 RewriteRule Rule = 210 makeRule(callExpr(callee(functionDecl(hasName("f")))), 211 {addInclude("clang/OtherLib.h"), changeTo(cat("other()"))}); 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, AddIncludeAngled) { 227 RewriteRule Rule = makeRule( 228 callExpr(callee(functionDecl(hasName("f")))), 229 {addInclude("clang/OtherLib.h", transformer::IncludeFormat::Angled), 230 changeTo(cat("other()"))}); 231 232 std::string Input = R"cc( 233 int f(int x); 234 int h(int x) { return f(x); } 235 )cc"; 236 std::string Expected = R"cc(#include <clang/OtherLib.h> 237 238 int f(int x); 239 int h(int x) { return other(); } 240 )cc"; 241 242 testRule(Rule, Input, Expected); 243 } 244 245 TEST_F(TransformerTest, AddIncludeQuotedForRule) { 246 RewriteRule Rule = makeRule(callExpr(callee(functionDecl(hasName("f")))), 247 changeTo(cat("other()"))); 248 addInclude(Rule, "clang/OtherLib.h"); 249 250 std::string Input = R"cc( 251 int f(int x); 252 int h(int x) { return f(x); } 253 )cc"; 254 std::string Expected = R"cc(#include "clang/OtherLib.h" 255 256 int f(int x); 257 int h(int x) { return other(); } 258 )cc"; 259 260 testRule(Rule, Input, Expected); 261 } 262 263 TEST_F(TransformerTest, AddIncludeAngledForRule) { 264 RewriteRule Rule = makeRule(callExpr(callee(functionDecl(hasName("f")))), 265 changeTo(cat("other()"))); 266 addInclude(Rule, "clang/OtherLib.h", transformer::IncludeFormat::Angled); 267 268 std::string Input = R"cc( 269 int f(int x); 270 int h(int x) { return f(x); } 271 )cc"; 272 std::string Expected = R"cc(#include <clang/OtherLib.h> 273 274 int f(int x); 275 int h(int x) { return other(); } 276 )cc"; 277 278 testRule(Rule, Input, Expected); 279 } 280 281 TEST_F(TransformerTest, NodePartNameNamedDecl) { 282 StringRef Fun = "fun"; 283 RewriteRule Rule = makeRule(functionDecl(hasName("bad")).bind(Fun), 284 changeTo(name(std::string(Fun)), cat("good"))); 285 286 std::string Input = R"cc( 287 int bad(int x); 288 int bad(int x) { return x * x; } 289 )cc"; 290 std::string Expected = R"cc( 291 int good(int x); 292 int good(int x) { return x * x; } 293 )cc"; 294 295 testRule(Rule, Input, Expected); 296 } 297 298 TEST_F(TransformerTest, NodePartNameDeclRef) { 299 std::string Input = R"cc( 300 template <typename T> 301 T bad(T x) { 302 return x; 303 } 304 int neutral(int x) { return bad<int>(x) * x; } 305 )cc"; 306 std::string Expected = R"cc( 307 template <typename T> 308 T bad(T x) { 309 return x; 310 } 311 int neutral(int x) { return good<int>(x) * x; } 312 )cc"; 313 314 StringRef Ref = "ref"; 315 testRule(makeRule(declRefExpr(to(functionDecl(hasName("bad")))).bind(Ref), 316 changeTo(name(std::string(Ref)), cat("good"))), 317 Input, Expected); 318 } 319 320 TEST_F(TransformerTest, NodePartNameDeclRefFailure) { 321 std::string Input = R"cc( 322 struct Y { 323 int operator*(); 324 }; 325 int neutral(int x) { 326 Y y; 327 int (Y::*ptr)() = &Y::operator*; 328 return *y + x; 329 } 330 )cc"; 331 332 StringRef Ref = "ref"; 333 Transformer T(makeRule(declRefExpr(to(functionDecl())).bind(Ref), 334 changeTo(name(std::string(Ref)), cat("good"))), 335 consumer()); 336 T.registerMatchers(&MatchFinder); 337 EXPECT_FALSE(rewrite(Input)); 338 } 339 340 TEST_F(TransformerTest, NodePartMember) { 341 StringRef E = "expr"; 342 RewriteRule Rule = makeRule(memberExpr(member(hasName("bad"))).bind(E), 343 changeTo(member(std::string(E)), cat("good"))); 344 345 std::string Input = R"cc( 346 struct S { 347 int bad; 348 }; 349 int g() { 350 S s; 351 return s.bad; 352 } 353 )cc"; 354 std::string Expected = R"cc( 355 struct S { 356 int bad; 357 }; 358 int g() { 359 S s; 360 return s.good; 361 } 362 )cc"; 363 364 testRule(Rule, Input, Expected); 365 } 366 367 TEST_F(TransformerTest, NodePartMemberQualified) { 368 std::string Input = R"cc( 369 struct S { 370 int bad; 371 int good; 372 }; 373 struct T : public S { 374 int bad; 375 }; 376 int g() { 377 T t; 378 return t.S::bad; 379 } 380 )cc"; 381 std::string Expected = R"cc( 382 struct S { 383 int bad; 384 int good; 385 }; 386 struct T : public S { 387 int bad; 388 }; 389 int g() { 390 T t; 391 return t.S::good; 392 } 393 )cc"; 394 395 StringRef E = "expr"; 396 testRule(makeRule(memberExpr().bind(E), 397 changeTo(member(std::string(E)), cat("good"))), 398 Input, Expected); 399 } 400 401 TEST_F(TransformerTest, NodePartMemberMultiToken) { 402 std::string Input = R"cc( 403 struct Y { 404 int operator*(); 405 int good(); 406 template <typename T> void foo(T t); 407 }; 408 int neutral(int x) { 409 Y y; 410 y.template foo<int>(3); 411 return y.operator *(); 412 } 413 )cc"; 414 std::string Expected = R"cc( 415 struct Y { 416 int operator*(); 417 int good(); 418 template <typename T> void foo(T t); 419 }; 420 int neutral(int x) { 421 Y y; 422 y.template good<int>(3); 423 return y.good(); 424 } 425 )cc"; 426 427 StringRef MemExpr = "member"; 428 testRule(makeRule(memberExpr().bind(MemExpr), 429 changeTo(member(std::string(MemExpr)), cat("good"))), 430 Input, Expected); 431 } 432 433 TEST_F(TransformerTest, NoEdits) { 434 using transformer::noEdits; 435 std::string Input = "int f(int x) { return x; }"; 436 testRule(makeRule(returnStmt().bind("return"), noEdits()), Input, Input); 437 } 438 439 TEST_F(TransformerTest, NoopEdit) { 440 using transformer::node; 441 using transformer::noopEdit; 442 std::string Input = "int f(int x) { return x; }"; 443 testRule(makeRule(returnStmt().bind("return"), noopEdit(node("return"))), 444 Input, Input); 445 } 446 447 TEST_F(TransformerTest, IfBound2Args) { 448 using transformer::ifBound; 449 std::string Input = "int f(int x) { return x; }"; 450 std::string Expected = "int f(int x) { CHANGE; }"; 451 testRule(makeRule(returnStmt().bind("return"), 452 ifBound("return", changeTo(cat("CHANGE;")))), 453 Input, Expected); 454 } 455 456 TEST_F(TransformerTest, IfBound3Args) { 457 using transformer::ifBound; 458 std::string Input = "int f(int x) { return x; }"; 459 std::string Expected = "int f(int x) { CHANGE; }"; 460 testRule(makeRule(returnStmt().bind("return"), 461 ifBound("nothing", changeTo(cat("ERROR")), 462 changeTo(cat("CHANGE;")))), 463 Input, Expected); 464 } 465 466 TEST_F(TransformerTest, ShrinkTo) { 467 using transformer::shrinkTo; 468 std::string Input = "int f(int x) { return x; }"; 469 std::string Expected = "return x;"; 470 testRule(makeRule(functionDecl(hasDescendant(returnStmt().bind("return"))) 471 .bind("function"), 472 shrinkTo(node("function"), node("return"))), 473 Input, Expected); 474 } 475 476 // Rewrite various Stmts inside a Decl. 477 TEST_F(TransformerTest, RewriteDescendantsDeclChangeStmt) { 478 std::string Input = 479 "int f(int x) { int y = x; { int z = x * x; } return x; }"; 480 std::string Expected = 481 "int f(int x) { int y = 3; { int z = 3 * 3; } return 3; }"; 482 auto InlineX = 483 makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3"))); 484 testRule(makeRule(functionDecl(hasName("f")).bind("fun"), 485 rewriteDescendants("fun", InlineX)), 486 Input, Expected); 487 } 488 489 // Rewrite various TypeLocs inside a Decl. 490 TEST_F(TransformerTest, RewriteDescendantsDeclChangeTypeLoc) { 491 std::string Input = "int f(int *x) { return *x; }"; 492 std::string Expected = "char f(char *x) { return *x; }"; 493 auto IntToChar = makeRule(typeLoc(loc(qualType(isInteger(), builtinType()))), 494 changeTo(cat("char"))); 495 testRule(makeRule(functionDecl(hasName("f")).bind("fun"), 496 rewriteDescendants("fun", IntToChar)), 497 Input, Expected); 498 } 499 500 TEST_F(TransformerTest, RewriteDescendantsStmt) { 501 // Add an unrelated definition to the header that also has a variable named 502 // "x", to test that the rewrite is limited to the scope we intend. 503 appendToHeader(R"cc(int g(int x) { return x; })cc"); 504 std::string Input = 505 "int f(int x) { int y = x; { int z = x * x; } return x; }"; 506 std::string Expected = 507 "int f(int x) { int y = 3; { int z = 3 * 3; } return 3; }"; 508 auto InlineX = 509 makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3"))); 510 testRule(makeRule(functionDecl(hasName("f"), hasBody(stmt().bind("body"))), 511 rewriteDescendants("body", InlineX)), 512 Input, Expected); 513 } 514 515 TEST_F(TransformerTest, RewriteDescendantsStmtWithAdditionalChange) { 516 std::string Input = 517 "int f(int x) { int y = x; { int z = x * x; } return x; }"; 518 std::string Expected = 519 "int newName(int x) { int y = 3; { int z = 3 * 3; } return 3; }"; 520 auto InlineX = 521 makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3"))); 522 testRule( 523 makeRule( 524 functionDecl(hasName("f"), hasBody(stmt().bind("body"))).bind("f"), 525 flatten(changeTo(name("f"), cat("newName")), 526 rewriteDescendants("body", InlineX))), 527 Input, Expected); 528 } 529 530 TEST_F(TransformerTest, RewriteDescendantsTypeLoc) { 531 std::string Input = "int f(int *x) { return *x; }"; 532 std::string Expected = "int f(char *x) { return *x; }"; 533 auto IntToChar = 534 makeRule(typeLoc(loc(qualType(isInteger(), builtinType()))).bind("loc"), 535 changeTo(cat("char"))); 536 testRule( 537 makeRule(functionDecl(hasName("f"), 538 hasParameter(0, varDecl(hasTypeLoc( 539 typeLoc().bind("parmType"))))), 540 rewriteDescendants("parmType", IntToChar)), 541 Input, Expected); 542 } 543 544 TEST_F(TransformerTest, RewriteDescendantsReferToParentBinding) { 545 std::string Input = 546 "int f(int p) { int y = p; { int z = p * p; } return p; }"; 547 std::string Expected = 548 "int f(int p) { int y = 3; { int z = 3 * 3; } return 3; }"; 549 std::string VarId = "var"; 550 auto InlineVar = makeRule(declRefExpr(to(varDecl(equalsBoundNode(VarId)))), 551 changeTo(cat("3"))); 552 testRule(makeRule(functionDecl(hasName("f"), 553 hasParameter(0, varDecl().bind(VarId))) 554 .bind("fun"), 555 rewriteDescendants("fun", InlineVar)), 556 Input, Expected); 557 } 558 559 TEST_F(TransformerTest, RewriteDescendantsUnboundNode) { 560 std::string Input = 561 "int f(int x) { int y = x; { int z = x * x; } return x; }"; 562 auto InlineX = 563 makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3"))); 564 Transformer T(makeRule(functionDecl(hasName("f")), 565 rewriteDescendants("UNBOUND", InlineX)), 566 consumer()); 567 T.registerMatchers(&MatchFinder); 568 EXPECT_FALSE(rewrite(Input)); 569 EXPECT_THAT(Changes, IsEmpty()); 570 EXPECT_EQ(ErrorCount, 1); 571 } 572 573 TEST_F(TransformerTest, RewriteDescendantsInvalidNodeType) { 574 std::string Input = 575 "int f(int x) { int y = x; { int z = x * x; } return x; }"; 576 auto IntToChar = 577 makeRule(qualType(isInteger(), builtinType()), changeTo(cat("char"))); 578 Transformer T( 579 makeRule(functionDecl( 580 hasName("f"), 581 hasParameter(0, varDecl(hasType(qualType().bind("type"))))), 582 rewriteDescendants("type", IntToChar)), 583 consumer()); 584 T.registerMatchers(&MatchFinder); 585 EXPECT_FALSE(rewrite(Input)); 586 EXPECT_THAT(Changes, IsEmpty()); 587 EXPECT_EQ(ErrorCount, 1); 588 } 589 590 // 591 // We include one test per typed overload. We don't test extensively since that 592 // is already covered by the tests above. 593 // 594 595 TEST_F(TransformerTest, RewriteDescendantsTypedStmt) { 596 // Add an unrelated definition to the header that also has a variable named 597 // "x", to test that the rewrite is limited to the scope we intend. 598 appendToHeader(R"cc(int g(int x) { return x; })cc"); 599 std::string Input = 600 "int f(int x) { int y = x; { int z = x * x; } return x; }"; 601 std::string Expected = 602 "int f(int x) { int y = 3; { int z = 3 * 3; } return 3; }"; 603 auto InlineX = 604 makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3"))); 605 testRule(makeRule(functionDecl(hasName("f"), hasBody(stmt().bind("body"))), 606 [&InlineX](const MatchFinder::MatchResult &R) { 607 const auto *Node = R.Nodes.getNodeAs<Stmt>("body"); 608 assert(Node != nullptr && "body must be bound"); 609 return transformer::detail::rewriteDescendants( 610 *Node, InlineX, R); 611 }), 612 Input, Expected); 613 } 614 615 TEST_F(TransformerTest, RewriteDescendantsTypedDecl) { 616 std::string Input = 617 "int f(int x) { int y = x; { int z = x * x; } return x; }"; 618 std::string Expected = 619 "int f(int x) { int y = 3; { int z = 3 * 3; } return 3; }"; 620 auto InlineX = 621 makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3"))); 622 testRule(makeRule(functionDecl(hasName("f")).bind("fun"), 623 [&InlineX](const MatchFinder::MatchResult &R) { 624 const auto *Node = R.Nodes.getNodeAs<Decl>("fun"); 625 assert(Node != nullptr && "fun must be bound"); 626 return transformer::detail::rewriteDescendants( 627 *Node, InlineX, R); 628 }), 629 Input, Expected); 630 } 631 632 TEST_F(TransformerTest, RewriteDescendantsTypedTypeLoc) { 633 std::string Input = "int f(int *x) { return *x; }"; 634 std::string Expected = "int f(char *x) { return *x; }"; 635 auto IntToChar = 636 makeRule(typeLoc(loc(qualType(isInteger(), builtinType()))).bind("loc"), 637 changeTo(cat("char"))); 638 testRule( 639 makeRule( 640 functionDecl( 641 hasName("f"), 642 hasParameter(0, varDecl(hasTypeLoc(typeLoc().bind("parmType"))))), 643 [&IntToChar](const MatchFinder::MatchResult &R) { 644 const auto *Node = R.Nodes.getNodeAs<TypeLoc>("parmType"); 645 assert(Node != nullptr && "parmType must be bound"); 646 return transformer::detail::rewriteDescendants(*Node, IntToChar, R); 647 }), 648 Input, Expected); 649 } 650 651 TEST_F(TransformerTest, RewriteDescendantsTypedDynTyped) { 652 // Add an unrelated definition to the header that also has a variable named 653 // "x", to test that the rewrite is limited to the scope we intend. 654 appendToHeader(R"cc(int g(int x) { return x; })cc"); 655 std::string Input = 656 "int f(int x) { int y = x; { int z = x * x; } return x; }"; 657 std::string Expected = 658 "int f(int x) { int y = 3; { int z = 3 * 3; } return 3; }"; 659 auto InlineX = 660 makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3"))); 661 testRule( 662 makeRule(functionDecl(hasName("f"), hasBody(stmt().bind("body"))), 663 [&InlineX](const MatchFinder::MatchResult &R) { 664 auto It = R.Nodes.getMap().find("body"); 665 assert(It != R.Nodes.getMap().end() && "body must be bound"); 666 return transformer::detail::rewriteDescendants(It->second, 667 InlineX, R); 668 }), 669 Input, Expected); 670 } 671 672 TEST_F(TransformerTest, InsertBeforeEdit) { 673 std::string Input = R"cc( 674 int f() { 675 return 7; 676 } 677 )cc"; 678 std::string Expected = R"cc( 679 int f() { 680 int y = 3; 681 return 7; 682 } 683 )cc"; 684 685 StringRef Ret = "return"; 686 testRule( 687 makeRule(returnStmt().bind(Ret), 688 insertBefore(statement(std::string(Ret)), cat("int y = 3;"))), 689 Input, Expected); 690 } 691 692 TEST_F(TransformerTest, InsertAfterEdit) { 693 std::string Input = R"cc( 694 int f() { 695 int x = 5; 696 return 7; 697 } 698 )cc"; 699 std::string Expected = R"cc( 700 int f() { 701 int x = 5; 702 int y = 3; 703 return 7; 704 } 705 )cc"; 706 707 StringRef Decl = "decl"; 708 testRule( 709 makeRule(declStmt().bind(Decl), 710 insertAfter(statement(std::string(Decl)), cat("int y = 3;"))), 711 Input, Expected); 712 } 713 714 TEST_F(TransformerTest, RemoveEdit) { 715 std::string Input = R"cc( 716 int f() { 717 int x = 5; 718 return 7; 719 } 720 )cc"; 721 std::string Expected = R"cc( 722 int f() { 723 return 7; 724 } 725 )cc"; 726 727 StringRef Decl = "decl"; 728 testRule( 729 makeRule(declStmt().bind(Decl), remove(statement(std::string(Decl)))), 730 Input, Expected); 731 } 732 733 TEST_F(TransformerTest, WithMetadata) { 734 auto makeMetadata = [](const MatchFinder::MatchResult &R) -> llvm::Any { 735 int N = 736 R.Nodes.getNodeAs<IntegerLiteral>("int")->getValue().getLimitedValue(); 737 return N; 738 }; 739 740 std::string Input = R"cc( 741 int f() { 742 int x = 5; 743 return 7; 744 } 745 )cc"; 746 747 Transformer T( 748 makeRule( 749 declStmt(containsDeclaration(0, varDecl(hasInitializer( 750 integerLiteral().bind("int"))))) 751 .bind("decl"), 752 withMetadata(remove(statement(std::string("decl"))), makeMetadata)), 753 consumer()); 754 T.registerMatchers(&MatchFinder); 755 auto Factory = newFrontendActionFactory(&MatchFinder); 756 EXPECT_TRUE(runToolOnCodeWithArgs( 757 Factory->create(), Input, std::vector<std::string>(), "input.cc", 758 "clang-tool", std::make_shared<PCHContainerOperations>(), {})); 759 ASSERT_EQ(Changes.size(), 1u); 760 const llvm::Any &Metadata = Changes[0].getMetadata(); 761 ASSERT_TRUE(llvm::any_isa<int>(Metadata)); 762 EXPECT_THAT(llvm::any_cast<int>(Metadata), 5); 763 } 764 765 TEST_F(TransformerTest, MultiChange) { 766 std::string Input = R"cc( 767 void foo() { 768 if (10 > 1.0) 769 log(1) << "oh no!"; 770 else 771 log(0) << "ok"; 772 } 773 )cc"; 774 std::string Expected = R"( 775 void foo() { 776 if (true) { /* then */ } 777 else { /* else */ } 778 } 779 )"; 780 781 StringRef C = "C", T = "T", E = "E"; 782 testRule( 783 makeRule(ifStmt(hasCondition(expr().bind(C)), hasThen(stmt().bind(T)), 784 hasElse(stmt().bind(E))), 785 {changeTo(node(std::string(C)), cat("true")), 786 changeTo(statement(std::string(T)), cat("{ /* then */ }")), 787 changeTo(statement(std::string(E)), cat("{ /* else */ }"))}), 788 Input, Expected); 789 } 790 791 TEST_F(TransformerTest, EditList) { 792 using clang::transformer::editList; 793 std::string Input = R"cc( 794 void foo() { 795 if (10 > 1.0) 796 log(1) << "oh no!"; 797 else 798 log(0) << "ok"; 799 } 800 )cc"; 801 std::string Expected = R"( 802 void foo() { 803 if (true) { /* then */ } 804 else { /* else */ } 805 } 806 )"; 807 808 StringRef C = "C", T = "T", E = "E"; 809 testRule(makeRule(ifStmt(hasCondition(expr().bind(C)), 810 hasThen(stmt().bind(T)), hasElse(stmt().bind(E))), 811 editList({changeTo(node(std::string(C)), cat("true")), 812 changeTo(statement(std::string(T)), 813 cat("{ /* then */ }")), 814 changeTo(statement(std::string(E)), 815 cat("{ /* else */ }"))})), 816 Input, Expected); 817 } 818 819 TEST_F(TransformerTest, Flatten) { 820 using clang::transformer::editList; 821 std::string Input = R"cc( 822 void foo() { 823 if (10 > 1.0) 824 log(1) << "oh no!"; 825 else 826 log(0) << "ok"; 827 } 828 )cc"; 829 std::string Expected = R"( 830 void foo() { 831 if (true) { /* then */ } 832 else { /* else */ } 833 } 834 )"; 835 836 StringRef C = "C", T = "T", E = "E"; 837 testRule( 838 makeRule( 839 ifStmt(hasCondition(expr().bind(C)), hasThen(stmt().bind(T)), 840 hasElse(stmt().bind(E))), 841 flatten(changeTo(node(std::string(C)), cat("true")), 842 changeTo(statement(std::string(T)), cat("{ /* then */ }")), 843 changeTo(statement(std::string(E)), cat("{ /* else */ }")))), 844 Input, Expected); 845 } 846 847 TEST_F(TransformerTest, FlattenWithMixedArgs) { 848 using clang::transformer::editList; 849 std::string Input = R"cc( 850 void foo() { 851 if (10 > 1.0) 852 log(1) << "oh no!"; 853 else 854 log(0) << "ok"; 855 } 856 )cc"; 857 std::string Expected = R"( 858 void foo() { 859 if (true) { /* then */ } 860 else { /* else */ } 861 } 862 )"; 863 864 StringRef C = "C", T = "T", E = "E"; 865 testRule(makeRule(ifStmt(hasCondition(expr().bind(C)), 866 hasThen(stmt().bind(T)), hasElse(stmt().bind(E))), 867 flatten(changeTo(node(std::string(C)), cat("true")), 868 edit(changeTo(statement(std::string(T)), 869 cat("{ /* then */ }"))), 870 editList({changeTo(statement(std::string(E)), 871 cat("{ /* else */ }"))}))), 872 Input, Expected); 873 } 874 875 TEST_F(TransformerTest, OrderedRuleUnrelated) { 876 StringRef Flag = "flag"; 877 RewriteRule FlagRule = makeRule( 878 cxxMemberCallExpr(on(expr(hasType(cxxRecordDecl( 879 hasName("proto::ProtoCommandLineFlag")))) 880 .bind(Flag)), 881 unless(callee(cxxMethodDecl(hasName("GetProto"))))), 882 changeTo(node(std::string(Flag)), cat("PROTO"))); 883 884 std::string Input = R"cc( 885 proto::ProtoCommandLineFlag flag; 886 int x = flag.foo(); 887 int y = flag.GetProto().foo(); 888 int f(string s) { return strlen(s.c_str()); } 889 )cc"; 890 std::string Expected = R"cc( 891 proto::ProtoCommandLineFlag flag; 892 int x = PROTO.foo(); 893 int y = flag.GetProto().foo(); 894 int f(string s) { return REPLACED; } 895 )cc"; 896 897 testRule(applyFirst({ruleStrlenSize(), FlagRule}), Input, Expected); 898 } 899 900 TEST_F(TransformerTest, OrderedRuleRelated) { 901 std::string Input = R"cc( 902 void f1(); 903 void f2(); 904 void call_f1() { f1(); } 905 void call_f2() { f2(); } 906 )cc"; 907 std::string Expected = R"cc( 908 void f1(); 909 void f2(); 910 void call_f1() { REPLACE_F1; } 911 void call_f2() { REPLACE_F1_OR_F2; } 912 )cc"; 913 914 RewriteRule ReplaceF1 = 915 makeRule(callExpr(callee(functionDecl(hasName("f1")))), 916 changeTo(cat("REPLACE_F1"))); 917 RewriteRule ReplaceF1OrF2 = 918 makeRule(callExpr(callee(functionDecl(hasAnyName("f1", "f2")))), 919 changeTo(cat("REPLACE_F1_OR_F2"))); 920 testRule(applyFirst({ReplaceF1, ReplaceF1OrF2}), Input, Expected); 921 } 922 923 // Change the order of the rules to get a different result. When `ReplaceF1OrF2` 924 // comes first, it applies for both uses, so `ReplaceF1` never applies. 925 TEST_F(TransformerTest, OrderedRuleRelatedSwapped) { 926 std::string Input = R"cc( 927 void f1(); 928 void f2(); 929 void call_f1() { f1(); } 930 void call_f2() { f2(); } 931 )cc"; 932 std::string Expected = R"cc( 933 void f1(); 934 void f2(); 935 void call_f1() { REPLACE_F1_OR_F2; } 936 void call_f2() { REPLACE_F1_OR_F2; } 937 )cc"; 938 939 RewriteRule ReplaceF1 = 940 makeRule(callExpr(callee(functionDecl(hasName("f1")))), 941 changeTo(cat("REPLACE_F1"))); 942 RewriteRule ReplaceF1OrF2 = 943 makeRule(callExpr(callee(functionDecl(hasAnyName("f1", "f2")))), 944 changeTo(cat("REPLACE_F1_OR_F2"))); 945 testRule(applyFirst({ReplaceF1OrF2, ReplaceF1}), Input, Expected); 946 } 947 948 // Verify that a set of rules whose matchers have different base kinds works 949 // properly, including that `applyFirst` produces multiple matchers. We test 950 // two different kinds of rules: Expr and Decl. We place the Decl rule in the 951 // middle to test that `buildMatchers` works even when the kinds aren't grouped 952 // together. 953 TEST_F(TransformerTest, OrderedRuleMultipleKinds) { 954 std::string Input = R"cc( 955 void f1(); 956 void f2(); 957 void call_f1() { f1(); } 958 void call_f2() { f2(); } 959 )cc"; 960 std::string Expected = R"cc( 961 void f1(); 962 void DECL_RULE(); 963 void call_f1() { REPLACE_F1; } 964 void call_f2() { REPLACE_F1_OR_F2; } 965 )cc"; 966 967 RewriteRule ReplaceF1 = 968 makeRule(callExpr(callee(functionDecl(hasName("f1")))), 969 changeTo(cat("REPLACE_F1"))); 970 RewriteRule ReplaceF1OrF2 = 971 makeRule(callExpr(callee(functionDecl(hasAnyName("f1", "f2")))), 972 changeTo(cat("REPLACE_F1_OR_F2"))); 973 RewriteRule DeclRule = makeRule(functionDecl(hasName("f2")).bind("fun"), 974 changeTo(name("fun"), cat("DECL_RULE"))); 975 976 RewriteRule Rule = applyFirst({ReplaceF1, DeclRule, ReplaceF1OrF2}); 977 EXPECT_EQ(transformer::detail::buildMatchers(Rule).size(), 2UL); 978 testRule(Rule, Input, Expected); 979 } 980 981 // Verifies that a rule with a top-level matcher for an implicit node (like 982 // `implicitCastExpr`) works correctly -- the implicit nodes are not skipped. 983 TEST_F(TransformerTest, OrderedRuleImplicitMatched) { 984 std::string Input = R"cc( 985 void f1(); 986 int f2(); 987 void call_f1() { f1(); } 988 float call_f2() { return f2(); } 989 )cc"; 990 std::string Expected = R"cc( 991 void f1(); 992 int f2(); 993 void call_f1() { REPLACE_F1; } 994 float call_f2() { return REPLACE_F2; } 995 )cc"; 996 997 RewriteRule ReplaceF1 = 998 makeRule(callExpr(callee(functionDecl(hasName("f1")))), 999 changeTo(cat("REPLACE_F1"))); 1000 RewriteRule ReplaceF2 = 1001 makeRule(implicitCastExpr(hasSourceExpression(callExpr())), 1002 changeTo(cat("REPLACE_F2"))); 1003 testRule(applyFirst({ReplaceF1, ReplaceF2}), Input, Expected); 1004 } 1005 1006 // 1007 // Negative tests (where we expect no transformation to occur). 1008 // 1009 1010 // Tests for a conflict in edits from a single match for a rule. 1011 TEST_F(TransformerTest, TextGeneratorFailure) { 1012 std::string Input = "int conflictOneRule() { return 3 + 7; }"; 1013 // Try to change the whole binary-operator expression AND one its operands: 1014 StringRef O = "O"; 1015 class AlwaysFail : public transformer::MatchComputation<std::string> { 1016 llvm::Error eval(const ast_matchers::MatchFinder::MatchResult &, 1017 std::string *) const override { 1018 return llvm::createStringError(llvm::errc::invalid_argument, "ERROR"); 1019 } 1020 std::string toString() const override { return "AlwaysFail"; } 1021 }; 1022 Transformer T( 1023 makeRule(binaryOperator().bind(O), 1024 changeTo(node(std::string(O)), std::make_shared<AlwaysFail>())), 1025 consumer()); 1026 T.registerMatchers(&MatchFinder); 1027 EXPECT_FALSE(rewrite(Input)); 1028 EXPECT_THAT(Changes, IsEmpty()); 1029 EXPECT_EQ(ErrorCount, 1); 1030 } 1031 1032 // Tests for a conflict in edits from a single match for a rule. 1033 TEST_F(TransformerTest, OverlappingEditsInRule) { 1034 std::string Input = "int conflictOneRule() { return 3 + 7; }"; 1035 // Try to change the whole binary-operator expression AND one its operands: 1036 StringRef O = "O", L = "L"; 1037 Transformer T(makeRule(binaryOperator(hasLHS(expr().bind(L))).bind(O), 1038 {changeTo(node(std::string(O)), cat("DELETE_OP")), 1039 changeTo(node(std::string(L)), cat("DELETE_LHS"))}), 1040 consumer()); 1041 T.registerMatchers(&MatchFinder); 1042 EXPECT_FALSE(rewrite(Input)); 1043 EXPECT_THAT(Changes, IsEmpty()); 1044 EXPECT_EQ(ErrorCount, 1); 1045 } 1046 1047 // Tests for a conflict in edits across multiple matches (of the same rule). 1048 TEST_F(TransformerTest, OverlappingEditsMultipleMatches) { 1049 std::string Input = "int conflictOneRule() { return -7; }"; 1050 // Try to change the whole binary-operator expression AND one its operands: 1051 StringRef E = "E"; 1052 Transformer T(makeRule(expr().bind(E), 1053 changeTo(node(std::string(E)), cat("DELETE_EXPR"))), 1054 consumer()); 1055 T.registerMatchers(&MatchFinder); 1056 // The rewrite process fails because the changes conflict with each other... 1057 EXPECT_FALSE(rewrite(Input)); 1058 // ... but two changes were produced. 1059 EXPECT_EQ(Changes.size(), 2u); 1060 EXPECT_EQ(ErrorCount, 0); 1061 } 1062 1063 TEST_F(TransformerTest, ErrorOccurredMatchSkipped) { 1064 // Syntax error in the function body: 1065 std::string Input = "void errorOccurred() { 3 }"; 1066 Transformer T(makeRule(functionDecl(hasName("errorOccurred")), 1067 changeTo(cat("DELETED;"))), 1068 consumer()); 1069 T.registerMatchers(&MatchFinder); 1070 // The rewrite process itself fails... 1071 EXPECT_FALSE(rewrite(Input)); 1072 // ... and no changes or errors are produced in the process. 1073 EXPECT_THAT(Changes, IsEmpty()); 1074 EXPECT_EQ(ErrorCount, 0); 1075 } 1076 1077 TEST_F(TransformerTest, ImplicitNodes_ConstructorDecl) { 1078 1079 std::string OtherStructPrefix = R"cpp( 1080 struct Other { 1081 )cpp"; 1082 std::string OtherStructSuffix = "};"; 1083 1084 std::string CopyableStructName = "struct Copyable"; 1085 std::string BrokenStructName = "struct explicit Copyable"; 1086 1087 std::string CodeSuffix = R"cpp( 1088 { 1089 Other m_i; 1090 Copyable(); 1091 }; 1092 )cpp"; 1093 1094 std::string CopyCtor = "Other(const Other&) = default;"; 1095 std::string ExplicitCopyCtor = "explicit Other(const Other&) = default;"; 1096 std::string BrokenExplicitCopyCtor = 1097 "explicit explicit explicit Other(const Other&) = default;"; 1098 1099 std::string RewriteInput = OtherStructPrefix + CopyCtor + OtherStructSuffix + 1100 CopyableStructName + CodeSuffix; 1101 std::string ExpectedRewriteOutput = OtherStructPrefix + ExplicitCopyCtor + 1102 OtherStructSuffix + CopyableStructName + 1103 CodeSuffix; 1104 std::string BrokenRewriteOutput = OtherStructPrefix + BrokenExplicitCopyCtor + 1105 OtherStructSuffix + BrokenStructName + 1106 CodeSuffix; 1107 1108 auto MatchedRecord = 1109 cxxConstructorDecl(isCopyConstructor()).bind("copyConstructor"); 1110 1111 auto RewriteRule = 1112 changeTo(before(node("copyConstructor")), cat("explicit ")); 1113 1114 testRule(makeRule(traverse(TK_IgnoreUnlessSpelledInSource, MatchedRecord), 1115 RewriteRule), 1116 RewriteInput, ExpectedRewriteOutput); 1117 1118 testRule(makeRule(traverse(TK_AsIs, MatchedRecord), RewriteRule), 1119 RewriteInput, BrokenRewriteOutput); 1120 } 1121 1122 TEST_F(TransformerTest, ImplicitNodes_RangeFor) { 1123 1124 std::string CodePrefix = R"cpp( 1125 struct Container 1126 { 1127 int* begin() const; 1128 int* end() const; 1129 int* cbegin() const; 1130 int* cend() const; 1131 }; 1132 1133 void foo() 1134 { 1135 const Container c; 1136 )cpp"; 1137 1138 std::string BeginCallBefore = " c.begin();"; 1139 std::string BeginCallAfter = " c.cbegin();"; 1140 1141 std::string ForLoop = "for (auto i : c)"; 1142 std::string BrokenForLoop = "for (auto i :.cbegin() c)"; 1143 1144 std::string CodeSuffix = R"cpp( 1145 { 1146 } 1147 } 1148 )cpp"; 1149 1150 std::string RewriteInput = 1151 CodePrefix + BeginCallBefore + ForLoop + CodeSuffix; 1152 std::string ExpectedRewriteOutput = 1153 CodePrefix + BeginCallAfter + ForLoop + CodeSuffix; 1154 std::string BrokenRewriteOutput = 1155 CodePrefix + BeginCallAfter + BrokenForLoop + CodeSuffix; 1156 1157 auto MatchedRecord = 1158 cxxMemberCallExpr(on(expr(hasType(qualType(isConstQualified(), 1159 hasDeclaration(cxxRecordDecl( 1160 hasName("Container")))))) 1161 .bind("callTarget")), 1162 callee(cxxMethodDecl(hasName("begin")))) 1163 .bind("constBeginCall"); 1164 1165 auto RewriteRule = 1166 changeTo(node("constBeginCall"), cat(name("callTarget"), ".cbegin()")); 1167 1168 testRule(makeRule(traverse(TK_IgnoreUnlessSpelledInSource, MatchedRecord), 1169 RewriteRule), 1170 RewriteInput, ExpectedRewriteOutput); 1171 1172 testRule(makeRule(traverse(TK_AsIs, MatchedRecord), RewriteRule), 1173 RewriteInput, BrokenRewriteOutput); 1174 } 1175 1176 TEST_F(TransformerTest, ImplicitNodes_ForStmt) { 1177 1178 std::string CodePrefix = R"cpp( 1179 struct NonTrivial { 1180 NonTrivial() {} 1181 NonTrivial(NonTrivial&) {} 1182 NonTrivial& operator=(NonTrivial const&) { return *this; } 1183 1184 ~NonTrivial() {} 1185 }; 1186 1187 struct ContainsArray { 1188 NonTrivial arr[2]; 1189 ContainsArray& operator=(ContainsArray const&) = default; 1190 }; 1191 1192 void testIt() 1193 { 1194 ContainsArray ca1; 1195 ContainsArray ca2; 1196 ca2 = ca1; 1197 )cpp"; 1198 1199 auto CodeSuffix = "}"; 1200 1201 auto LoopBody = R"cpp( 1202 { 1203 1204 } 1205 )cpp"; 1206 1207 auto RawLoop = "for (auto i = 0; i != 5; ++i)"; 1208 1209 auto RangeLoop = "for (auto i : boost::irange(5))"; 1210 1211 // Expect to rewrite the raw loop to the ranged loop. 1212 // This works in TK_IgnoreUnlessSpelledInSource mode, but TK_AsIs 1213 // mode also matches the hidden for loop generated in the copy assignment 1214 // operator of ContainsArray. Transformer then fails to transform the code at 1215 // all. 1216 1217 auto RewriteInput = 1218 CodePrefix + RawLoop + LoopBody + RawLoop + LoopBody + CodeSuffix; 1219 1220 auto RewriteOutput = 1221 CodePrefix + RangeLoop + LoopBody + RangeLoop + LoopBody + CodeSuffix; 1222 1223 auto MatchedLoop = forStmt( 1224 has(declStmt( 1225 hasSingleDecl(varDecl(hasInitializer(integerLiteral(equals(0)))) 1226 .bind("loopVar")))), 1227 has(binaryOperator(hasOperatorName("!="), 1228 hasLHS(ignoringImplicit(declRefExpr( 1229 to(varDecl(equalsBoundNode("loopVar")))))), 1230 hasRHS(expr().bind("upperBoundExpr")))), 1231 has(unaryOperator(hasOperatorName("++"), 1232 hasUnaryOperand(declRefExpr( 1233 to(varDecl(equalsBoundNode("loopVar")))))) 1234 .bind("incrementOp"))); 1235 1236 auto RewriteRule = 1237 changeTo(transformer::enclose(node("loopVar"), node("incrementOp")), 1238 cat("auto ", name("loopVar"), " : boost::irange(", 1239 node("upperBoundExpr"), ")")); 1240 1241 testRule(makeRule(traverse(TK_IgnoreUnlessSpelledInSource, MatchedLoop), 1242 RewriteRule), 1243 RewriteInput, RewriteOutput); 1244 1245 testRuleFailure(makeRule(traverse(TK_AsIs, MatchedLoop), RewriteRule), 1246 RewriteInput); 1247 1248 } 1249 1250 TEST_F(TransformerTest, ImplicitNodes_ForStmt2) { 1251 1252 std::string CodePrefix = R"cpp( 1253 struct NonTrivial { 1254 NonTrivial() {} 1255 NonTrivial(NonTrivial&) {} 1256 NonTrivial& operator=(NonTrivial const&) { return *this; } 1257 1258 ~NonTrivial() {} 1259 }; 1260 1261 struct ContainsArray { 1262 NonTrivial arr[2]; 1263 ContainsArray& operator=(ContainsArray const&) = default; 1264 }; 1265 1266 void testIt() 1267 { 1268 ContainsArray ca1; 1269 ContainsArray ca2; 1270 ca2 = ca1; 1271 )cpp"; 1272 1273 auto CodeSuffix = "}"; 1274 1275 auto LoopBody = R"cpp( 1276 { 1277 1278 } 1279 )cpp"; 1280 1281 auto RawLoop = "for (auto i = 0; i != 5; ++i)"; 1282 1283 auto RangeLoop = "for (auto i : boost::irange(5))"; 1284 1285 // Expect to rewrite the raw loop to the ranged loop. 1286 // This works in TK_IgnoreUnlessSpelledInSource mode, but TK_AsIs 1287 // mode also matches the hidden for loop generated in the copy assignment 1288 // operator of ContainsArray. Transformer then fails to transform the code at 1289 // all. 1290 1291 auto RewriteInput = 1292 CodePrefix + RawLoop + LoopBody + RawLoop + LoopBody + CodeSuffix; 1293 1294 auto RewriteOutput = 1295 CodePrefix + RangeLoop + LoopBody + RangeLoop + LoopBody + CodeSuffix; 1296 auto MatchedLoop = forStmt( 1297 hasLoopInit(declStmt( 1298 hasSingleDecl(varDecl(hasInitializer(integerLiteral(equals(0)))) 1299 .bind("loopVar")))), 1300 hasCondition(binaryOperator(hasOperatorName("!="), 1301 hasLHS(ignoringImplicit(declRefExpr(to( 1302 varDecl(equalsBoundNode("loopVar")))))), 1303 hasRHS(expr().bind("upperBoundExpr")))), 1304 hasIncrement(unaryOperator(hasOperatorName("++"), 1305 hasUnaryOperand(declRefExpr(to( 1306 varDecl(equalsBoundNode("loopVar")))))) 1307 .bind("incrementOp"))); 1308 1309 auto RewriteRule = 1310 changeTo(transformer::enclose(node("loopVar"), node("incrementOp")), 1311 cat("auto ", name("loopVar"), " : boost::irange(", 1312 node("upperBoundExpr"), ")")); 1313 1314 testRule(makeRule(traverse(TK_IgnoreUnlessSpelledInSource, MatchedLoop), 1315 RewriteRule), 1316 RewriteInput, RewriteOutput); 1317 1318 testRuleFailure(makeRule(traverse(TK_AsIs, MatchedLoop), RewriteRule), 1319 RewriteInput); 1320 1321 } 1322 1323 TEST_F(TransformerTest, TemplateInstantiation) { 1324 1325 std::string NonTemplatesInput = R"cpp( 1326 struct S { 1327 int m_i; 1328 }; 1329 )cpp"; 1330 std::string NonTemplatesExpected = R"cpp( 1331 struct S { 1332 safe_int m_i; 1333 }; 1334 )cpp"; 1335 1336 std::string TemplatesInput = R"cpp( 1337 template<typename T> 1338 struct TemplStruct { 1339 TemplStruct() {} 1340 ~TemplStruct() {} 1341 1342 private: 1343 T m_t; 1344 }; 1345 1346 void instantiate() 1347 { 1348 TemplStruct<int> ti; 1349 } 1350 )cpp"; 1351 1352 auto MatchedField = fieldDecl(hasType(asString("int"))).bind("theField"); 1353 1354 // Changes the 'int' in 'S', but not the 'T' in 'TemplStruct': 1355 testRule(makeRule(traverse(TK_IgnoreUnlessSpelledInSource, MatchedField), 1356 changeTo(cat("safe_int ", name("theField"), ";"))), 1357 NonTemplatesInput + TemplatesInput, 1358 NonTemplatesExpected + TemplatesInput); 1359 1360 // In AsIs mode, template instantiations are modified, which is 1361 // often not desired: 1362 1363 std::string IncorrectTemplatesExpected = R"cpp( 1364 template<typename T> 1365 struct TemplStruct { 1366 TemplStruct() {} 1367 ~TemplStruct() {} 1368 1369 private: 1370 safe_int m_t; 1371 }; 1372 1373 void instantiate() 1374 { 1375 TemplStruct<int> ti; 1376 } 1377 )cpp"; 1378 1379 // Changes the 'int' in 'S', and (incorrectly) the 'T' in 'TemplStruct': 1380 testRule(makeRule(traverse(TK_AsIs, MatchedField), 1381 changeTo(cat("safe_int ", name("theField"), ";"))), 1382 1383 NonTemplatesInput + TemplatesInput, 1384 NonTemplatesExpected + IncorrectTemplatesExpected); 1385 } 1386 1387 // Transformation of macro source text when the change encompasses the entirety 1388 // of the expanded text. 1389 TEST_F(TransformerTest, SimpleMacro) { 1390 std::string Input = R"cc( 1391 #define ZERO 0 1392 int f(string s) { return ZERO; } 1393 )cc"; 1394 std::string Expected = R"cc( 1395 #define ZERO 0 1396 int f(string s) { return 999; } 1397 )cc"; 1398 1399 StringRef zero = "zero"; 1400 RewriteRule R = makeRule(integerLiteral(equals(0)).bind(zero), 1401 changeTo(node(std::string(zero)), cat("999"))); 1402 testRule(R, Input, Expected); 1403 } 1404 1405 // Transformation of macro source text when the change encompasses the entirety 1406 // of the expanded text, for the case of function-style macros. 1407 TEST_F(TransformerTest, FunctionMacro) { 1408 std::string Input = R"cc( 1409 #define MACRO(str) strlen((str).c_str()) 1410 int f(string s) { return MACRO(s); } 1411 )cc"; 1412 std::string Expected = R"cc( 1413 #define MACRO(str) strlen((str).c_str()) 1414 int f(string s) { return REPLACED; } 1415 )cc"; 1416 1417 testRule(ruleStrlenSize(), Input, Expected); 1418 } 1419 1420 // Tests that expressions in macro arguments can be rewritten. 1421 TEST_F(TransformerTest, MacroArg) { 1422 std::string Input = R"cc( 1423 #define PLUS(e) e + 1 1424 int f(string s) { return PLUS(strlen(s.c_str())); } 1425 )cc"; 1426 std::string Expected = R"cc( 1427 #define PLUS(e) e + 1 1428 int f(string s) { return PLUS(REPLACED); } 1429 )cc"; 1430 1431 testRule(ruleStrlenSize(), Input, Expected); 1432 } 1433 1434 // Tests that expressions in macro arguments can be rewritten, even when the 1435 // macro call occurs inside another macro's definition. 1436 TEST_F(TransformerTest, MacroArgInMacroDef) { 1437 std::string Input = R"cc( 1438 #define NESTED(e) e 1439 #define MACRO(str) NESTED(strlen((str).c_str())) 1440 int f(string s) { return MACRO(s); } 1441 )cc"; 1442 std::string Expected = R"cc( 1443 #define NESTED(e) e 1444 #define MACRO(str) NESTED(strlen((str).c_str())) 1445 int f(string s) { return REPLACED; } 1446 )cc"; 1447 1448 testRule(ruleStrlenSize(), Input, Expected); 1449 } 1450 1451 // Tests the corner case of the identity macro, specifically that it is 1452 // discarded in the rewrite rather than preserved (like PLUS is preserved in the 1453 // previous test). This behavior is of dubious value (and marked with a FIXME 1454 // in the code), but we test it to verify (and demonstrate) how this case is 1455 // handled. 1456 TEST_F(TransformerTest, IdentityMacro) { 1457 std::string Input = R"cc( 1458 #define ID(e) e 1459 int f(string s) { return ID(strlen(s.c_str())); } 1460 )cc"; 1461 std::string Expected = R"cc( 1462 #define ID(e) e 1463 int f(string s) { return REPLACED; } 1464 )cc"; 1465 1466 testRule(ruleStrlenSize(), Input, Expected); 1467 } 1468 1469 // Tests that two changes in a single macro expansion do not lead to conflicts 1470 // in applying the changes. 1471 TEST_F(TransformerTest, TwoChangesInOneMacroExpansion) { 1472 std::string Input = R"cc( 1473 #define PLUS(a,b) (a) + (b) 1474 int f() { return PLUS(3, 4); } 1475 )cc"; 1476 std::string Expected = R"cc( 1477 #define PLUS(a,b) (a) + (b) 1478 int f() { return PLUS(LIT, LIT); } 1479 )cc"; 1480 1481 testRule(makeRule(integerLiteral(), changeTo(cat("LIT"))), Input, Expected); 1482 } 1483 1484 // Tests case where the rule's match spans both source from the macro and its 1485 // arg, with the begin location (the "anchor") being the arg. 1486 TEST_F(TransformerTest, MatchSpansMacroTextButChangeDoesNot) { 1487 std::string Input = R"cc( 1488 #define PLUS_ONE(a) a + 1 1489 int f() { return PLUS_ONE(3); } 1490 )cc"; 1491 std::string Expected = R"cc( 1492 #define PLUS_ONE(a) a + 1 1493 int f() { return PLUS_ONE(LIT); } 1494 )cc"; 1495 1496 StringRef E = "expr"; 1497 testRule(makeRule(binaryOperator(hasLHS(expr().bind(E))), 1498 changeTo(node(std::string(E)), cat("LIT"))), 1499 Input, Expected); 1500 } 1501 1502 // Tests case where the rule's match spans both source from the macro and its 1503 // arg, with the begin location (the "anchor") being inside the macro. 1504 TEST_F(TransformerTest, MatchSpansMacroTextButChangeDoesNotAnchoredInMacro) { 1505 std::string Input = R"cc( 1506 #define PLUS_ONE(a) 1 + a 1507 int f() { return PLUS_ONE(3); } 1508 )cc"; 1509 std::string Expected = R"cc( 1510 #define PLUS_ONE(a) 1 + a 1511 int f() { return PLUS_ONE(LIT); } 1512 )cc"; 1513 1514 StringRef E = "expr"; 1515 testRule(makeRule(binaryOperator(hasRHS(expr().bind(E))), 1516 changeTo(node(std::string(E)), cat("LIT"))), 1517 Input, Expected); 1518 } 1519 1520 // No rewrite is applied when the changed text does not encompass the entirety 1521 // of the expanded text. That is, the edit would have to be applied to the 1522 // macro's definition to succeed and editing the expansion point would not 1523 // suffice. 1524 TEST_F(TransformerTest, NoPartialRewriteOMacroExpansion) { 1525 std::string Input = R"cc( 1526 #define ZERO_PLUS 0 + 3 1527 int f(string s) { return ZERO_PLUS; })cc"; 1528 1529 StringRef zero = "zero"; 1530 RewriteRule R = makeRule(integerLiteral(equals(0)).bind(zero), 1531 changeTo(node(std::string(zero)), cat("0"))); 1532 testRule(R, Input, Input); 1533 } 1534 1535 // This test handles the corner case where a macro expands within another macro 1536 // to matching code, but that code is an argument to the nested macro call. A 1537 // simple check of isMacroArgExpansion() vs. isMacroBodyExpansion() will get 1538 // this wrong, and transform the code. 1539 TEST_F(TransformerTest, NoPartialRewriteOfMacroExpansionForMacroArgs) { 1540 std::string Input = R"cc( 1541 #define NESTED(e) e 1542 #define MACRO(str) 1 + NESTED(strlen((str).c_str())) 1543 int f(string s) { return MACRO(s); } 1544 )cc"; 1545 1546 testRule(ruleStrlenSize(), Input, Input); 1547 } 1548 1549 #if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST 1550 // Verifies that `Type` and `QualType` are not allowed as top-level matchers in 1551 // rules. 1552 TEST(TransformerDeathTest, OrderedRuleTypes) { 1553 RewriteRule QualTypeRule = makeRule(qualType(), changeTo(cat("Q"))); 1554 EXPECT_DEATH(transformer::detail::buildMatchers(QualTypeRule), 1555 "Matcher must be.*node matcher"); 1556 1557 RewriteRule TypeRule = makeRule(arrayType(), changeTo(cat("T"))); 1558 EXPECT_DEATH(transformer::detail::buildMatchers(TypeRule), 1559 "Matcher must be.*node matcher"); 1560 } 1561 #endif 1562 1563 // Edits are able to span multiple files; in this case, a header and an 1564 // implementation file. 1565 TEST_F(TransformerTest, MultipleFiles) { 1566 std::string Header = R"cc(void RemoveThisFunction();)cc"; 1567 std::string Source = R"cc(#include "input.h" 1568 void RemoveThisFunction();)cc"; 1569 Transformer T( 1570 makeRule(functionDecl(hasName("RemoveThisFunction")), changeTo(cat(""))), 1571 consumer()); 1572 T.registerMatchers(&MatchFinder); 1573 auto Factory = newFrontendActionFactory(&MatchFinder); 1574 EXPECT_TRUE(runToolOnCodeWithArgs( 1575 Factory->create(), Source, std::vector<std::string>(), "input.cc", 1576 "clang-tool", std::make_shared<PCHContainerOperations>(), 1577 {{"input.h", Header}})); 1578 1579 std::sort(Changes.begin(), Changes.end(), 1580 [](const AtomicChange &L, const AtomicChange &R) { 1581 return L.getFilePath() < R.getFilePath(); 1582 }); 1583 1584 ASSERT_EQ(Changes[0].getFilePath(), "./input.h"); 1585 EXPECT_THAT(Changes[0].getInsertedHeaders(), IsEmpty()); 1586 EXPECT_THAT(Changes[0].getRemovedHeaders(), IsEmpty()); 1587 llvm::Expected<std::string> UpdatedCode = 1588 clang::tooling::applyAllReplacements(Header, 1589 Changes[0].getReplacements()); 1590 ASSERT_TRUE(static_cast<bool>(UpdatedCode)) 1591 << "Could not update code: " << llvm::toString(UpdatedCode.takeError()); 1592 EXPECT_EQ(format(*UpdatedCode), ""); 1593 1594 ASSERT_EQ(Changes[1].getFilePath(), "input.cc"); 1595 EXPECT_THAT(Changes[1].getInsertedHeaders(), IsEmpty()); 1596 EXPECT_THAT(Changes[1].getRemovedHeaders(), IsEmpty()); 1597 UpdatedCode = clang::tooling::applyAllReplacements( 1598 Source, Changes[1].getReplacements()); 1599 ASSERT_TRUE(static_cast<bool>(UpdatedCode)) 1600 << "Could not update code: " << llvm::toString(UpdatedCode.takeError()); 1601 EXPECT_EQ(format(*UpdatedCode), format("#include \"input.h\"\n")); 1602 } 1603 1604 TEST_F(TransformerTest, AddIncludeMultipleFiles) { 1605 std::string Header = R"cc(void RemoveThisFunction();)cc"; 1606 std::string Source = R"cc(#include "input.h" 1607 void Foo() {RemoveThisFunction();})cc"; 1608 Transformer T( 1609 makeRule(callExpr(callee( 1610 functionDecl(hasName("RemoveThisFunction")).bind("fun"))), 1611 addInclude(node("fun"), "header.h")), 1612 consumer()); 1613 T.registerMatchers(&MatchFinder); 1614 auto Factory = newFrontendActionFactory(&MatchFinder); 1615 EXPECT_TRUE(runToolOnCodeWithArgs( 1616 Factory->create(), Source, std::vector<std::string>(), "input.cc", 1617 "clang-tool", std::make_shared<PCHContainerOperations>(), 1618 {{"input.h", Header}})); 1619 1620 ASSERT_EQ(Changes.size(), 1U); 1621 ASSERT_EQ(Changes[0].getFilePath(), "./input.h"); 1622 EXPECT_THAT(Changes[0].getInsertedHeaders(), ElementsAre("header.h")); 1623 EXPECT_THAT(Changes[0].getRemovedHeaders(), IsEmpty()); 1624 llvm::Expected<std::string> UpdatedCode = 1625 clang::tooling::applyAllReplacements(Header, 1626 Changes[0].getReplacements()); 1627 ASSERT_TRUE(static_cast<bool>(UpdatedCode)) 1628 << "Could not update code: " << llvm::toString(UpdatedCode.takeError()); 1629 EXPECT_EQ(format(*UpdatedCode), format(Header)); 1630 } 1631 } // namespace 1632