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