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/Refactoring/Transformer.h" 10 #include "clang/ASTMatchers/ASTMatchers.h" 11 #include "clang/Tooling/Refactoring/RangeSelector.h" 12 #include "clang/Tooling/Tooling.h" 13 #include "llvm/Support/Errc.h" 14 #include "llvm/Support/Error.h" 15 #include "gmock/gmock.h" 16 #include "gtest/gtest.h" 17 18 using namespace clang; 19 using namespace tooling; 20 using namespace ast_matchers; 21 22 namespace { 23 using ::testing::IsEmpty; 24 25 constexpr char KHeaderContents[] = R"cc( 26 struct string { 27 string(const char*); 28 char* c_str(); 29 int size(); 30 }; 31 int strlen(const char*); 32 33 namespace proto { 34 struct PCFProto { 35 int foo(); 36 }; 37 struct ProtoCommandLineFlag : PCFProto { 38 PCFProto& GetProto(); 39 }; 40 } // namespace proto 41 class Logger {}; 42 void operator<<(Logger& l, string msg); 43 Logger& log(int level); 44 )cc"; 45 46 static ast_matchers::internal::Matcher<clang::QualType> 47 isOrPointsTo(const clang::ast_matchers::DeclarationMatcher &TypeMatcher) { 48 return anyOf(hasDeclaration(TypeMatcher), pointsTo(TypeMatcher)); 49 } 50 51 static std::string format(StringRef Code) { 52 const std::vector<Range> Ranges(1, Range(0, Code.size())); 53 auto Style = format::getLLVMStyle(); 54 const auto Replacements = format::reformat(Style, Code, Ranges); 55 auto Formatted = applyAllReplacements(Code, Replacements); 56 if (!Formatted) { 57 ADD_FAILURE() << "Could not format code: " 58 << llvm::toString(Formatted.takeError()); 59 return std::string(); 60 } 61 return *Formatted; 62 } 63 64 static void compareSnippets(StringRef Expected, 65 const llvm::Optional<std::string> &MaybeActual) { 66 ASSERT_TRUE(MaybeActual) << "Rewrite failed. Expecting: " << Expected; 67 auto Actual = *MaybeActual; 68 std::string HL = "#include \"header.h\"\n"; 69 auto I = Actual.find(HL); 70 if (I != std::string::npos) 71 Actual.erase(I, HL.size()); 72 EXPECT_EQ(format(Expected), format(Actual)); 73 } 74 75 // FIXME: consider separating this class into its own file(s). 76 class ClangRefactoringTestBase : public testing::Test { 77 protected: 78 void appendToHeader(StringRef S) { FileContents[0].second += S; } 79 80 void addFile(StringRef Filename, StringRef Content) { 81 FileContents.emplace_back(Filename, Content); 82 } 83 84 llvm::Optional<std::string> rewrite(StringRef Input) { 85 std::string Code = ("#include \"header.h\"\n" + Input).str(); 86 auto Factory = newFrontendActionFactory(&MatchFinder); 87 if (!runToolOnCodeWithArgs( 88 Factory->create(), Code, std::vector<std::string>(), "input.cc", 89 "clang-tool", std::make_shared<PCHContainerOperations>(), 90 FileContents)) { 91 llvm::errs() << "Running tool failed.\n"; 92 return None; 93 } 94 if (ErrorCount != 0) { 95 llvm::errs() << "Generating changes failed.\n"; 96 return None; 97 } 98 auto ChangedCode = 99 applyAtomicChanges("input.cc", Code, Changes, ApplyChangesSpec()); 100 if (!ChangedCode) { 101 llvm::errs() << "Applying changes failed: " 102 << llvm::toString(ChangedCode.takeError()) << "\n"; 103 return None; 104 } 105 return *ChangedCode; 106 } 107 108 Transformer::ChangeConsumer consumer() { 109 return [this](Expected<AtomicChange> C) { 110 if (C) { 111 Changes.push_back(std::move(*C)); 112 } else { 113 consumeError(C.takeError()); 114 ++ErrorCount; 115 } 116 }; 117 } 118 119 template <typename R> 120 void testRule(R Rule, StringRef Input, StringRef Expected) { 121 Transformer T(std::move(Rule), consumer()); 122 T.registerMatchers(&MatchFinder); 123 compareSnippets(Expected, rewrite(Input)); 124 } 125 126 clang::ast_matchers::MatchFinder MatchFinder; 127 // Records whether any errors occurred in individual changes. 128 int ErrorCount = 0; 129 AtomicChanges Changes; 130 131 private: 132 FileContentMappings FileContents = {{"header.h", ""}}; 133 }; 134 135 class TransformerTest : public ClangRefactoringTestBase { 136 protected: 137 TransformerTest() { appendToHeader(KHeaderContents); } 138 }; 139 140 // Given string s, change strlen($s.c_str()) to REPLACED. 141 static RewriteRule ruleStrlenSize() { 142 StringRef StringExpr = "strexpr"; 143 auto StringType = namedDecl(hasAnyName("::basic_string", "::string")); 144 auto R = makeRule( 145 callExpr(callee(functionDecl(hasName("strlen"))), 146 hasArgument(0, cxxMemberCallExpr( 147 on(expr(hasType(isOrPointsTo(StringType))) 148 .bind(StringExpr)), 149 callee(cxxMethodDecl(hasName("c_str")))))), 150 change(text("REPLACED")), text("Use size() method directly on string.")); 151 return R; 152 } 153 154 TEST_F(TransformerTest, StrlenSize) { 155 std::string Input = "int f(string s) { return strlen(s.c_str()); }"; 156 std::string Expected = "int f(string s) { return REPLACED; }"; 157 testRule(ruleStrlenSize(), Input, Expected); 158 } 159 160 // Tests that no change is applied when a match is not expected. 161 TEST_F(TransformerTest, NoMatch) { 162 std::string Input = "int f(string s) { return s.size(); }"; 163 testRule(ruleStrlenSize(), Input, Input); 164 } 165 166 // Tests replacing an expression. 167 TEST_F(TransformerTest, Flag) { 168 StringRef Flag = "flag"; 169 RewriteRule Rule = makeRule( 170 cxxMemberCallExpr(on(expr(hasType(cxxRecordDecl( 171 hasName("proto::ProtoCommandLineFlag")))) 172 .bind(Flag)), 173 unless(callee(cxxMethodDecl(hasName("GetProto"))))), 174 change(node(Flag), text("EXPR"))); 175 176 std::string Input = R"cc( 177 proto::ProtoCommandLineFlag flag; 178 int x = flag.foo(); 179 int y = flag.GetProto().foo(); 180 )cc"; 181 std::string Expected = R"cc( 182 proto::ProtoCommandLineFlag flag; 183 int x = EXPR.foo(); 184 int y = flag.GetProto().foo(); 185 )cc"; 186 187 testRule(std::move(Rule), Input, Expected); 188 } 189 190 TEST_F(TransformerTest, AddIncludeQuoted) { 191 RewriteRule Rule = makeRule(callExpr(callee(functionDecl(hasName("f")))), 192 change(text("other()"))); 193 addInclude(Rule, "clang/OtherLib.h"); 194 195 std::string Input = R"cc( 196 int f(int x); 197 int h(int x) { return f(x); } 198 )cc"; 199 std::string Expected = R"cc(#include "clang/OtherLib.h" 200 201 int f(int x); 202 int h(int x) { return other(); } 203 )cc"; 204 205 testRule(Rule, Input, Expected); 206 } 207 208 TEST_F(TransformerTest, AddIncludeAngled) { 209 RewriteRule Rule = makeRule(callExpr(callee(functionDecl(hasName("f")))), 210 change(text("other()"))); 211 addInclude(Rule, "clang/OtherLib.h", IncludeFormat::Angled); 212 213 std::string Input = R"cc( 214 int f(int x); 215 int h(int x) { return f(x); } 216 )cc"; 217 std::string Expected = R"cc(#include <clang/OtherLib.h> 218 219 int f(int x); 220 int h(int x) { return other(); } 221 )cc"; 222 223 testRule(Rule, Input, Expected); 224 } 225 226 TEST_F(TransformerTest, NodePartNameNamedDecl) { 227 StringRef Fun = "fun"; 228 RewriteRule Rule = makeRule(functionDecl(hasName("bad")).bind(Fun), 229 change(name(Fun), text("good"))); 230 231 std::string Input = R"cc( 232 int bad(int x); 233 int bad(int x) { return x * x; } 234 )cc"; 235 std::string Expected = R"cc( 236 int good(int x); 237 int good(int x) { return x * x; } 238 )cc"; 239 240 testRule(Rule, Input, Expected); 241 } 242 243 TEST_F(TransformerTest, NodePartNameDeclRef) { 244 std::string Input = R"cc( 245 template <typename T> 246 T bad(T x) { 247 return x; 248 } 249 int neutral(int x) { return bad<int>(x) * x; } 250 )cc"; 251 std::string Expected = R"cc( 252 template <typename T> 253 T bad(T x) { 254 return x; 255 } 256 int neutral(int x) { return good<int>(x) * x; } 257 )cc"; 258 259 StringRef Ref = "ref"; 260 testRule(makeRule(declRefExpr(to(functionDecl(hasName("bad")))).bind(Ref), 261 change(name(Ref), text("good"))), 262 Input, Expected); 263 } 264 265 TEST_F(TransformerTest, NodePartNameDeclRefFailure) { 266 std::string Input = R"cc( 267 struct Y { 268 int operator*(); 269 }; 270 int neutral(int x) { 271 Y y; 272 int (Y::*ptr)() = &Y::operator*; 273 return *y + x; 274 } 275 )cc"; 276 277 StringRef Ref = "ref"; 278 Transformer T(makeRule(declRefExpr(to(functionDecl())).bind(Ref), 279 change(name(Ref), text("good"))), 280 consumer()); 281 T.registerMatchers(&MatchFinder); 282 EXPECT_FALSE(rewrite(Input)); 283 } 284 285 TEST_F(TransformerTest, NodePartMember) { 286 StringRef E = "expr"; 287 RewriteRule Rule = makeRule(memberExpr(member(hasName("bad"))).bind(E), 288 change(member(E), text("good"))); 289 290 std::string Input = R"cc( 291 struct S { 292 int bad; 293 }; 294 int g() { 295 S s; 296 return s.bad; 297 } 298 )cc"; 299 std::string Expected = R"cc( 300 struct S { 301 int bad; 302 }; 303 int g() { 304 S s; 305 return s.good; 306 } 307 )cc"; 308 309 testRule(Rule, Input, Expected); 310 } 311 312 TEST_F(TransformerTest, NodePartMemberQualified) { 313 std::string Input = R"cc( 314 struct S { 315 int bad; 316 int good; 317 }; 318 struct T : public S { 319 int bad; 320 }; 321 int g() { 322 T t; 323 return t.S::bad; 324 } 325 )cc"; 326 std::string Expected = R"cc( 327 struct S { 328 int bad; 329 int good; 330 }; 331 struct T : public S { 332 int bad; 333 }; 334 int g() { 335 T t; 336 return t.S::good; 337 } 338 )cc"; 339 340 StringRef E = "expr"; 341 testRule(makeRule(memberExpr().bind(E), change(member(E), text("good"))), 342 Input, Expected); 343 } 344 345 TEST_F(TransformerTest, NodePartMemberMultiToken) { 346 std::string Input = R"cc( 347 struct Y { 348 int operator*(); 349 int good(); 350 template <typename T> void foo(T t); 351 }; 352 int neutral(int x) { 353 Y y; 354 y.template foo<int>(3); 355 return y.operator *(); 356 } 357 )cc"; 358 std::string Expected = R"cc( 359 struct Y { 360 int operator*(); 361 int good(); 362 template <typename T> void foo(T t); 363 }; 364 int neutral(int x) { 365 Y y; 366 y.template good<int>(3); 367 return y.good(); 368 } 369 )cc"; 370 371 StringRef MemExpr = "member"; 372 testRule(makeRule(memberExpr().bind(MemExpr), 373 change(member(MemExpr), text("good"))), 374 Input, Expected); 375 } 376 377 TEST_F(TransformerTest, InsertBeforeEdit) { 378 std::string Input = R"cc( 379 int f() { 380 return 7; 381 } 382 )cc"; 383 std::string Expected = R"cc( 384 int f() { 385 int y = 3; 386 return 7; 387 } 388 )cc"; 389 390 StringRef Ret = "return"; 391 testRule(makeRule(returnStmt().bind(Ret), 392 insertBefore(statement(Ret), text("int y = 3;"))), 393 Input, Expected); 394 } 395 396 TEST_F(TransformerTest, InsertAfterEdit) { 397 std::string Input = R"cc( 398 int f() { 399 int x = 5; 400 return 7; 401 } 402 )cc"; 403 std::string Expected = R"cc( 404 int f() { 405 int x = 5; 406 int y = 3; 407 return 7; 408 } 409 )cc"; 410 411 StringRef Decl = "decl"; 412 testRule(makeRule(declStmt().bind(Decl), 413 insertAfter(statement(Decl), text("int y = 3;"))), 414 Input, Expected); 415 } 416 417 TEST_F(TransformerTest, RemoveEdit) { 418 std::string Input = R"cc( 419 int f() { 420 int x = 5; 421 return 7; 422 } 423 )cc"; 424 std::string Expected = R"cc( 425 int f() { 426 return 7; 427 } 428 )cc"; 429 430 StringRef Decl = "decl"; 431 testRule(makeRule(declStmt().bind(Decl), remove(statement(Decl))), Input, 432 Expected); 433 } 434 435 TEST_F(TransformerTest, MultiChange) { 436 std::string Input = R"cc( 437 void foo() { 438 if (10 > 1.0) 439 log(1) << "oh no!"; 440 else 441 log(0) << "ok"; 442 } 443 )cc"; 444 std::string Expected = R"( 445 void foo() { 446 if (true) { /* then */ } 447 else { /* else */ } 448 } 449 )"; 450 451 StringRef C = "C", T = "T", E = "E"; 452 testRule(makeRule(ifStmt(hasCondition(expr().bind(C)), 453 hasThen(stmt().bind(T)), hasElse(stmt().bind(E))), 454 {change(node(C), text("true")), 455 change(statement(T), text("{ /* then */ }")), 456 change(statement(E), text("{ /* else */ }"))}), 457 Input, Expected); 458 } 459 460 TEST_F(TransformerTest, OrderedRuleUnrelated) { 461 StringRef Flag = "flag"; 462 RewriteRule FlagRule = makeRule( 463 cxxMemberCallExpr(on(expr(hasType(cxxRecordDecl( 464 hasName("proto::ProtoCommandLineFlag")))) 465 .bind(Flag)), 466 unless(callee(cxxMethodDecl(hasName("GetProto"))))), 467 change(node(Flag), text("PROTO"))); 468 469 std::string Input = R"cc( 470 proto::ProtoCommandLineFlag flag; 471 int x = flag.foo(); 472 int y = flag.GetProto().foo(); 473 int f(string s) { return strlen(s.c_str()); } 474 )cc"; 475 std::string Expected = R"cc( 476 proto::ProtoCommandLineFlag flag; 477 int x = PROTO.foo(); 478 int y = flag.GetProto().foo(); 479 int f(string s) { return REPLACED; } 480 )cc"; 481 482 testRule(applyFirst({ruleStrlenSize(), FlagRule}), Input, Expected); 483 } 484 485 // Version of ruleStrlenSizeAny that inserts a method with a different name than 486 // ruleStrlenSize, so we can tell their effect apart. 487 RewriteRule ruleStrlenSizeDistinct() { 488 StringRef S; 489 return makeRule( 490 callExpr(callee(functionDecl(hasName("strlen"))), 491 hasArgument(0, cxxMemberCallExpr( 492 on(expr().bind(S)), 493 callee(cxxMethodDecl(hasName("c_str")))))), 494 change(text("DISTINCT"))); 495 } 496 497 TEST_F(TransformerTest, OrderedRuleRelated) { 498 std::string Input = R"cc( 499 namespace foo { 500 struct mystring { 501 char* c_str(); 502 }; 503 int f(mystring s) { return strlen(s.c_str()); } 504 } // namespace foo 505 int g(string s) { return strlen(s.c_str()); } 506 )cc"; 507 std::string Expected = R"cc( 508 namespace foo { 509 struct mystring { 510 char* c_str(); 511 }; 512 int f(mystring s) { return DISTINCT; } 513 } // namespace foo 514 int g(string s) { return REPLACED; } 515 )cc"; 516 517 testRule(applyFirst({ruleStrlenSize(), ruleStrlenSizeDistinct()}), Input, 518 Expected); 519 } 520 521 // Change the order of the rules to get a different result. 522 TEST_F(TransformerTest, OrderedRuleRelatedSwapped) { 523 std::string Input = R"cc( 524 namespace foo { 525 struct mystring { 526 char* c_str(); 527 }; 528 int f(mystring s) { return strlen(s.c_str()); } 529 } // namespace foo 530 int g(string s) { return strlen(s.c_str()); } 531 )cc"; 532 std::string Expected = R"cc( 533 namespace foo { 534 struct mystring { 535 char* c_str(); 536 }; 537 int f(mystring s) { return DISTINCT; } 538 } // namespace foo 539 int g(string s) { return DISTINCT; } 540 )cc"; 541 542 testRule(applyFirst({ruleStrlenSizeDistinct(), ruleStrlenSize()}), Input, 543 Expected); 544 } 545 546 // 547 // Negative tests (where we expect no transformation to occur). 548 // 549 550 // Tests for a conflict in edits from a single match for a rule. 551 TEST_F(TransformerTest, TextGeneratorFailure) { 552 std::string Input = "int conflictOneRule() { return 3 + 7; }"; 553 // Try to change the whole binary-operator expression AND one its operands: 554 StringRef O = "O"; 555 auto AlwaysFail = [](const ast_matchers::MatchFinder::MatchResult &) 556 -> llvm::Expected<std::string> { 557 return llvm::createStringError(llvm::errc::invalid_argument, "ERROR"); 558 }; 559 Transformer T(makeRule(binaryOperator().bind(O), change(node(O), AlwaysFail)), 560 consumer()); 561 T.registerMatchers(&MatchFinder); 562 EXPECT_FALSE(rewrite(Input)); 563 EXPECT_THAT(Changes, IsEmpty()); 564 EXPECT_EQ(ErrorCount, 1); 565 } 566 567 // Tests for a conflict in edits from a single match for a rule. 568 TEST_F(TransformerTest, OverlappingEditsInRule) { 569 std::string Input = "int conflictOneRule() { return 3 + 7; }"; 570 // Try to change the whole binary-operator expression AND one its operands: 571 StringRef O = "O", L = "L"; 572 Transformer T(makeRule(binaryOperator(hasLHS(expr().bind(L))).bind(O), 573 {change(node(O), text("DELETE_OP")), 574 change(node(L), text("DELETE_LHS"))}), 575 consumer()); 576 T.registerMatchers(&MatchFinder); 577 EXPECT_FALSE(rewrite(Input)); 578 EXPECT_THAT(Changes, IsEmpty()); 579 EXPECT_EQ(ErrorCount, 1); 580 } 581 582 // Tests for a conflict in edits across multiple matches (of the same rule). 583 TEST_F(TransformerTest, OverlappingEditsMultipleMatches) { 584 std::string Input = "int conflictOneRule() { return -7; }"; 585 // Try to change the whole binary-operator expression AND one its operands: 586 StringRef E = "E"; 587 Transformer T(makeRule(expr().bind(E), change(node(E), text("DELETE_EXPR"))), 588 consumer()); 589 T.registerMatchers(&MatchFinder); 590 // The rewrite process fails because the changes conflict with each other... 591 EXPECT_FALSE(rewrite(Input)); 592 // ... but two changes were produced. 593 EXPECT_EQ(Changes.size(), 2u); 594 EXPECT_EQ(ErrorCount, 0); 595 } 596 597 TEST_F(TransformerTest, ErrorOccurredMatchSkipped) { 598 // Syntax error in the function body: 599 std::string Input = "void errorOccurred() { 3 }"; 600 Transformer T(makeRule(functionDecl(hasName("errorOccurred")), 601 change(text("DELETED;"))), 602 consumer()); 603 T.registerMatchers(&MatchFinder); 604 // The rewrite process itself fails... 605 EXPECT_FALSE(rewrite(Input)); 606 // ... and no changes or errors are produced in the process. 607 EXPECT_THAT(Changes, IsEmpty()); 608 EXPECT_EQ(ErrorCount, 0); 609 } 610 611 // Transformation of macro source text when the change encompasses the entirety 612 // of the expanded text. 613 TEST_F(TransformerTest, SimpleMacro) { 614 std::string Input = R"cc( 615 #define ZERO 0 616 int f(string s) { return ZERO; } 617 )cc"; 618 std::string Expected = R"cc( 619 #define ZERO 0 620 int f(string s) { return 999; } 621 )cc"; 622 623 StringRef zero = "zero"; 624 RewriteRule R = makeRule(integerLiteral(equals(0)).bind(zero), 625 change(node(zero), text("999"))); 626 testRule(R, Input, Expected); 627 } 628 629 // Transformation of macro source text when the change encompasses the entirety 630 // of the expanded text, for the case of function-style macros. 631 TEST_F(TransformerTest, FunctionMacro) { 632 std::string Input = R"cc( 633 #define MACRO(str) strlen((str).c_str()) 634 int f(string s) { return MACRO(s); } 635 )cc"; 636 std::string Expected = R"cc( 637 #define MACRO(str) strlen((str).c_str()) 638 int f(string s) { return REPLACED; } 639 )cc"; 640 641 testRule(ruleStrlenSize(), Input, Expected); 642 } 643 644 // Tests that expressions in macro arguments can be rewritten. 645 TEST_F(TransformerTest, MacroArg) { 646 std::string Input = R"cc( 647 #define PLUS(e) e + 1 648 int f(string s) { return PLUS(strlen(s.c_str())); } 649 )cc"; 650 std::string Expected = R"cc( 651 #define PLUS(e) e + 1 652 int f(string s) { return PLUS(REPLACED); } 653 )cc"; 654 655 testRule(ruleStrlenSize(), Input, Expected); 656 } 657 658 // Tests that expressions in macro arguments can be rewritten, even when the 659 // macro call occurs inside another macro's definition. 660 TEST_F(TransformerTest, MacroArgInMacroDef) { 661 std::string Input = R"cc( 662 #define NESTED(e) e 663 #define MACRO(str) NESTED(strlen((str).c_str())) 664 int f(string s) { return MACRO(s); } 665 )cc"; 666 std::string Expected = R"cc( 667 #define NESTED(e) e 668 #define MACRO(str) NESTED(strlen((str).c_str())) 669 int f(string s) { return REPLACED; } 670 )cc"; 671 672 testRule(ruleStrlenSize(), Input, Expected); 673 } 674 675 // Tests the corner case of the identity macro, specifically that it is 676 // discarded in the rewrite rather than preserved (like PLUS is preserved in the 677 // previous test). This behavior is of dubious value (and marked with a FIXME 678 // in the code), but we test it to verify (and demonstrate) how this case is 679 // handled. 680 TEST_F(TransformerTest, IdentityMacro) { 681 std::string Input = R"cc( 682 #define ID(e) e 683 int f(string s) { return ID(strlen(s.c_str())); } 684 )cc"; 685 std::string Expected = R"cc( 686 #define ID(e) e 687 int f(string s) { return REPLACED; } 688 )cc"; 689 690 testRule(ruleStrlenSize(), Input, Expected); 691 } 692 693 // No rewrite is applied when the changed text does not encompass the entirety 694 // of the expanded text. That is, the edit would have to be applied to the 695 // macro's definition to succeed and editing the expansion point would not 696 // suffice. 697 TEST_F(TransformerTest, NoPartialRewriteOMacroExpansion) { 698 std::string Input = R"cc( 699 #define ZERO_PLUS 0 + 3 700 int f(string s) { return ZERO_PLUS; })cc"; 701 702 StringRef zero = "zero"; 703 RewriteRule R = makeRule(integerLiteral(equals(0)).bind(zero), 704 change(node(zero), text("0"))); 705 testRule(R, Input, Input); 706 } 707 708 // This test handles the corner case where a macro expands within another macro 709 // to matching code, but that code is an argument to the nested macro call. A 710 // simple check of isMacroArgExpansion() vs. isMacroBodyExpansion() will get 711 // this wrong, and transform the code. 712 TEST_F(TransformerTest, NoPartialRewriteOfMacroExpansionForMacroArgs) { 713 std::string Input = R"cc( 714 #define NESTED(e) e 715 #define MACRO(str) 1 + NESTED(strlen((str).c_str())) 716 int f(string s) { return MACRO(s); } 717 )cc"; 718 719 testRule(ruleStrlenSize(), Input, Input); 720 } 721 } // namespace 722