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( 1270 hasSingleDecl(varDecl(hasInitializer(integerLiteral(equals(0)))) 1271 .bind("loopVar")))), 1272 has(binaryOperator(hasOperatorName("!="), 1273 hasLHS(ignoringImplicit(declRefExpr( 1274 to(varDecl(equalsBoundNode("loopVar")))))), 1275 hasRHS(expr().bind("upperBoundExpr")))), 1276 has(unaryOperator(hasOperatorName("++"), 1277 hasUnaryOperand(declRefExpr( 1278 to(varDecl(equalsBoundNode("loopVar")))))) 1279 .bind("incrementOp"))); 1280 1281 auto RewriteRule = 1282 changeTo(transformer::enclose(node("loopVar"), node("incrementOp")), 1283 cat("auto ", name("loopVar"), " : boost::irange(", 1284 node("upperBoundExpr"), ")")); 1285 1286 testRule(makeRule(traverse(TK_IgnoreUnlessSpelledInSource, MatchedLoop), 1287 RewriteRule), 1288 RewriteInput, RewriteOutput); 1289 1290 testRuleFailure(makeRule(traverse(TK_AsIs, MatchedLoop), RewriteRule), 1291 RewriteInput); 1292 1293 } 1294 1295 TEST_F(TransformerTest, ImplicitNodes_ForStmt2) { 1296 1297 std::string CodePrefix = R"cpp( 1298 struct NonTrivial { 1299 NonTrivial() {} 1300 NonTrivial(NonTrivial&) {} 1301 NonTrivial& operator=(NonTrivial const&) { return *this; } 1302 1303 ~NonTrivial() {} 1304 }; 1305 1306 struct ContainsArray { 1307 NonTrivial arr[2]; 1308 ContainsArray& operator=(ContainsArray const&) = default; 1309 }; 1310 1311 void testIt() 1312 { 1313 ContainsArray ca1; 1314 ContainsArray ca2; 1315 ca2 = ca1; 1316 )cpp"; 1317 1318 auto CodeSuffix = "}"; 1319 1320 auto LoopBody = R"cpp( 1321 { 1322 1323 } 1324 )cpp"; 1325 1326 auto RawLoop = "for (auto i = 0; i != 5; ++i)"; 1327 1328 auto RangeLoop = "for (auto i : boost::irange(5))"; 1329 1330 // Expect to rewrite the raw loop to the ranged loop. 1331 // This works in TK_IgnoreUnlessSpelledInSource mode, but TK_AsIs 1332 // mode also matches the hidden for loop generated in the copy assignment 1333 // operator of ContainsArray. Transformer then fails to transform the code at 1334 // all. 1335 1336 auto RewriteInput = 1337 CodePrefix + RawLoop + LoopBody + RawLoop + LoopBody + CodeSuffix; 1338 1339 auto RewriteOutput = 1340 CodePrefix + RangeLoop + LoopBody + RangeLoop + LoopBody + CodeSuffix; 1341 auto MatchedLoop = forStmt( 1342 hasLoopInit(declStmt( 1343 hasSingleDecl(varDecl(hasInitializer(integerLiteral(equals(0)))) 1344 .bind("loopVar")))), 1345 hasCondition(binaryOperator(hasOperatorName("!="), 1346 hasLHS(ignoringImplicit(declRefExpr(to( 1347 varDecl(equalsBoundNode("loopVar")))))), 1348 hasRHS(expr().bind("upperBoundExpr")))), 1349 hasIncrement(unaryOperator(hasOperatorName("++"), 1350 hasUnaryOperand(declRefExpr(to( 1351 varDecl(equalsBoundNode("loopVar")))))) 1352 .bind("incrementOp"))); 1353 1354 auto RewriteRule = 1355 changeTo(transformer::enclose(node("loopVar"), node("incrementOp")), 1356 cat("auto ", name("loopVar"), " : boost::irange(", 1357 node("upperBoundExpr"), ")")); 1358 1359 testRule(makeRule(traverse(TK_IgnoreUnlessSpelledInSource, MatchedLoop), 1360 RewriteRule), 1361 RewriteInput, RewriteOutput); 1362 1363 testRuleFailure(makeRule(traverse(TK_AsIs, MatchedLoop), RewriteRule), 1364 RewriteInput); 1365 1366 } 1367 1368 TEST_F(TransformerTest, TemplateInstantiation) { 1369 1370 std::string NonTemplatesInput = R"cpp( 1371 struct S { 1372 int m_i; 1373 }; 1374 )cpp"; 1375 std::string NonTemplatesExpected = R"cpp( 1376 struct S { 1377 safe_int m_i; 1378 }; 1379 )cpp"; 1380 1381 std::string TemplatesInput = R"cpp( 1382 template<typename T> 1383 struct TemplStruct { 1384 TemplStruct() {} 1385 ~TemplStruct() {} 1386 1387 private: 1388 T m_t; 1389 }; 1390 1391 void instantiate() 1392 { 1393 TemplStruct<int> ti; 1394 } 1395 )cpp"; 1396 1397 auto MatchedField = fieldDecl(hasType(asString("int"))).bind("theField"); 1398 1399 // Changes the 'int' in 'S', but not the 'T' in 'TemplStruct': 1400 testRule(makeRule(traverse(TK_IgnoreUnlessSpelledInSource, MatchedField), 1401 changeTo(cat("safe_int ", name("theField"), ";"))), 1402 NonTemplatesInput + TemplatesInput, 1403 NonTemplatesExpected + TemplatesInput); 1404 1405 // In AsIs mode, template instantiations are modified, which is 1406 // often not desired: 1407 1408 std::string IncorrectTemplatesExpected = R"cpp( 1409 template<typename T> 1410 struct TemplStruct { 1411 TemplStruct() {} 1412 ~TemplStruct() {} 1413 1414 private: 1415 safe_int m_t; 1416 }; 1417 1418 void instantiate() 1419 { 1420 TemplStruct<int> ti; 1421 } 1422 )cpp"; 1423 1424 // Changes the 'int' in 'S', and (incorrectly) the 'T' in 'TemplStruct': 1425 testRule(makeRule(traverse(TK_AsIs, MatchedField), 1426 changeTo(cat("safe_int ", name("theField"), ";"))), 1427 1428 NonTemplatesInput + TemplatesInput, 1429 NonTemplatesExpected + IncorrectTemplatesExpected); 1430 } 1431 1432 // Transformation of macro source text when the change encompasses the entirety 1433 // of the expanded text. 1434 TEST_F(TransformerTest, SimpleMacro) { 1435 std::string Input = R"cc( 1436 #define ZERO 0 1437 int f(string s) { return ZERO; } 1438 )cc"; 1439 std::string Expected = R"cc( 1440 #define ZERO 0 1441 int f(string s) { return 999; } 1442 )cc"; 1443 1444 StringRef zero = "zero"; 1445 RewriteRule R = makeRule(integerLiteral(equals(0)).bind(zero), 1446 changeTo(node(std::string(zero)), cat("999"))); 1447 testRule(R, Input, Expected); 1448 } 1449 1450 // Transformation of macro source text when the change encompasses the entirety 1451 // of the expanded text, for the case of function-style macros. 1452 TEST_F(TransformerTest, FunctionMacro) { 1453 std::string Input = R"cc( 1454 #define MACRO(str) strlen((str).c_str()) 1455 int f(string s) { return MACRO(s); } 1456 )cc"; 1457 std::string Expected = R"cc( 1458 #define MACRO(str) strlen((str).c_str()) 1459 int f(string s) { return REPLACED; } 1460 )cc"; 1461 1462 testRule(ruleStrlenSize(), Input, Expected); 1463 } 1464 1465 // Tests that expressions in macro arguments can be rewritten. 1466 TEST_F(TransformerTest, MacroArg) { 1467 std::string Input = R"cc( 1468 #define PLUS(e) e + 1 1469 int f(string s) { return PLUS(strlen(s.c_str())); } 1470 )cc"; 1471 std::string Expected = R"cc( 1472 #define PLUS(e) e + 1 1473 int f(string s) { return PLUS(REPLACED); } 1474 )cc"; 1475 1476 testRule(ruleStrlenSize(), Input, Expected); 1477 } 1478 1479 // Tests that expressions in macro arguments can be rewritten, even when the 1480 // macro call occurs inside another macro's definition. 1481 TEST_F(TransformerTest, MacroArgInMacroDef) { 1482 std::string Input = R"cc( 1483 #define NESTED(e) e 1484 #define MACRO(str) NESTED(strlen((str).c_str())) 1485 int f(string s) { return MACRO(s); } 1486 )cc"; 1487 std::string Expected = R"cc( 1488 #define NESTED(e) e 1489 #define MACRO(str) NESTED(strlen((str).c_str())) 1490 int f(string s) { return REPLACED; } 1491 )cc"; 1492 1493 testRule(ruleStrlenSize(), Input, Expected); 1494 } 1495 1496 // Tests the corner case of the identity macro, specifically that it is 1497 // discarded in the rewrite rather than preserved (like PLUS is preserved in the 1498 // previous test). This behavior is of dubious value (and marked with a FIXME 1499 // in the code), but we test it to verify (and demonstrate) how this case is 1500 // handled. 1501 TEST_F(TransformerTest, IdentityMacro) { 1502 std::string Input = R"cc( 1503 #define ID(e) e 1504 int f(string s) { return ID(strlen(s.c_str())); } 1505 )cc"; 1506 std::string Expected = R"cc( 1507 #define ID(e) e 1508 int f(string s) { return REPLACED; } 1509 )cc"; 1510 1511 testRule(ruleStrlenSize(), Input, Expected); 1512 } 1513 1514 // Tests that two changes in a single macro expansion do not lead to conflicts 1515 // in applying the changes. 1516 TEST_F(TransformerTest, TwoChangesInOneMacroExpansion) { 1517 std::string Input = R"cc( 1518 #define PLUS(a,b) (a) + (b) 1519 int f() { return PLUS(3, 4); } 1520 )cc"; 1521 std::string Expected = R"cc( 1522 #define PLUS(a,b) (a) + (b) 1523 int f() { return PLUS(LIT, LIT); } 1524 )cc"; 1525 1526 testRule(makeRule(integerLiteral(), changeTo(cat("LIT"))), Input, Expected); 1527 } 1528 1529 // Tests case where the rule's match spans both source from the macro and its 1530 // arg, with the begin location (the "anchor") being the arg. 1531 TEST_F(TransformerTest, MatchSpansMacroTextButChangeDoesNot) { 1532 std::string Input = R"cc( 1533 #define PLUS_ONE(a) a + 1 1534 int f() { return PLUS_ONE(3); } 1535 )cc"; 1536 std::string Expected = R"cc( 1537 #define PLUS_ONE(a) a + 1 1538 int f() { return PLUS_ONE(LIT); } 1539 )cc"; 1540 1541 StringRef E = "expr"; 1542 testRule(makeRule(binaryOperator(hasLHS(expr().bind(E))), 1543 changeTo(node(std::string(E)), cat("LIT"))), 1544 Input, Expected); 1545 } 1546 1547 // Tests case where the rule's match spans both source from the macro and its 1548 // arg, with the begin location (the "anchor") being inside the macro. 1549 TEST_F(TransformerTest, MatchSpansMacroTextButChangeDoesNotAnchoredInMacro) { 1550 std::string Input = R"cc( 1551 #define PLUS_ONE(a) 1 + a 1552 int f() { return PLUS_ONE(3); } 1553 )cc"; 1554 std::string Expected = R"cc( 1555 #define PLUS_ONE(a) 1 + a 1556 int f() { return PLUS_ONE(LIT); } 1557 )cc"; 1558 1559 StringRef E = "expr"; 1560 testRule(makeRule(binaryOperator(hasRHS(expr().bind(E))), 1561 changeTo(node(std::string(E)), cat("LIT"))), 1562 Input, Expected); 1563 } 1564 1565 // No rewrite is applied when the changed text does not encompass the entirety 1566 // of the expanded text. That is, the edit would have to be applied to the 1567 // macro's definition to succeed and editing the expansion point would not 1568 // suffice. 1569 TEST_F(TransformerTest, NoPartialRewriteOMacroExpansion) { 1570 std::string Input = R"cc( 1571 #define ZERO_PLUS 0 + 3 1572 int f(string s) { return ZERO_PLUS; })cc"; 1573 1574 StringRef zero = "zero"; 1575 RewriteRule R = makeRule(integerLiteral(equals(0)).bind(zero), 1576 changeTo(node(std::string(zero)), cat("0"))); 1577 testRule(R, Input, Input); 1578 } 1579 1580 // This test handles the corner case where a macro expands within another macro 1581 // to matching code, but that code is an argument to the nested macro call. A 1582 // simple check of isMacroArgExpansion() vs. isMacroBodyExpansion() will get 1583 // this wrong, and transform the code. 1584 TEST_F(TransformerTest, NoPartialRewriteOfMacroExpansionForMacroArgs) { 1585 std::string Input = R"cc( 1586 #define NESTED(e) e 1587 #define MACRO(str) 1 + NESTED(strlen((str).c_str())) 1588 int f(string s) { return MACRO(s); } 1589 )cc"; 1590 1591 testRule(ruleStrlenSize(), Input, Input); 1592 } 1593 1594 #if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST 1595 // Verifies that `Type` and `QualType` are not allowed as top-level matchers in 1596 // rules. 1597 TEST(TransformerDeathTest, OrderedRuleTypes) { 1598 RewriteRule QualTypeRule = makeRule(qualType(), changeTo(cat("Q"))); 1599 EXPECT_DEATH(transformer::detail::buildMatchers(QualTypeRule), 1600 "Matcher must be.*node matcher"); 1601 1602 RewriteRule TypeRule = makeRule(arrayType(), changeTo(cat("T"))); 1603 EXPECT_DEATH(transformer::detail::buildMatchers(TypeRule), 1604 "Matcher must be.*node matcher"); 1605 } 1606 #endif 1607 1608 // Edits are able to span multiple files; in this case, a header and an 1609 // implementation file. 1610 TEST_F(TransformerTest, MultipleFiles) { 1611 std::string Header = R"cc(void RemoveThisFunction();)cc"; 1612 std::string Source = R"cc(#include "input.h" 1613 void RemoveThisFunction();)cc"; 1614 Transformer T( 1615 makeRule(functionDecl(hasName("RemoveThisFunction")), changeTo(cat(""))), 1616 consumer()); 1617 T.registerMatchers(&MatchFinder); 1618 auto Factory = newFrontendActionFactory(&MatchFinder); 1619 EXPECT_TRUE(runToolOnCodeWithArgs( 1620 Factory->create(), Source, std::vector<std::string>(), "input.cc", 1621 "clang-tool", std::make_shared<PCHContainerOperations>(), 1622 {{"input.h", Header}})); 1623 1624 std::sort(Changes.begin(), Changes.end(), 1625 [](const AtomicChange &L, const AtomicChange &R) { 1626 return L.getFilePath() < R.getFilePath(); 1627 }); 1628 1629 ASSERT_EQ(Changes[0].getFilePath(), "./input.h"); 1630 EXPECT_THAT(Changes[0].getInsertedHeaders(), IsEmpty()); 1631 EXPECT_THAT(Changes[0].getRemovedHeaders(), IsEmpty()); 1632 llvm::Expected<std::string> UpdatedCode = 1633 clang::tooling::applyAllReplacements(Header, 1634 Changes[0].getReplacements()); 1635 ASSERT_TRUE(static_cast<bool>(UpdatedCode)) 1636 << "Could not update code: " << llvm::toString(UpdatedCode.takeError()); 1637 EXPECT_EQ(format(*UpdatedCode), ""); 1638 1639 ASSERT_EQ(Changes[1].getFilePath(), "input.cc"); 1640 EXPECT_THAT(Changes[1].getInsertedHeaders(), IsEmpty()); 1641 EXPECT_THAT(Changes[1].getRemovedHeaders(), IsEmpty()); 1642 UpdatedCode = clang::tooling::applyAllReplacements( 1643 Source, Changes[1].getReplacements()); 1644 ASSERT_TRUE(static_cast<bool>(UpdatedCode)) 1645 << "Could not update code: " << llvm::toString(UpdatedCode.takeError()); 1646 EXPECT_EQ(format(*UpdatedCode), format("#include \"input.h\"\n")); 1647 } 1648 1649 TEST_F(TransformerTest, AddIncludeMultipleFiles) { 1650 std::string Header = R"cc(void RemoveThisFunction();)cc"; 1651 std::string Source = R"cc(#include "input.h" 1652 void Foo() {RemoveThisFunction();})cc"; 1653 Transformer T( 1654 makeRule(callExpr(callee( 1655 functionDecl(hasName("RemoveThisFunction")).bind("fun"))), 1656 addInclude(node("fun"), "header.h")), 1657 consumer()); 1658 T.registerMatchers(&MatchFinder); 1659 auto Factory = newFrontendActionFactory(&MatchFinder); 1660 EXPECT_TRUE(runToolOnCodeWithArgs( 1661 Factory->create(), Source, std::vector<std::string>(), "input.cc", 1662 "clang-tool", std::make_shared<PCHContainerOperations>(), 1663 {{"input.h", Header}})); 1664 1665 ASSERT_EQ(Changes.size(), 1U); 1666 ASSERT_EQ(Changes[0].getFilePath(), "./input.h"); 1667 EXPECT_THAT(Changes[0].getInsertedHeaders(), ElementsAre("header.h")); 1668 EXPECT_THAT(Changes[0].getRemovedHeaders(), IsEmpty()); 1669 llvm::Expected<std::string> UpdatedCode = 1670 clang::tooling::applyAllReplacements(Header, 1671 Changes[0].getReplacements()); 1672 ASSERT_TRUE(static_cast<bool>(UpdatedCode)) 1673 << "Could not update code: " << llvm::toString(UpdatedCode.takeError()); 1674 EXPECT_EQ(format(*UpdatedCode), format(Header)); 1675 } 1676 1677 // A single change set can span multiple files. 1678 TEST_F(TransformerTest, MultiFileEdit) { 1679 // NB: The fixture is unused for this test, but kept for the test suite name. 1680 std::string Header = R"cc(void Func(int id);)cc"; 1681 std::string Source = R"cc(#include "input.h" 1682 void Caller() { 1683 int id = 0; 1684 Func(id); 1685 })cc"; 1686 int ErrorCount = 0; 1687 std::vector<AtomicChanges> ChangeSets; 1688 clang::ast_matchers::MatchFinder MatchFinder; 1689 Transformer T( 1690 makeRule(callExpr(callee(functionDecl(hasName("Func"))), 1691 forEachArgumentWithParam(expr().bind("arg"), 1692 parmVarDecl().bind("param"))), 1693 {changeTo(node("arg"), cat("ARG")), 1694 changeTo(node("param"), cat("PARAM"))}), 1695 [&](Expected<MutableArrayRef<AtomicChange>> Changes) { 1696 if (Changes) 1697 ChangeSets.push_back(AtomicChanges(Changes->begin(), Changes->end())); 1698 else 1699 ++ErrorCount; 1700 }); 1701 T.registerMatchers(&MatchFinder); 1702 auto Factory = newFrontendActionFactory(&MatchFinder); 1703 EXPECT_TRUE(runToolOnCodeWithArgs( 1704 Factory->create(), Source, std::vector<std::string>(), "input.cc", 1705 "clang-tool", std::make_shared<PCHContainerOperations>(), 1706 {{"input.h", Header}})); 1707 1708 EXPECT_EQ(ErrorCount, 0); 1709 EXPECT_THAT( 1710 ChangeSets, 1711 UnorderedElementsAre(UnorderedElementsAre( 1712 ResultOf([](const AtomicChange &C) { return C.getFilePath(); }, 1713 "input.cc"), 1714 ResultOf([](const AtomicChange &C) { return C.getFilePath(); }, 1715 "./input.h")))); 1716 } 1717 1718 TEST_F(TransformerTest, GeneratesMetadata) { 1719 std::string Input = R"cc(int target = 0;)cc"; 1720 std::string Expected = R"cc(REPLACE)cc"; 1721 RewriteRuleWith<std::string> Rule = makeRule( 1722 varDecl(hasName("target")), changeTo(cat("REPLACE")), cat("METADATA")); 1723 testRule(std::move(Rule), Input, Expected); 1724 EXPECT_EQ(ErrorCount, 0); 1725 EXPECT_THAT(StringMetadata, UnorderedElementsAre("METADATA")); 1726 } 1727 1728 TEST_F(TransformerTest, GeneratesMetadataWithNoEdits) { 1729 std::string Input = R"cc(int target = 0;)cc"; 1730 RewriteRuleWith<std::string> Rule = makeRule( 1731 varDecl(hasName("target")).bind("var"), noEdits(), cat("METADATA")); 1732 testRule(std::move(Rule), Input, Input); 1733 EXPECT_EQ(ErrorCount, 0); 1734 EXPECT_THAT(StringMetadata, UnorderedElementsAre("METADATA")); 1735 } 1736 1737 TEST_F(TransformerTest, PropagateMetadataErrors) { 1738 class AlwaysFail : public transformer::MatchComputation<std::string> { 1739 llvm::Error eval(const ast_matchers::MatchFinder::MatchResult &, 1740 std::string *) const override { 1741 return llvm::createStringError(llvm::errc::invalid_argument, "ERROR"); 1742 } 1743 std::string toString() const override { return "AlwaysFail"; } 1744 }; 1745 std::string Input = R"cc(int target = 0;)cc"; 1746 RewriteRuleWith<std::string> Rule = makeRule<std::string>( 1747 varDecl(hasName("target")).bind("var"), changeTo(cat("REPLACE")), 1748 std::make_shared<AlwaysFail>()); 1749 testRuleFailure(std::move(Rule), Input); 1750 EXPECT_EQ(ErrorCount, 1); 1751 } 1752 1753 } // namespace 1754