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