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