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