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