TransformerTest.cpp 24 KB

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