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