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 TEST_F(TransformerTest, OrderedRuleRelated) {
486   std::string Input = R"cc(
487     void f1();
488     void f2();
489     void call_f1() { f1(); }
490     void call_f2() { f2(); }
491   )cc";
492   std::string Expected = R"cc(
493     void f1();
494     void f2();
495     void call_f1() { REPLACE_F1; }
496     void call_f2() { REPLACE_F1_OR_F2; }
497   )cc";
498 
499   RewriteRule ReplaceF1 =
500       makeRule(callExpr(callee(functionDecl(hasName("f1")))),
501                change(text("REPLACE_F1")));
502   RewriteRule ReplaceF1OrF2 =
503       makeRule(callExpr(callee(functionDecl(hasAnyName("f1", "f2")))),
504                change(text("REPLACE_F1_OR_F2")));
505   testRule(applyFirst({ReplaceF1, ReplaceF1OrF2}), Input, Expected);
506 }
507 
508 // Change the order of the rules to get a different result. When `ReplaceF1OrF2`
509 // comes first, it applies for both uses, so `ReplaceF1` never applies.
510 TEST_F(TransformerTest, OrderedRuleRelatedSwapped) {
511   std::string Input = R"cc(
512     void f1();
513     void f2();
514     void call_f1() { f1(); }
515     void call_f2() { f2(); }
516   )cc";
517   std::string Expected = R"cc(
518     void f1();
519     void f2();
520     void call_f1() { REPLACE_F1_OR_F2; }
521     void call_f2() { REPLACE_F1_OR_F2; }
522   )cc";
523 
524   RewriteRule ReplaceF1 =
525       makeRule(callExpr(callee(functionDecl(hasName("f1")))),
526                change(text("REPLACE_F1")));
527   RewriteRule ReplaceF1OrF2 =
528       makeRule(callExpr(callee(functionDecl(hasAnyName("f1", "f2")))),
529                change(text("REPLACE_F1_OR_F2")));
530   testRule(applyFirst({ReplaceF1OrF2, ReplaceF1}), Input, Expected);
531 }
532 
533 // Verify that a set of rules whose matchers have different base kinds works
534 // properly, including that `applyFirst` produces multiple matchers.  We test
535 // two different kinds of rules: Expr and Decl. We place the Decl rule in the
536 // middle to test that `buildMatchers` works even when the kinds aren't grouped
537 // together.
538 TEST_F(TransformerTest, OrderedRuleMultipleKinds) {
539   std::string Input = R"cc(
540     void f1();
541     void f2();
542     void call_f1() { f1(); }
543     void call_f2() { f2(); }
544   )cc";
545   std::string Expected = R"cc(
546     void f1();
547     void DECL_RULE();
548     void call_f1() { REPLACE_F1; }
549     void call_f2() { REPLACE_F1_OR_F2; }
550   )cc";
551 
552   RewriteRule ReplaceF1 =
553       makeRule(callExpr(callee(functionDecl(hasName("f1")))),
554                change(text("REPLACE_F1")));
555   RewriteRule ReplaceF1OrF2 =
556       makeRule(callExpr(callee(functionDecl(hasAnyName("f1", "f2")))),
557                change(text("REPLACE_F1_OR_F2")));
558   RewriteRule DeclRule = makeRule(functionDecl(hasName("f2")).bind("fun"),
559                                   change(name("fun"), text("DECL_RULE")));
560 
561   RewriteRule Rule = applyFirst({ReplaceF1, DeclRule, ReplaceF1OrF2});
562   EXPECT_EQ(tooling::detail::buildMatchers(Rule).size(), 2UL);
563   testRule(Rule, Input, Expected);
564 }
565 
566 //
567 // Negative tests (where we expect no transformation to occur).
568 //
569 
570 // Tests for a conflict in edits from a single match for a rule.
571 TEST_F(TransformerTest, TextGeneratorFailure) {
572   std::string Input = "int conflictOneRule() { return 3 + 7; }";
573   // Try to change the whole binary-operator expression AND one its operands:
574   StringRef O = "O";
575   auto AlwaysFail = [](const ast_matchers::MatchFinder::MatchResult &)
576       -> llvm::Expected<std::string> {
577     return llvm::createStringError(llvm::errc::invalid_argument, "ERROR");
578   };
579   Transformer T(makeRule(binaryOperator().bind(O), change(node(O), AlwaysFail)),
580                 consumer());
581   T.registerMatchers(&MatchFinder);
582   EXPECT_FALSE(rewrite(Input));
583   EXPECT_THAT(Changes, IsEmpty());
584   EXPECT_EQ(ErrorCount, 1);
585 }
586 
587 // Tests for a conflict in edits from a single match for a rule.
588 TEST_F(TransformerTest, OverlappingEditsInRule) {
589   std::string Input = "int conflictOneRule() { return 3 + 7; }";
590   // Try to change the whole binary-operator expression AND one its operands:
591   StringRef O = "O", L = "L";
592   Transformer T(makeRule(binaryOperator(hasLHS(expr().bind(L))).bind(O),
593                          {change(node(O), text("DELETE_OP")),
594                           change(node(L), text("DELETE_LHS"))}),
595                 consumer());
596   T.registerMatchers(&MatchFinder);
597   EXPECT_FALSE(rewrite(Input));
598   EXPECT_THAT(Changes, IsEmpty());
599   EXPECT_EQ(ErrorCount, 1);
600 }
601 
602 // Tests for a conflict in edits across multiple matches (of the same rule).
603 TEST_F(TransformerTest, OverlappingEditsMultipleMatches) {
604   std::string Input = "int conflictOneRule() { return -7; }";
605   // Try to change the whole binary-operator expression AND one its operands:
606   StringRef E = "E";
607   Transformer T(makeRule(expr().bind(E), change(node(E), text("DELETE_EXPR"))),
608                 consumer());
609   T.registerMatchers(&MatchFinder);
610   // The rewrite process fails because the changes conflict with each other...
611   EXPECT_FALSE(rewrite(Input));
612   // ... but two changes were produced.
613   EXPECT_EQ(Changes.size(), 2u);
614   EXPECT_EQ(ErrorCount, 0);
615 }
616 
617 TEST_F(TransformerTest, ErrorOccurredMatchSkipped) {
618   // Syntax error in the function body:
619   std::string Input = "void errorOccurred() { 3 }";
620   Transformer T(makeRule(functionDecl(hasName("errorOccurred")),
621                          change(text("DELETED;"))),
622                 consumer());
623   T.registerMatchers(&MatchFinder);
624   // The rewrite process itself fails...
625   EXPECT_FALSE(rewrite(Input));
626   // ... and no changes or errors are produced in the process.
627   EXPECT_THAT(Changes, IsEmpty());
628   EXPECT_EQ(ErrorCount, 0);
629 }
630 
631 // Transformation of macro source text when the change encompasses the entirety
632 // of the expanded text.
633 TEST_F(TransformerTest, SimpleMacro) {
634   std::string Input = R"cc(
635 #define ZERO 0
636     int f(string s) { return ZERO; }
637   )cc";
638   std::string Expected = R"cc(
639 #define ZERO 0
640     int f(string s) { return 999; }
641   )cc";
642 
643   StringRef zero = "zero";
644   RewriteRule R = makeRule(integerLiteral(equals(0)).bind(zero),
645                            change(node(zero), text("999")));
646   testRule(R, Input, Expected);
647 }
648 
649 // Transformation of macro source text when the change encompasses the entirety
650 // of the expanded text, for the case of function-style macros.
651 TEST_F(TransformerTest, FunctionMacro) {
652   std::string Input = R"cc(
653 #define MACRO(str) strlen((str).c_str())
654     int f(string s) { return MACRO(s); }
655   )cc";
656   std::string Expected = R"cc(
657 #define MACRO(str) strlen((str).c_str())
658     int f(string s) { return REPLACED; }
659   )cc";
660 
661   testRule(ruleStrlenSize(), Input, Expected);
662 }
663 
664 // Tests that expressions in macro arguments can be rewritten.
665 TEST_F(TransformerTest, MacroArg) {
666   std::string Input = R"cc(
667 #define PLUS(e) e + 1
668     int f(string s) { return PLUS(strlen(s.c_str())); }
669   )cc";
670   std::string Expected = R"cc(
671 #define PLUS(e) e + 1
672     int f(string s) { return PLUS(REPLACED); }
673   )cc";
674 
675   testRule(ruleStrlenSize(), Input, Expected);
676 }
677 
678 // Tests that expressions in macro arguments can be rewritten, even when the
679 // macro call occurs inside another macro's definition.
680 TEST_F(TransformerTest, MacroArgInMacroDef) {
681   std::string Input = R"cc(
682 #define NESTED(e) e
683 #define MACRO(str) NESTED(strlen((str).c_str()))
684     int f(string s) { return MACRO(s); }
685   )cc";
686   std::string Expected = R"cc(
687 #define NESTED(e) e
688 #define MACRO(str) NESTED(strlen((str).c_str()))
689     int f(string s) { return REPLACED; }
690   )cc";
691 
692   testRule(ruleStrlenSize(), Input, Expected);
693 }
694 
695 // Tests the corner case of the identity macro, specifically that it is
696 // discarded in the rewrite rather than preserved (like PLUS is preserved in the
697 // previous test).  This behavior is of dubious value (and marked with a FIXME
698 // in the code), but we test it to verify (and demonstrate) how this case is
699 // handled.
700 TEST_F(TransformerTest, IdentityMacro) {
701   std::string Input = R"cc(
702 #define ID(e) e
703     int f(string s) { return ID(strlen(s.c_str())); }
704   )cc";
705   std::string Expected = R"cc(
706 #define ID(e) e
707     int f(string s) { return REPLACED; }
708   )cc";
709 
710   testRule(ruleStrlenSize(), Input, Expected);
711 }
712 
713 // No rewrite is applied when the changed text does not encompass the entirety
714 // of the expanded text. That is, the edit would have to be applied to the
715 // macro's definition to succeed and editing the expansion point would not
716 // suffice.
717 TEST_F(TransformerTest, NoPartialRewriteOMacroExpansion) {
718   std::string Input = R"cc(
719 #define ZERO_PLUS 0 + 3
720     int f(string s) { return ZERO_PLUS; })cc";
721 
722   StringRef zero = "zero";
723   RewriteRule R = makeRule(integerLiteral(equals(0)).bind(zero),
724                            change(node(zero), text("0")));
725   testRule(R, Input, Input);
726 }
727 
728 // This test handles the corner case where a macro expands within another macro
729 // to matching code, but that code is an argument to the nested macro call.  A
730 // simple check of isMacroArgExpansion() vs. isMacroBodyExpansion() will get
731 // this wrong, and transform the code.
732 TEST_F(TransformerTest, NoPartialRewriteOfMacroExpansionForMacroArgs) {
733   std::string Input = R"cc(
734 #define NESTED(e) e
735 #define MACRO(str) 1 + NESTED(strlen((str).c_str()))
736     int f(string s) { return MACRO(s); }
737   )cc";
738 
739   testRule(ruleStrlenSize(), Input, Input);
740 }
741 
742 #if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST
743 // Verifies that `Type` and `QualType` are not allowed as top-level matchers in
744 // rules.
745 TEST(TransformerDeathTest, OrderedRuleTypes) {
746   RewriteRule QualTypeRule = makeRule(qualType(), change(text("Q")));
747   EXPECT_DEATH(tooling::detail::buildMatchers(QualTypeRule),
748                "Matcher must be.*node matcher");
749 
750   RewriteRule TypeRule = makeRule(arrayType(), change(text("T")));
751   EXPECT_DEATH(tooling::detail::buildMatchers(TypeRule),
752                "Matcher must be.*node matcher");
753 }
754 #endif
755 } // namespace
756