xref: /llvm-project/clang/unittests/Tooling/TransformerTest.cpp (revision 5523fefb01c282c4cbcaf6314a9aaf658c6c145f)
1fdd98782SYitzhak Mandelbaum //===- unittest/Tooling/TransformerTest.cpp -------------------------------===//
2fdd98782SYitzhak Mandelbaum //
3fdd98782SYitzhak Mandelbaum // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4fdd98782SYitzhak Mandelbaum // See https://llvm.org/LICENSE.txt for license information.
5fdd98782SYitzhak Mandelbaum // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6fdd98782SYitzhak Mandelbaum //
7fdd98782SYitzhak Mandelbaum //===----------------------------------------------------------------------===//
8fdd98782SYitzhak Mandelbaum 
9fbdf8352SYitzhak Mandelbaum #include "clang/Tooling/Transformer/Transformer.h"
10fdd98782SYitzhak Mandelbaum #include "clang/ASTMatchers/ASTMatchers.h"
11fdd98782SYitzhak Mandelbaum #include "clang/Tooling/Tooling.h"
126c683aa8SYitzhak Mandelbaum #include "clang/Tooling/Transformer/RangeSelector.h"
13cf428778SYitzhak Mandelbaum #include "clang/Tooling/Transformer/RewriteRule.h"
146c683aa8SYitzhak Mandelbaum #include "clang/Tooling/Transformer/Stencil.h"
15aba43035SDmitri Gribenko #include "llvm/ADT/STLExtras.h"
16aecc59c5SYitzhak Mandelbaum #include "llvm/Support/Errc.h"
17aecc59c5SYitzhak Mandelbaum #include "llvm/Support/Error.h"
18fdd98782SYitzhak Mandelbaum #include "gmock/gmock.h"
19fdd98782SYitzhak Mandelbaum #include "gtest/gtest.h"
20a1580d7bSKazu Hirata #include <optional>
21fdd98782SYitzhak Mandelbaum 
22fa1552e8SYitzhak Mandelbaum using namespace clang;
23fa1552e8SYitzhak Mandelbaum using namespace tooling;
24fa1552e8SYitzhak Mandelbaum using namespace ast_matchers;
25fdd98782SYitzhak Mandelbaum namespace {
26fdff677aSYitzhak Mandelbaum using ::clang::transformer::addInclude;
27fdff677aSYitzhak Mandelbaum using ::clang::transformer::applyFirst;
28fdff677aSYitzhak Mandelbaum using ::clang::transformer::before;
29fdff677aSYitzhak Mandelbaum using ::clang::transformer::cat;
30fdff677aSYitzhak Mandelbaum using ::clang::transformer::changeTo;
31d1e3235fSEric Li using ::clang::transformer::editList;
32fdff677aSYitzhak Mandelbaum using ::clang::transformer::makeRule;
33fdff677aSYitzhak Mandelbaum using ::clang::transformer::member;
34fdff677aSYitzhak Mandelbaum using ::clang::transformer::name;
35fdff677aSYitzhak Mandelbaum using ::clang::transformer::node;
369edeceaeSEric Li using ::clang::transformer::noEdits;
37fdff677aSYitzhak Mandelbaum using ::clang::transformer::remove;
38fdff677aSYitzhak Mandelbaum using ::clang::transformer::rewriteDescendants;
39fdff677aSYitzhak Mandelbaum using ::clang::transformer::RewriteRule;
409edeceaeSEric Li using ::clang::transformer::RewriteRuleWith;
41fdff677aSYitzhak Mandelbaum using ::clang::transformer::statement;
42d8c1f43dSYitzhak Mandelbaum using ::testing::ElementsAre;
43aecc59c5SYitzhak Mandelbaum using ::testing::IsEmpty;
44d1e3235fSEric Li using ::testing::ResultOf;
45d1e3235fSEric Li using ::testing::UnorderedElementsAre;
46aecc59c5SYitzhak Mandelbaum 
47fdd98782SYitzhak Mandelbaum constexpr char KHeaderContents[] = R"cc(
48fdd98782SYitzhak Mandelbaum   struct string {
49fdd98782SYitzhak Mandelbaum     string(const char*);
50fdd98782SYitzhak Mandelbaum     char* c_str();
51fdd98782SYitzhak Mandelbaum     int size();
52fdd98782SYitzhak Mandelbaum   };
53fdd98782SYitzhak Mandelbaum   int strlen(const char*);
54fdd98782SYitzhak Mandelbaum 
55fdd98782SYitzhak Mandelbaum   namespace proto {
56fdd98782SYitzhak Mandelbaum   struct PCFProto {
57fdd98782SYitzhak Mandelbaum     int foo();
58fdd98782SYitzhak Mandelbaum   };
59fdd98782SYitzhak Mandelbaum   struct ProtoCommandLineFlag : PCFProto {
60fdd98782SYitzhak Mandelbaum     PCFProto& GetProto();
61fdd98782SYitzhak Mandelbaum   };
62fdd98782SYitzhak Mandelbaum   }  // namespace proto
63fa1552e8SYitzhak Mandelbaum   class Logger {};
64fa1552e8SYitzhak Mandelbaum   void operator<<(Logger& l, string msg);
65fa1552e8SYitzhak Mandelbaum   Logger& log(int level);
66fdd98782SYitzhak Mandelbaum )cc";
67fdd98782SYitzhak Mandelbaum 
68fdd98782SYitzhak Mandelbaum static ast_matchers::internal::Matcher<clang::QualType>
isOrPointsTo(const clang::ast_matchers::DeclarationMatcher & TypeMatcher)69fdd98782SYitzhak Mandelbaum isOrPointsTo(const clang::ast_matchers::DeclarationMatcher &TypeMatcher) {
70fdd98782SYitzhak Mandelbaum   return anyOf(hasDeclaration(TypeMatcher), pointsTo(TypeMatcher));
71fdd98782SYitzhak Mandelbaum }
72fdd98782SYitzhak Mandelbaum 
format(StringRef Code)73fdd98782SYitzhak Mandelbaum static std::string format(StringRef Code) {
74fdd98782SYitzhak Mandelbaum   const std::vector<Range> Ranges(1, Range(0, Code.size()));
75fdd98782SYitzhak Mandelbaum   auto Style = format::getLLVMStyle();
76fdd98782SYitzhak Mandelbaum   const auto Replacements = format::reformat(Style, Code, Ranges);
77fdd98782SYitzhak Mandelbaum   auto Formatted = applyAllReplacements(Code, Replacements);
78fdd98782SYitzhak Mandelbaum   if (!Formatted) {
79fdd98782SYitzhak Mandelbaum     ADD_FAILURE() << "Could not format code: "
80fdd98782SYitzhak Mandelbaum                   << llvm::toString(Formatted.takeError());
81fdd98782SYitzhak Mandelbaum     return std::string();
82fdd98782SYitzhak Mandelbaum   }
83fdd98782SYitzhak Mandelbaum   return *Formatted;
84fdd98782SYitzhak Mandelbaum }
85fdd98782SYitzhak Mandelbaum 
compareSnippets(StringRef Expected,const std::optional<std::string> & MaybeActual)86fdd98782SYitzhak Mandelbaum static void compareSnippets(StringRef Expected,
876ad0788cSKazu Hirata                             const std::optional<std::string> &MaybeActual) {
88fdd98782SYitzhak Mandelbaum   ASSERT_TRUE(MaybeActual) << "Rewrite failed. Expecting: " << Expected;
89fdd98782SYitzhak Mandelbaum   auto Actual = *MaybeActual;
90fdd98782SYitzhak Mandelbaum   std::string HL = "#include \"header.h\"\n";
91fdd98782SYitzhak Mandelbaum   auto I = Actual.find(HL);
92fdd98782SYitzhak Mandelbaum   if (I != std::string::npos)
93fdd98782SYitzhak Mandelbaum     Actual.erase(I, HL.size());
94fdd98782SYitzhak Mandelbaum   EXPECT_EQ(format(Expected), format(Actual));
95fdd98782SYitzhak Mandelbaum }
96fdd98782SYitzhak Mandelbaum 
97fdd98782SYitzhak Mandelbaum // FIXME: consider separating this class into its own file(s).
98fdd98782SYitzhak Mandelbaum class ClangRefactoringTestBase : public testing::Test {
99fdd98782SYitzhak Mandelbaum protected:
appendToHeader(StringRef S)100fdd98782SYitzhak Mandelbaum   void appendToHeader(StringRef S) { FileContents[0].second += S; }
101fdd98782SYitzhak Mandelbaum 
addFile(StringRef Filename,StringRef Content)102fdd98782SYitzhak Mandelbaum   void addFile(StringRef Filename, StringRef Content) {
103757bdc64SBenjamin Kramer     FileContents.emplace_back(std::string(Filename), std::string(Content));
104fdd98782SYitzhak Mandelbaum   }
105fdd98782SYitzhak Mandelbaum 
rewrite(StringRef Input)1066ad0788cSKazu Hirata   std::optional<std::string> rewrite(StringRef Input) {
107fdd98782SYitzhak Mandelbaum     std::string Code = ("#include \"header.h\"\n" + Input).str();
108fdd98782SYitzhak Mandelbaum     auto Factory = newFrontendActionFactory(&MatchFinder);
109fdd98782SYitzhak Mandelbaum     if (!runToolOnCodeWithArgs(
110fdd98782SYitzhak Mandelbaum             Factory->create(), Code, std::vector<std::string>(), "input.cc",
111fdd98782SYitzhak Mandelbaum             "clang-tool", std::make_shared<PCHContainerOperations>(),
112fdd98782SYitzhak Mandelbaum             FileContents)) {
113aecc59c5SYitzhak Mandelbaum       llvm::errs() << "Running tool failed.\n";
114a41fbb1fSKazu Hirata       return std::nullopt;
115fdd98782SYitzhak Mandelbaum     }
116aecc59c5SYitzhak Mandelbaum     if (ErrorCount != 0) {
117aecc59c5SYitzhak Mandelbaum       llvm::errs() << "Generating changes failed.\n";
118a41fbb1fSKazu Hirata       return std::nullopt;
119aecc59c5SYitzhak Mandelbaum     }
120aecc59c5SYitzhak Mandelbaum     auto ChangedCode =
121fdd98782SYitzhak Mandelbaum         applyAtomicChanges("input.cc", Code, Changes, ApplyChangesSpec());
122aecc59c5SYitzhak Mandelbaum     if (!ChangedCode) {
123aecc59c5SYitzhak Mandelbaum       llvm::errs() << "Applying changes failed: "
124aecc59c5SYitzhak Mandelbaum                    << llvm::toString(ChangedCode.takeError()) << "\n";
125a41fbb1fSKazu Hirata       return std::nullopt;
126fdd98782SYitzhak Mandelbaum     }
127aecc59c5SYitzhak Mandelbaum     return *ChangedCode;
128aecc59c5SYitzhak Mandelbaum   }
129aecc59c5SYitzhak Mandelbaum 
consumer()130d1e3235fSEric Li   Transformer::ChangeSetConsumer consumer() {
131d1e3235fSEric Li     return [this](Expected<MutableArrayRef<AtomicChange>> C) {
132aecc59c5SYitzhak Mandelbaum       if (C) {
133d1e3235fSEric Li         Changes.insert(Changes.end(), std::make_move_iterator(C->begin()),
134d1e3235fSEric Li                        std::make_move_iterator(C->end()));
135aecc59c5SYitzhak Mandelbaum       } else {
1369edeceaeSEric Li         // FIXME: stash this error rather than printing.
137c332a984SYitzhak Mandelbaum         llvm::errs() << "Error generating changes: "
138c332a984SYitzhak Mandelbaum                      << llvm::toString(C.takeError()) << "\n";
139aecc59c5SYitzhak Mandelbaum         ++ErrorCount;
140aecc59c5SYitzhak Mandelbaum       }
141aecc59c5SYitzhak Mandelbaum     };
142fdd98782SYitzhak Mandelbaum   }
143fdd98782SYitzhak Mandelbaum 
consumerWithStringMetadata()1449edeceaeSEric Li   auto consumerWithStringMetadata() {
1459edeceaeSEric Li     return [this](Expected<TransformerResult<std::string>> C) {
1469edeceaeSEric Li       if (C) {
1479edeceaeSEric Li         Changes.insert(Changes.end(),
1489edeceaeSEric Li                        std::make_move_iterator(C->Changes.begin()),
1499edeceaeSEric Li                        std::make_move_iterator(C->Changes.end()));
1509edeceaeSEric Li         StringMetadata.push_back(std::move(C->Metadata));
1519edeceaeSEric Li       } else {
1529edeceaeSEric Li         // FIXME: stash this error rather than printing.
1539edeceaeSEric Li         llvm::errs() << "Error generating changes: "
1549edeceaeSEric Li                      << llvm::toString(C.takeError()) << "\n";
1559edeceaeSEric Li         ++ErrorCount;
1569edeceaeSEric Li       }
1579edeceaeSEric Li     };
1589edeceaeSEric Li   }
1599edeceaeSEric Li 
testRule(RewriteRule Rule,StringRef Input,StringRef Expected)1609edeceaeSEric Li   void testRule(RewriteRule Rule, StringRef Input, StringRef Expected) {
16196ed6793SFangrui Song     Transformers.push_back(
16296ed6793SFangrui Song         std::make_unique<Transformer>(std::move(Rule), consumer()));
16396ed6793SFangrui Song     Transformers.back()->registerMatchers(&MatchFinder);
164fdd98782SYitzhak Mandelbaum     compareSnippets(Expected, rewrite(Input));
165fdd98782SYitzhak Mandelbaum   }
166fdd98782SYitzhak Mandelbaum 
testRule(RewriteRuleWith<std::string> Rule,StringRef Input,StringRef Expected)1679edeceaeSEric Li   void testRule(RewriteRuleWith<std::string> Rule, StringRef Input,
1689edeceaeSEric Li                 StringRef Expected) {
1699edeceaeSEric Li     Transformers.push_back(std::make_unique<Transformer>(
1709edeceaeSEric Li         std::move(Rule), consumerWithStringMetadata()));
1719edeceaeSEric Li     Transformers.back()->registerMatchers(&MatchFinder);
1729edeceaeSEric Li     compareSnippets(Expected, rewrite(Input));
1739edeceaeSEric Li   }
1749edeceaeSEric Li 
testRuleFailure(RewriteRule Rule,StringRef Input)1759edeceaeSEric Li   void testRuleFailure(RewriteRule Rule, StringRef Input) {
176246b428fSStephen Kelly     Transformers.push_back(
177246b428fSStephen Kelly         std::make_unique<Transformer>(std::move(Rule), consumer()));
178246b428fSStephen Kelly     Transformers.back()->registerMatchers(&MatchFinder);
179246b428fSStephen Kelly     ASSERT_FALSE(rewrite(Input)) << "Expected failure to rewrite code";
180246b428fSStephen Kelly   }
181246b428fSStephen Kelly 
testRuleFailure(RewriteRuleWith<std::string> Rule,StringRef Input)1829edeceaeSEric Li   void testRuleFailure(RewriteRuleWith<std::string> Rule, StringRef Input) {
1839edeceaeSEric Li     Transformers.push_back(std::make_unique<Transformer>(
1849edeceaeSEric Li         std::move(Rule), consumerWithStringMetadata()));
1859edeceaeSEric Li     Transformers.back()->registerMatchers(&MatchFinder);
1869edeceaeSEric Li     ASSERT_FALSE(rewrite(Input)) << "Expected failure to rewrite code";
1879edeceaeSEric Li   }
1889edeceaeSEric Li 
18996ed6793SFangrui Song   // Transformers are referenced by MatchFinder.
19096ed6793SFangrui Song   std::vector<std::unique_ptr<Transformer>> Transformers;
191fdd98782SYitzhak Mandelbaum   clang::ast_matchers::MatchFinder MatchFinder;
192aecc59c5SYitzhak Mandelbaum   // Records whether any errors occurred in individual changes.
193aecc59c5SYitzhak Mandelbaum   int ErrorCount = 0;
194fdd98782SYitzhak Mandelbaum   AtomicChanges Changes;
1959edeceaeSEric Li   std::vector<std::string> StringMetadata;
196fdd98782SYitzhak Mandelbaum 
197fdd98782SYitzhak Mandelbaum private:
198fdd98782SYitzhak Mandelbaum   FileContentMappings FileContents = {{"header.h", ""}};
199fdd98782SYitzhak Mandelbaum };
200fdd98782SYitzhak Mandelbaum 
201fdd98782SYitzhak Mandelbaum class TransformerTest : public ClangRefactoringTestBase {
202fdd98782SYitzhak Mandelbaum protected:
TransformerTest()203fdd98782SYitzhak Mandelbaum   TransformerTest() { appendToHeader(KHeaderContents); }
204fdd98782SYitzhak Mandelbaum };
205fdd98782SYitzhak Mandelbaum 
2063f1ab737SYitzhak Mandelbaum // Given string s, change strlen($s.c_str()) to REPLACED.
ruleStrlenSize()2079edeceaeSEric Li static RewriteRuleWith<std::string> ruleStrlenSize() {
208fdd98782SYitzhak Mandelbaum   StringRef StringExpr = "strexpr";
209fdd98782SYitzhak Mandelbaum   auto StringType = namedDecl(hasAnyName("::basic_string", "::string"));
210fa1552e8SYitzhak Mandelbaum   auto R = makeRule(
211fa1552e8SYitzhak Mandelbaum       callExpr(callee(functionDecl(hasName("strlen"))),
212fdd98782SYitzhak Mandelbaum                hasArgument(0, cxxMemberCallExpr(
213fdd98782SYitzhak Mandelbaum                                   on(expr(hasType(isOrPointsTo(StringType)))
214fdd98782SYitzhak Mandelbaum                                          .bind(StringExpr)),
215fa1552e8SYitzhak Mandelbaum                                   callee(cxxMethodDecl(hasName("c_str")))))),
2169f97480cSYitzhak Mandelbaum       changeTo(cat("REPLACED")), cat("Use size() method directly on string."));
217fa1552e8SYitzhak Mandelbaum   return R;
218fdd98782SYitzhak Mandelbaum }
219fdd98782SYitzhak Mandelbaum 
TEST_F(TransformerTest,StrlenSize)220fdd98782SYitzhak Mandelbaum TEST_F(TransformerTest, StrlenSize) {
221fdd98782SYitzhak Mandelbaum   std::string Input = "int f(string s) { return strlen(s.c_str()); }";
222fdd98782SYitzhak Mandelbaum   std::string Expected = "int f(string s) { return REPLACED; }";
223fdd98782SYitzhak Mandelbaum   testRule(ruleStrlenSize(), Input, Expected);
224fdd98782SYitzhak Mandelbaum }
225fdd98782SYitzhak Mandelbaum 
226fdd98782SYitzhak Mandelbaum // Tests that no change is applied when a match is not expected.
TEST_F(TransformerTest,NoMatch)227fdd98782SYitzhak Mandelbaum TEST_F(TransformerTest, NoMatch) {
228fdd98782SYitzhak Mandelbaum   std::string Input = "int f(string s) { return s.size(); }";
229fdd98782SYitzhak Mandelbaum   testRule(ruleStrlenSize(), Input, Input);
230fdd98782SYitzhak Mandelbaum }
231fdd98782SYitzhak Mandelbaum 
232fdd98782SYitzhak Mandelbaum // Tests replacing an expression.
TEST_F(TransformerTest,Flag)233fdd98782SYitzhak Mandelbaum TEST_F(TransformerTest, Flag) {
234fdd98782SYitzhak Mandelbaum   StringRef Flag = "flag";
235fa1552e8SYitzhak Mandelbaum   RewriteRule Rule = makeRule(
236fa1552e8SYitzhak Mandelbaum       cxxMemberCallExpr(on(expr(hasType(cxxRecordDecl(
237fa1552e8SYitzhak Mandelbaum                                     hasName("proto::ProtoCommandLineFlag"))))
238fdd98782SYitzhak Mandelbaum                                .bind(Flag)),
239fa1552e8SYitzhak Mandelbaum                         unless(callee(cxxMethodDecl(hasName("GetProto"))))),
240adcd0268SBenjamin Kramer       changeTo(node(std::string(Flag)), cat("EXPR")));
241fdd98782SYitzhak Mandelbaum 
242fdd98782SYitzhak Mandelbaum   std::string Input = R"cc(
243fdd98782SYitzhak Mandelbaum     proto::ProtoCommandLineFlag flag;
244fdd98782SYitzhak Mandelbaum     int x = flag.foo();
245fdd98782SYitzhak Mandelbaum     int y = flag.GetProto().foo();
246fdd98782SYitzhak Mandelbaum   )cc";
247fdd98782SYitzhak Mandelbaum   std::string Expected = R"cc(
248fdd98782SYitzhak Mandelbaum     proto::ProtoCommandLineFlag flag;
249fdd98782SYitzhak Mandelbaum     int x = EXPR.foo();
250fdd98782SYitzhak Mandelbaum     int y = flag.GetProto().foo();
251fdd98782SYitzhak Mandelbaum   )cc";
252fdd98782SYitzhak Mandelbaum 
253fdd98782SYitzhak Mandelbaum   testRule(std::move(Rule), Input, Expected);
254fdd98782SYitzhak Mandelbaum }
255fdd98782SYitzhak Mandelbaum 
TEST_F(TransformerTest,AddIncludeQuoted)256727bdcb2SYitzhak Mandelbaum TEST_F(TransformerTest, AddIncludeQuoted) {
257d8c1f43dSYitzhak Mandelbaum   RewriteRule Rule =
258d8c1f43dSYitzhak Mandelbaum       makeRule(callExpr(callee(functionDecl(hasName("f")))),
259d8c1f43dSYitzhak Mandelbaum                {addInclude("clang/OtherLib.h"), changeTo(cat("other()"))});
260d8c1f43dSYitzhak Mandelbaum 
261d8c1f43dSYitzhak Mandelbaum   std::string Input = R"cc(
262d8c1f43dSYitzhak Mandelbaum     int f(int x);
263d8c1f43dSYitzhak Mandelbaum     int h(int x) { return f(x); }
264d8c1f43dSYitzhak Mandelbaum   )cc";
265d8c1f43dSYitzhak Mandelbaum   std::string Expected = R"cc(#include "clang/OtherLib.h"
266d8c1f43dSYitzhak Mandelbaum 
267d8c1f43dSYitzhak Mandelbaum     int f(int x);
268d8c1f43dSYitzhak Mandelbaum     int h(int x) { return other(); }
269d8c1f43dSYitzhak Mandelbaum   )cc";
270d8c1f43dSYitzhak Mandelbaum 
271d8c1f43dSYitzhak Mandelbaum   testRule(Rule, Input, Expected);
272d8c1f43dSYitzhak Mandelbaum }
273d8c1f43dSYitzhak Mandelbaum 
TEST_F(TransformerTest,AddIncludeAngled)274d8c1f43dSYitzhak Mandelbaum TEST_F(TransformerTest, AddIncludeAngled) {
275d8c1f43dSYitzhak Mandelbaum   RewriteRule Rule = makeRule(
276d8c1f43dSYitzhak Mandelbaum       callExpr(callee(functionDecl(hasName("f")))),
277d8c1f43dSYitzhak Mandelbaum       {addInclude("clang/OtherLib.h", transformer::IncludeFormat::Angled),
278d8c1f43dSYitzhak Mandelbaum        changeTo(cat("other()"))});
279d8c1f43dSYitzhak Mandelbaum 
280d8c1f43dSYitzhak Mandelbaum   std::string Input = R"cc(
281d8c1f43dSYitzhak Mandelbaum     int f(int x);
282d8c1f43dSYitzhak Mandelbaum     int h(int x) { return f(x); }
283d8c1f43dSYitzhak Mandelbaum   )cc";
284d8c1f43dSYitzhak Mandelbaum   std::string Expected = R"cc(#include <clang/OtherLib.h>
285d8c1f43dSYitzhak Mandelbaum 
286d8c1f43dSYitzhak Mandelbaum     int f(int x);
287d8c1f43dSYitzhak Mandelbaum     int h(int x) { return other(); }
288d8c1f43dSYitzhak Mandelbaum   )cc";
289d8c1f43dSYitzhak Mandelbaum 
290d8c1f43dSYitzhak Mandelbaum   testRule(Rule, Input, Expected);
291d8c1f43dSYitzhak Mandelbaum }
292d8c1f43dSYitzhak Mandelbaum 
TEST_F(TransformerTest,AddIncludeQuotedForRule)293d8c1f43dSYitzhak Mandelbaum TEST_F(TransformerTest, AddIncludeQuotedForRule) {
294727bdcb2SYitzhak Mandelbaum   RewriteRule Rule = makeRule(callExpr(callee(functionDecl(hasName("f")))),
2959f97480cSYitzhak Mandelbaum                               changeTo(cat("other()")));
296727bdcb2SYitzhak Mandelbaum   addInclude(Rule, "clang/OtherLib.h");
297727bdcb2SYitzhak Mandelbaum 
298727bdcb2SYitzhak Mandelbaum   std::string Input = R"cc(
299727bdcb2SYitzhak Mandelbaum     int f(int x);
300727bdcb2SYitzhak Mandelbaum     int h(int x) { return f(x); }
301727bdcb2SYitzhak Mandelbaum   )cc";
302727bdcb2SYitzhak Mandelbaum   std::string Expected = R"cc(#include "clang/OtherLib.h"
303727bdcb2SYitzhak Mandelbaum 
304727bdcb2SYitzhak Mandelbaum     int f(int x);
305727bdcb2SYitzhak Mandelbaum     int h(int x) { return other(); }
306727bdcb2SYitzhak Mandelbaum   )cc";
307727bdcb2SYitzhak Mandelbaum 
308727bdcb2SYitzhak Mandelbaum   testRule(Rule, Input, Expected);
309727bdcb2SYitzhak Mandelbaum }
310727bdcb2SYitzhak Mandelbaum 
TEST_F(TransformerTest,AddIncludeAngledForRule)311d8c1f43dSYitzhak Mandelbaum TEST_F(TransformerTest, AddIncludeAngledForRule) {
312727bdcb2SYitzhak Mandelbaum   RewriteRule Rule = makeRule(callExpr(callee(functionDecl(hasName("f")))),
3139f97480cSYitzhak Mandelbaum                               changeTo(cat("other()")));
3148bb47cd8SYitzhak Mandelbaum   addInclude(Rule, "clang/OtherLib.h", transformer::IncludeFormat::Angled);
315727bdcb2SYitzhak Mandelbaum 
316727bdcb2SYitzhak Mandelbaum   std::string Input = R"cc(
317727bdcb2SYitzhak Mandelbaum     int f(int x);
318727bdcb2SYitzhak Mandelbaum     int h(int x) { return f(x); }
319727bdcb2SYitzhak Mandelbaum   )cc";
320727bdcb2SYitzhak Mandelbaum   std::string Expected = R"cc(#include <clang/OtherLib.h>
321727bdcb2SYitzhak Mandelbaum 
322727bdcb2SYitzhak Mandelbaum     int f(int x);
323727bdcb2SYitzhak Mandelbaum     int h(int x) { return other(); }
324727bdcb2SYitzhak Mandelbaum   )cc";
325727bdcb2SYitzhak Mandelbaum 
326727bdcb2SYitzhak Mandelbaum   testRule(Rule, Input, Expected);
327727bdcb2SYitzhak Mandelbaum }
328727bdcb2SYitzhak Mandelbaum 
TEST_F(TransformerTest,NodePartNameNamedDecl)329fdd98782SYitzhak Mandelbaum TEST_F(TransformerTest, NodePartNameNamedDecl) {
330fdd98782SYitzhak Mandelbaum   StringRef Fun = "fun";
3313ec50e29SYitzhak Mandelbaum   RewriteRule Rule = makeRule(functionDecl(hasName("bad")).bind(Fun),
332adcd0268SBenjamin Kramer                               changeTo(name(std::string(Fun)), cat("good")));
333fdd98782SYitzhak Mandelbaum 
334fdd98782SYitzhak Mandelbaum   std::string Input = R"cc(
335fdd98782SYitzhak Mandelbaum     int bad(int x);
336fdd98782SYitzhak Mandelbaum     int bad(int x) { return x * x; }
337fdd98782SYitzhak Mandelbaum   )cc";
338fdd98782SYitzhak Mandelbaum   std::string Expected = R"cc(
339fdd98782SYitzhak Mandelbaum     int good(int x);
340fdd98782SYitzhak Mandelbaum     int good(int x) { return x * x; }
341fdd98782SYitzhak Mandelbaum   )cc";
342fdd98782SYitzhak Mandelbaum 
343fdd98782SYitzhak Mandelbaum   testRule(Rule, Input, Expected);
344fdd98782SYitzhak Mandelbaum }
345fdd98782SYitzhak Mandelbaum 
TEST_F(TransformerTest,NodePartNameDeclRef)346fdd98782SYitzhak Mandelbaum TEST_F(TransformerTest, NodePartNameDeclRef) {
347fdd98782SYitzhak Mandelbaum   std::string Input = R"cc(
348fdd98782SYitzhak Mandelbaum     template <typename T>
349fdd98782SYitzhak Mandelbaum     T bad(T x) {
350fdd98782SYitzhak Mandelbaum       return x;
351fdd98782SYitzhak Mandelbaum     }
352fdd98782SYitzhak Mandelbaum     int neutral(int x) { return bad<int>(x) * x; }
353fdd98782SYitzhak Mandelbaum   )cc";
354fdd98782SYitzhak Mandelbaum   std::string Expected = R"cc(
355fdd98782SYitzhak Mandelbaum     template <typename T>
356fdd98782SYitzhak Mandelbaum     T bad(T x) {
357fdd98782SYitzhak Mandelbaum       return x;
358fdd98782SYitzhak Mandelbaum     }
359fdd98782SYitzhak Mandelbaum     int neutral(int x) { return good<int>(x) * x; }
360fdd98782SYitzhak Mandelbaum   )cc";
361fdd98782SYitzhak Mandelbaum 
362fdd98782SYitzhak Mandelbaum   StringRef Ref = "ref";
363fa1552e8SYitzhak Mandelbaum   testRule(makeRule(declRefExpr(to(functionDecl(hasName("bad")))).bind(Ref),
364adcd0268SBenjamin Kramer                     changeTo(name(std::string(Ref)), cat("good"))),
365fdd98782SYitzhak Mandelbaum            Input, Expected);
366fdd98782SYitzhak Mandelbaum }
367fdd98782SYitzhak Mandelbaum 
TEST_F(TransformerTest,NodePartNameDeclRefFailure)368fdd98782SYitzhak Mandelbaum TEST_F(TransformerTest, NodePartNameDeclRefFailure) {
369fdd98782SYitzhak Mandelbaum   std::string Input = R"cc(
370fdd98782SYitzhak Mandelbaum     struct Y {
371fdd98782SYitzhak Mandelbaum       int operator*();
372fdd98782SYitzhak Mandelbaum     };
373fdd98782SYitzhak Mandelbaum     int neutral(int x) {
374fdd98782SYitzhak Mandelbaum       Y y;
375fdd98782SYitzhak Mandelbaum       int (Y::*ptr)() = &Y::operator*;
376fdd98782SYitzhak Mandelbaum       return *y + x;
377fdd98782SYitzhak Mandelbaum     }
378fdd98782SYitzhak Mandelbaum   )cc";
379fdd98782SYitzhak Mandelbaum 
380fdd98782SYitzhak Mandelbaum   StringRef Ref = "ref";
381a5dadbe1SYitzhak Mandelbaum   Transformer T(makeRule(declRefExpr(to(functionDecl())).bind(Ref),
382adcd0268SBenjamin Kramer                          changeTo(name(std::string(Ref)), cat("good"))),
383a5dadbe1SYitzhak Mandelbaum                 consumer());
384a5dadbe1SYitzhak Mandelbaum   T.registerMatchers(&MatchFinder);
385a5dadbe1SYitzhak Mandelbaum   EXPECT_FALSE(rewrite(Input));
386fdd98782SYitzhak Mandelbaum }
387fdd98782SYitzhak Mandelbaum 
TEST_F(TransformerTest,NodePartMember)388fdd98782SYitzhak Mandelbaum TEST_F(TransformerTest, NodePartMember) {
389fdd98782SYitzhak Mandelbaum   StringRef E = "expr";
390fdff677aSYitzhak Mandelbaum   RewriteRule Rule =
391fdff677aSYitzhak Mandelbaum       makeRule(memberExpr(clang::ast_matchers::member(hasName("bad"))).bind(E),
392adcd0268SBenjamin Kramer                changeTo(member(std::string(E)), cat("good")));
393fdd98782SYitzhak Mandelbaum 
394fdd98782SYitzhak Mandelbaum   std::string Input = R"cc(
395fdd98782SYitzhak Mandelbaum     struct S {
396fdd98782SYitzhak Mandelbaum       int bad;
397fdd98782SYitzhak Mandelbaum     };
398fdd98782SYitzhak Mandelbaum     int g() {
399fdd98782SYitzhak Mandelbaum       S s;
400fdd98782SYitzhak Mandelbaum       return s.bad;
401fdd98782SYitzhak Mandelbaum     }
402fdd98782SYitzhak Mandelbaum   )cc";
403fdd98782SYitzhak Mandelbaum   std::string Expected = R"cc(
404fdd98782SYitzhak Mandelbaum     struct S {
405fdd98782SYitzhak Mandelbaum       int bad;
406fdd98782SYitzhak Mandelbaum     };
407fdd98782SYitzhak Mandelbaum     int g() {
408fdd98782SYitzhak Mandelbaum       S s;
409fdd98782SYitzhak Mandelbaum       return s.good;
410fdd98782SYitzhak Mandelbaum     }
411fdd98782SYitzhak Mandelbaum   )cc";
412fdd98782SYitzhak Mandelbaum 
413fdd98782SYitzhak Mandelbaum   testRule(Rule, Input, Expected);
414fdd98782SYitzhak Mandelbaum }
415fdd98782SYitzhak Mandelbaum 
TEST_F(TransformerTest,NodePartMemberQualified)416fdd98782SYitzhak Mandelbaum TEST_F(TransformerTest, NodePartMemberQualified) {
417fdd98782SYitzhak Mandelbaum   std::string Input = R"cc(
418fdd98782SYitzhak Mandelbaum     struct S {
419fdd98782SYitzhak Mandelbaum       int bad;
420fdd98782SYitzhak Mandelbaum       int good;
421fdd98782SYitzhak Mandelbaum     };
422fdd98782SYitzhak Mandelbaum     struct T : public S {
423fdd98782SYitzhak Mandelbaum       int bad;
424fdd98782SYitzhak Mandelbaum     };
425fdd98782SYitzhak Mandelbaum     int g() {
426fdd98782SYitzhak Mandelbaum       T t;
427fdd98782SYitzhak Mandelbaum       return t.S::bad;
428fdd98782SYitzhak Mandelbaum     }
429fdd98782SYitzhak Mandelbaum   )cc";
430fdd98782SYitzhak Mandelbaum   std::string Expected = R"cc(
431fdd98782SYitzhak Mandelbaum     struct S {
432fdd98782SYitzhak Mandelbaum       int bad;
433fdd98782SYitzhak Mandelbaum       int good;
434fdd98782SYitzhak Mandelbaum     };
435fdd98782SYitzhak Mandelbaum     struct T : public S {
436fdd98782SYitzhak Mandelbaum       int bad;
437fdd98782SYitzhak Mandelbaum     };
438fdd98782SYitzhak Mandelbaum     int g() {
439fdd98782SYitzhak Mandelbaum       T t;
440fdd98782SYitzhak Mandelbaum       return t.S::good;
441fdd98782SYitzhak Mandelbaum     }
442fdd98782SYitzhak Mandelbaum   )cc";
443fdd98782SYitzhak Mandelbaum 
444fdd98782SYitzhak Mandelbaum   StringRef E = "expr";
445adcd0268SBenjamin Kramer   testRule(makeRule(memberExpr().bind(E),
446adcd0268SBenjamin Kramer                     changeTo(member(std::string(E)), cat("good"))),
447fdd98782SYitzhak Mandelbaum            Input, Expected);
448fdd98782SYitzhak Mandelbaum }
449fdd98782SYitzhak Mandelbaum 
TEST_F(TransformerTest,NodePartMemberMultiToken)450fdd98782SYitzhak Mandelbaum TEST_F(TransformerTest, NodePartMemberMultiToken) {
451fdd98782SYitzhak Mandelbaum   std::string Input = R"cc(
452fdd98782SYitzhak Mandelbaum     struct Y {
453fdd98782SYitzhak Mandelbaum       int operator*();
454fdd98782SYitzhak Mandelbaum       int good();
455fdd98782SYitzhak Mandelbaum       template <typename T> void foo(T t);
456fdd98782SYitzhak Mandelbaum     };
457fdd98782SYitzhak Mandelbaum     int neutral(int x) {
458fdd98782SYitzhak Mandelbaum       Y y;
459fdd98782SYitzhak Mandelbaum       y.template foo<int>(3);
460fdd98782SYitzhak Mandelbaum       return y.operator *();
461fdd98782SYitzhak Mandelbaum     }
462fdd98782SYitzhak Mandelbaum   )cc";
463fdd98782SYitzhak Mandelbaum   std::string Expected = R"cc(
464fdd98782SYitzhak Mandelbaum     struct Y {
465fdd98782SYitzhak Mandelbaum       int operator*();
466fdd98782SYitzhak Mandelbaum       int good();
467fdd98782SYitzhak Mandelbaum       template <typename T> void foo(T t);
468fdd98782SYitzhak Mandelbaum     };
469fdd98782SYitzhak Mandelbaum     int neutral(int x) {
470fdd98782SYitzhak Mandelbaum       Y y;
471fdd98782SYitzhak Mandelbaum       y.template good<int>(3);
472fdd98782SYitzhak Mandelbaum       return y.good();
473fdd98782SYitzhak Mandelbaum     }
474fdd98782SYitzhak Mandelbaum   )cc";
475fdd98782SYitzhak Mandelbaum 
476fdd98782SYitzhak Mandelbaum   StringRef MemExpr = "member";
477fa1552e8SYitzhak Mandelbaum   testRule(makeRule(memberExpr().bind(MemExpr),
478adcd0268SBenjamin Kramer                     changeTo(member(std::string(MemExpr)), cat("good"))),
479fa1552e8SYitzhak Mandelbaum            Input, Expected);
480fa1552e8SYitzhak Mandelbaum }
481fa1552e8SYitzhak Mandelbaum 
TEST_F(TransformerTest,NoEdits)482cf428778SYitzhak Mandelbaum TEST_F(TransformerTest, NoEdits) {
483cf428778SYitzhak Mandelbaum   using transformer::noEdits;
484cf428778SYitzhak Mandelbaum   std::string Input = "int f(int x) { return x; }";
485cf428778SYitzhak Mandelbaum   testRule(makeRule(returnStmt().bind("return"), noEdits()), Input, Input);
486cf428778SYitzhak Mandelbaum }
487cf428778SYitzhak Mandelbaum 
TEST_F(TransformerTest,NoopEdit)4886f8f5cb7SYitzhak Mandelbaum TEST_F(TransformerTest, NoopEdit) {
4896f8f5cb7SYitzhak Mandelbaum   using transformer::node;
4906f8f5cb7SYitzhak Mandelbaum   using transformer::noopEdit;
4916f8f5cb7SYitzhak Mandelbaum   std::string Input = "int f(int x) { return x; }";
4926f8f5cb7SYitzhak Mandelbaum   testRule(makeRule(returnStmt().bind("return"), noopEdit(node("return"))),
4936f8f5cb7SYitzhak Mandelbaum            Input, Input);
4946f8f5cb7SYitzhak Mandelbaum }
4956f8f5cb7SYitzhak Mandelbaum 
TEST_F(TransformerTest,IfBound2Args)496cf428778SYitzhak Mandelbaum TEST_F(TransformerTest, IfBound2Args) {
497cf428778SYitzhak Mandelbaum   using transformer::ifBound;
498cf428778SYitzhak Mandelbaum   std::string Input = "int f(int x) { return x; }";
499cf428778SYitzhak Mandelbaum   std::string Expected = "int f(int x) { CHANGE; }";
500cf428778SYitzhak Mandelbaum   testRule(makeRule(returnStmt().bind("return"),
501cf428778SYitzhak Mandelbaum                     ifBound("return", changeTo(cat("CHANGE;")))),
502cf428778SYitzhak Mandelbaum            Input, Expected);
503cf428778SYitzhak Mandelbaum }
504cf428778SYitzhak Mandelbaum 
TEST_F(TransformerTest,IfBound3Args)505cf428778SYitzhak Mandelbaum TEST_F(TransformerTest, IfBound3Args) {
506cf428778SYitzhak Mandelbaum   using transformer::ifBound;
507cf428778SYitzhak Mandelbaum   std::string Input = "int f(int x) { return x; }";
508cf428778SYitzhak Mandelbaum   std::string Expected = "int f(int x) { CHANGE; }";
509cf428778SYitzhak Mandelbaum   testRule(makeRule(returnStmt().bind("return"),
510cf428778SYitzhak Mandelbaum                     ifBound("nothing", changeTo(cat("ERROR")),
511cf428778SYitzhak Mandelbaum                             changeTo(cat("CHANGE;")))),
512cf428778SYitzhak Mandelbaum            Input, Expected);
513cf428778SYitzhak Mandelbaum }
514cf428778SYitzhak Mandelbaum 
TEST_F(TransformerTest,ShrinkTo)515cf428778SYitzhak Mandelbaum TEST_F(TransformerTest, ShrinkTo) {
516cf428778SYitzhak Mandelbaum   using transformer::shrinkTo;
517cf428778SYitzhak Mandelbaum   std::string Input = "int f(int x) { return x; }";
518cf428778SYitzhak Mandelbaum   std::string Expected = "return x;";
519cf428778SYitzhak Mandelbaum   testRule(makeRule(functionDecl(hasDescendant(returnStmt().bind("return")))
520cf428778SYitzhak Mandelbaum                         .bind("function"),
521cf428778SYitzhak Mandelbaum                     shrinkTo(node("function"), node("return"))),
522cf428778SYitzhak Mandelbaum            Input, Expected);
523cf428778SYitzhak Mandelbaum }
524cf428778SYitzhak Mandelbaum 
525c332a984SYitzhak Mandelbaum // Rewrite various Stmts inside a Decl.
TEST_F(TransformerTest,RewriteDescendantsDeclChangeStmt)526c332a984SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsDeclChangeStmt) {
527c332a984SYitzhak Mandelbaum   std::string Input =
528c332a984SYitzhak Mandelbaum       "int f(int x) { int y = x; { int z = x * x; } return x; }";
529c332a984SYitzhak Mandelbaum   std::string Expected =
530c332a984SYitzhak Mandelbaum       "int f(int x) { int y = 3; { int z = 3 * 3; } return 3; }";
531c332a984SYitzhak Mandelbaum   auto InlineX =
532c332a984SYitzhak Mandelbaum       makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
533c332a984SYitzhak Mandelbaum   testRule(makeRule(functionDecl(hasName("f")).bind("fun"),
534c332a984SYitzhak Mandelbaum                     rewriteDescendants("fun", InlineX)),
535c332a984SYitzhak Mandelbaum            Input, Expected);
536c332a984SYitzhak Mandelbaum }
537c332a984SYitzhak Mandelbaum 
538c332a984SYitzhak Mandelbaum // Rewrite various TypeLocs inside a Decl.
TEST_F(TransformerTest,RewriteDescendantsDeclChangeTypeLoc)539c332a984SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsDeclChangeTypeLoc) {
540c332a984SYitzhak Mandelbaum   std::string Input = "int f(int *x) { return *x; }";
541c332a984SYitzhak Mandelbaum   std::string Expected = "char f(char *x) { return *x; }";
542c332a984SYitzhak Mandelbaum   auto IntToChar = makeRule(typeLoc(loc(qualType(isInteger(), builtinType()))),
543c332a984SYitzhak Mandelbaum                             changeTo(cat("char")));
544c332a984SYitzhak Mandelbaum   testRule(makeRule(functionDecl(hasName("f")).bind("fun"),
545c332a984SYitzhak Mandelbaum                     rewriteDescendants("fun", IntToChar)),
546c332a984SYitzhak Mandelbaum            Input, Expected);
547c332a984SYitzhak Mandelbaum }
548c332a984SYitzhak Mandelbaum 
TEST_F(TransformerTest,RewriteDescendantsStmt)549c332a984SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsStmt) {
550c332a984SYitzhak Mandelbaum   // Add an unrelated definition to the header that also has a variable named
551c332a984SYitzhak Mandelbaum   // "x", to test that the rewrite is limited to the scope we intend.
552c332a984SYitzhak Mandelbaum   appendToHeader(R"cc(int g(int x) { return x; })cc");
553c332a984SYitzhak Mandelbaum   std::string Input =
554c332a984SYitzhak Mandelbaum       "int f(int x) { int y = x; { int z = x * x; } return x; }";
555c332a984SYitzhak Mandelbaum   std::string Expected =
556c332a984SYitzhak Mandelbaum       "int f(int x) { int y = 3; { int z = 3 * 3; } return 3; }";
557c332a984SYitzhak Mandelbaum   auto InlineX =
558c332a984SYitzhak Mandelbaum       makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
559c332a984SYitzhak Mandelbaum   testRule(makeRule(functionDecl(hasName("f"), hasBody(stmt().bind("body"))),
560c332a984SYitzhak Mandelbaum                     rewriteDescendants("body", InlineX)),
561c332a984SYitzhak Mandelbaum            Input, Expected);
562c332a984SYitzhak Mandelbaum }
563c332a984SYitzhak Mandelbaum 
TEST_F(TransformerTest,RewriteDescendantsStmtWithAdditionalChange)564c332a984SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsStmtWithAdditionalChange) {
565c332a984SYitzhak Mandelbaum   std::string Input =
566c332a984SYitzhak Mandelbaum       "int f(int x) { int y = x; { int z = x * x; } return x; }";
567c332a984SYitzhak Mandelbaum   std::string Expected =
568c332a984SYitzhak Mandelbaum       "int newName(int x) { int y = 3; { int z = 3 * 3; } return 3; }";
569c332a984SYitzhak Mandelbaum   auto InlineX =
570c332a984SYitzhak Mandelbaum       makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
571c332a984SYitzhak Mandelbaum   testRule(
572c332a984SYitzhak Mandelbaum       makeRule(
573c332a984SYitzhak Mandelbaum           functionDecl(hasName("f"), hasBody(stmt().bind("body"))).bind("f"),
574c332a984SYitzhak Mandelbaum           flatten(changeTo(name("f"), cat("newName")),
575c332a984SYitzhak Mandelbaum                   rewriteDescendants("body", InlineX))),
576c332a984SYitzhak Mandelbaum       Input, Expected);
577c332a984SYitzhak Mandelbaum }
578c332a984SYitzhak Mandelbaum 
TEST_F(TransformerTest,RewriteDescendantsTypeLoc)579c332a984SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsTypeLoc) {
580c332a984SYitzhak Mandelbaum   std::string Input = "int f(int *x) { return *x; }";
581c332a984SYitzhak Mandelbaum   std::string Expected = "int f(char *x) { return *x; }";
582c332a984SYitzhak Mandelbaum   auto IntToChar =
583c332a984SYitzhak Mandelbaum       makeRule(typeLoc(loc(qualType(isInteger(), builtinType()))).bind("loc"),
584c332a984SYitzhak Mandelbaum                changeTo(cat("char")));
585c332a984SYitzhak Mandelbaum   testRule(
586c332a984SYitzhak Mandelbaum       makeRule(functionDecl(hasName("f"),
587c332a984SYitzhak Mandelbaum                             hasParameter(0, varDecl(hasTypeLoc(
588c332a984SYitzhak Mandelbaum                                                 typeLoc().bind("parmType"))))),
589c332a984SYitzhak Mandelbaum                rewriteDescendants("parmType", IntToChar)),
590c332a984SYitzhak Mandelbaum       Input, Expected);
591c332a984SYitzhak Mandelbaum }
592c332a984SYitzhak Mandelbaum 
TEST_F(TransformerTest,RewriteDescendantsReferToParentBinding)593c332a984SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsReferToParentBinding) {
594c332a984SYitzhak Mandelbaum   std::string Input =
595c332a984SYitzhak Mandelbaum       "int f(int p) { int y = p; { int z = p * p; } return p; }";
596c332a984SYitzhak Mandelbaum   std::string Expected =
597c332a984SYitzhak Mandelbaum       "int f(int p) { int y = 3; { int z = 3 * 3; } return 3; }";
598c332a984SYitzhak Mandelbaum   std::string VarId = "var";
599c332a984SYitzhak Mandelbaum   auto InlineVar = makeRule(declRefExpr(to(varDecl(equalsBoundNode(VarId)))),
600c332a984SYitzhak Mandelbaum                             changeTo(cat("3")));
601c332a984SYitzhak Mandelbaum   testRule(makeRule(functionDecl(hasName("f"),
602c332a984SYitzhak Mandelbaum                                  hasParameter(0, varDecl().bind(VarId)))
603c332a984SYitzhak Mandelbaum                         .bind("fun"),
604c332a984SYitzhak Mandelbaum                     rewriteDescendants("fun", InlineVar)),
605c332a984SYitzhak Mandelbaum            Input, Expected);
606c332a984SYitzhak Mandelbaum }
607c332a984SYitzhak Mandelbaum 
TEST_F(TransformerTest,RewriteDescendantsUnboundNode)608c332a984SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsUnboundNode) {
609c332a984SYitzhak Mandelbaum   std::string Input =
610c332a984SYitzhak Mandelbaum       "int f(int x) { int y = x; { int z = x * x; } return x; }";
611c332a984SYitzhak Mandelbaum   auto InlineX =
612c332a984SYitzhak Mandelbaum       makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
613c332a984SYitzhak Mandelbaum   Transformer T(makeRule(functionDecl(hasName("f")),
614c332a984SYitzhak Mandelbaum                          rewriteDescendants("UNBOUND", InlineX)),
615c332a984SYitzhak Mandelbaum                 consumer());
616c332a984SYitzhak Mandelbaum   T.registerMatchers(&MatchFinder);
617c332a984SYitzhak Mandelbaum   EXPECT_FALSE(rewrite(Input));
618c332a984SYitzhak Mandelbaum   EXPECT_THAT(Changes, IsEmpty());
619c332a984SYitzhak Mandelbaum   EXPECT_EQ(ErrorCount, 1);
620c332a984SYitzhak Mandelbaum }
621c332a984SYitzhak Mandelbaum 
TEST_F(TransformerTest,RewriteDescendantsInvalidNodeType)622c332a984SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsInvalidNodeType) {
623c332a984SYitzhak Mandelbaum   std::string Input =
624c332a984SYitzhak Mandelbaum       "int f(int x) { int y = x; { int z = x * x; } return x; }";
625c332a984SYitzhak Mandelbaum   auto IntToChar =
626c332a984SYitzhak Mandelbaum       makeRule(qualType(isInteger(), builtinType()), changeTo(cat("char")));
627c332a984SYitzhak Mandelbaum   Transformer T(
628c332a984SYitzhak Mandelbaum       makeRule(functionDecl(
629c332a984SYitzhak Mandelbaum                    hasName("f"),
630c332a984SYitzhak Mandelbaum                    hasParameter(0, varDecl(hasType(qualType().bind("type"))))),
631c332a984SYitzhak Mandelbaum                rewriteDescendants("type", IntToChar)),
632c332a984SYitzhak Mandelbaum       consumer());
633c332a984SYitzhak Mandelbaum   T.registerMatchers(&MatchFinder);
634c332a984SYitzhak Mandelbaum   EXPECT_FALSE(rewrite(Input));
635c332a984SYitzhak Mandelbaum   EXPECT_THAT(Changes, IsEmpty());
636c332a984SYitzhak Mandelbaum   EXPECT_EQ(ErrorCount, 1);
637c332a984SYitzhak Mandelbaum }
638c332a984SYitzhak Mandelbaum 
639d4f39031SYitzhak Mandelbaum //
640d4f39031SYitzhak Mandelbaum // We include one test per typed overload. We don't test extensively since that
641d4f39031SYitzhak Mandelbaum // is already covered by the tests above.
642d4f39031SYitzhak Mandelbaum //
643d4f39031SYitzhak Mandelbaum 
TEST_F(TransformerTest,RewriteDescendantsTypedStmt)644d4f39031SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsTypedStmt) {
645d4f39031SYitzhak Mandelbaum   // Add an unrelated definition to the header that also has a variable named
646d4f39031SYitzhak Mandelbaum   // "x", to test that the rewrite is limited to the scope we intend.
647d4f39031SYitzhak Mandelbaum   appendToHeader(R"cc(int g(int x) { return x; })cc");
648d4f39031SYitzhak Mandelbaum   std::string Input =
649d4f39031SYitzhak Mandelbaum       "int f(int x) { int y = x; { int z = x * x; } return x; }";
650d4f39031SYitzhak Mandelbaum   std::string Expected =
651d4f39031SYitzhak Mandelbaum       "int f(int x) { int y = 3; { int z = 3 * 3; } return 3; }";
652d4f39031SYitzhak Mandelbaum   auto InlineX =
653d4f39031SYitzhak Mandelbaum       makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
654d4f39031SYitzhak Mandelbaum   testRule(makeRule(functionDecl(hasName("f"), hasBody(stmt().bind("body"))),
655d4f39031SYitzhak Mandelbaum                     [&InlineX](const MatchFinder::MatchResult &R) {
656d4f39031SYitzhak Mandelbaum                       const auto *Node = R.Nodes.getNodeAs<Stmt>("body");
657d4f39031SYitzhak Mandelbaum                       assert(Node != nullptr && "body must be bound");
658d4f39031SYitzhak Mandelbaum                       return transformer::detail::rewriteDescendants(
659d4f39031SYitzhak Mandelbaum                           *Node, InlineX, R);
660d4f39031SYitzhak Mandelbaum                     }),
661d4f39031SYitzhak Mandelbaum            Input, Expected);
662d4f39031SYitzhak Mandelbaum }
663d4f39031SYitzhak Mandelbaum 
TEST_F(TransformerTest,RewriteDescendantsTypedDecl)664d4f39031SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsTypedDecl) {
665d4f39031SYitzhak Mandelbaum   std::string Input =
666d4f39031SYitzhak Mandelbaum       "int f(int x) { int y = x; { int z = x * x; } return x; }";
667d4f39031SYitzhak Mandelbaum   std::string Expected =
668d4f39031SYitzhak Mandelbaum       "int f(int x) { int y = 3; { int z = 3 * 3; } return 3; }";
669d4f39031SYitzhak Mandelbaum   auto InlineX =
670d4f39031SYitzhak Mandelbaum       makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
671d4f39031SYitzhak Mandelbaum   testRule(makeRule(functionDecl(hasName("f")).bind("fun"),
672d4f39031SYitzhak Mandelbaum                     [&InlineX](const MatchFinder::MatchResult &R) {
673d4f39031SYitzhak Mandelbaum                       const auto *Node = R.Nodes.getNodeAs<Decl>("fun");
674d4f39031SYitzhak Mandelbaum                       assert(Node != nullptr && "fun must be bound");
675d4f39031SYitzhak Mandelbaum                       return transformer::detail::rewriteDescendants(
676d4f39031SYitzhak Mandelbaum                           *Node, InlineX, R);
677d4f39031SYitzhak Mandelbaum                     }),
678d4f39031SYitzhak Mandelbaum            Input, Expected);
679d4f39031SYitzhak Mandelbaum }
680d4f39031SYitzhak Mandelbaum 
TEST_F(TransformerTest,RewriteDescendantsTypedTypeLoc)681d4f39031SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsTypedTypeLoc) {
682d4f39031SYitzhak Mandelbaum   std::string Input = "int f(int *x) { return *x; }";
683d4f39031SYitzhak Mandelbaum   std::string Expected = "int f(char *x) { return *x; }";
684d4f39031SYitzhak Mandelbaum   auto IntToChar =
685d4f39031SYitzhak Mandelbaum       makeRule(typeLoc(loc(qualType(isInteger(), builtinType()))).bind("loc"),
686d4f39031SYitzhak Mandelbaum                changeTo(cat("char")));
687d4f39031SYitzhak Mandelbaum   testRule(
688d4f39031SYitzhak Mandelbaum       makeRule(
689d4f39031SYitzhak Mandelbaum           functionDecl(
690d4f39031SYitzhak Mandelbaum               hasName("f"),
691d4f39031SYitzhak Mandelbaum               hasParameter(0, varDecl(hasTypeLoc(typeLoc().bind("parmType"))))),
692d4f39031SYitzhak Mandelbaum           [&IntToChar](const MatchFinder::MatchResult &R) {
693d4f39031SYitzhak Mandelbaum             const auto *Node = R.Nodes.getNodeAs<TypeLoc>("parmType");
694d4f39031SYitzhak Mandelbaum             assert(Node != nullptr && "parmType must be bound");
695d4f39031SYitzhak Mandelbaum             return transformer::detail::rewriteDescendants(*Node, IntToChar, R);
696d4f39031SYitzhak Mandelbaum           }),
697d4f39031SYitzhak Mandelbaum       Input, Expected);
698d4f39031SYitzhak Mandelbaum }
699d4f39031SYitzhak Mandelbaum 
TEST_F(TransformerTest,RewriteDescendantsTypedDynTyped)700d4f39031SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsTypedDynTyped) {
701d4f39031SYitzhak Mandelbaum   // Add an unrelated definition to the header that also has a variable named
702d4f39031SYitzhak Mandelbaum   // "x", to test that the rewrite is limited to the scope we intend.
703d4f39031SYitzhak Mandelbaum   appendToHeader(R"cc(int g(int x) { return x; })cc");
704d4f39031SYitzhak Mandelbaum   std::string Input =
705d4f39031SYitzhak Mandelbaum       "int f(int x) { int y = x; { int z = x * x; } return x; }";
706d4f39031SYitzhak Mandelbaum   std::string Expected =
707d4f39031SYitzhak Mandelbaum       "int f(int x) { int y = 3; { int z = 3 * 3; } return 3; }";
708d4f39031SYitzhak Mandelbaum   auto InlineX =
709d4f39031SYitzhak Mandelbaum       makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
710d4f39031SYitzhak Mandelbaum   testRule(
711d4f39031SYitzhak Mandelbaum       makeRule(functionDecl(hasName("f"), hasBody(stmt().bind("body"))),
712d4f39031SYitzhak Mandelbaum                [&InlineX](const MatchFinder::MatchResult &R) {
713d4f39031SYitzhak Mandelbaum                  auto It = R.Nodes.getMap().find("body");
714d4f39031SYitzhak Mandelbaum                  assert(It != R.Nodes.getMap().end() && "body must be bound");
715d4f39031SYitzhak Mandelbaum                  return transformer::detail::rewriteDescendants(It->second,
716d4f39031SYitzhak Mandelbaum                                                                 InlineX, R);
717d4f39031SYitzhak Mandelbaum                }),
718d4f39031SYitzhak Mandelbaum       Input, Expected);
719d4f39031SYitzhak Mandelbaum }
720d4f39031SYitzhak Mandelbaum 
TEST_F(TransformerTest,InsertBeforeEdit)7212e4a628cSYitzhak Mandelbaum TEST_F(TransformerTest, InsertBeforeEdit) {
7222e4a628cSYitzhak Mandelbaum   std::string Input = R"cc(
7232e4a628cSYitzhak Mandelbaum     int f() {
7242e4a628cSYitzhak Mandelbaum       return 7;
7252e4a628cSYitzhak Mandelbaum     }
7262e4a628cSYitzhak Mandelbaum   )cc";
7272e4a628cSYitzhak Mandelbaum   std::string Expected = R"cc(
7282e4a628cSYitzhak Mandelbaum     int f() {
7292e4a628cSYitzhak Mandelbaum       int y = 3;
7302e4a628cSYitzhak Mandelbaum       return 7;
7312e4a628cSYitzhak Mandelbaum     }
7322e4a628cSYitzhak Mandelbaum   )cc";
7332e4a628cSYitzhak Mandelbaum 
7342e4a628cSYitzhak Mandelbaum   StringRef Ret = "return";
735adcd0268SBenjamin Kramer   testRule(
736adcd0268SBenjamin Kramer       makeRule(returnStmt().bind(Ret),
737adcd0268SBenjamin Kramer                insertBefore(statement(std::string(Ret)), cat("int y = 3;"))),
7382e4a628cSYitzhak Mandelbaum       Input, Expected);
7392e4a628cSYitzhak Mandelbaum }
7402e4a628cSYitzhak Mandelbaum 
TEST_F(TransformerTest,InsertAfterEdit)7412e4a628cSYitzhak Mandelbaum TEST_F(TransformerTest, InsertAfterEdit) {
7422e4a628cSYitzhak Mandelbaum   std::string Input = R"cc(
7432e4a628cSYitzhak Mandelbaum     int f() {
7442e4a628cSYitzhak Mandelbaum       int x = 5;
7452e4a628cSYitzhak Mandelbaum       return 7;
7462e4a628cSYitzhak Mandelbaum     }
7472e4a628cSYitzhak Mandelbaum   )cc";
7482e4a628cSYitzhak Mandelbaum   std::string Expected = R"cc(
7492e4a628cSYitzhak Mandelbaum     int f() {
7502e4a628cSYitzhak Mandelbaum       int x = 5;
7512e4a628cSYitzhak Mandelbaum       int y = 3;
7522e4a628cSYitzhak Mandelbaum       return 7;
7532e4a628cSYitzhak Mandelbaum     }
7542e4a628cSYitzhak Mandelbaum   )cc";
7552e4a628cSYitzhak Mandelbaum 
7562e4a628cSYitzhak Mandelbaum   StringRef Decl = "decl";
757adcd0268SBenjamin Kramer   testRule(
758adcd0268SBenjamin Kramer       makeRule(declStmt().bind(Decl),
759adcd0268SBenjamin Kramer                insertAfter(statement(std::string(Decl)), cat("int y = 3;"))),
7602e4a628cSYitzhak Mandelbaum       Input, Expected);
7612e4a628cSYitzhak Mandelbaum }
7622e4a628cSYitzhak Mandelbaum 
TEST_F(TransformerTest,RemoveEdit)7632e4a628cSYitzhak Mandelbaum TEST_F(TransformerTest, RemoveEdit) {
7642e4a628cSYitzhak Mandelbaum   std::string Input = R"cc(
7652e4a628cSYitzhak Mandelbaum     int f() {
7662e4a628cSYitzhak Mandelbaum       int x = 5;
7672e4a628cSYitzhak Mandelbaum       return 7;
7682e4a628cSYitzhak Mandelbaum     }
7692e4a628cSYitzhak Mandelbaum   )cc";
7702e4a628cSYitzhak Mandelbaum   std::string Expected = R"cc(
7712e4a628cSYitzhak Mandelbaum     int f() {
7722e4a628cSYitzhak Mandelbaum       return 7;
7732e4a628cSYitzhak Mandelbaum     }
7742e4a628cSYitzhak Mandelbaum   )cc";
7752e4a628cSYitzhak Mandelbaum 
7762e4a628cSYitzhak Mandelbaum   StringRef Decl = "decl";
777adcd0268SBenjamin Kramer   testRule(
778adcd0268SBenjamin Kramer       makeRule(declStmt().bind(Decl), remove(statement(std::string(Decl)))),
779adcd0268SBenjamin Kramer       Input, Expected);
7802e4a628cSYitzhak Mandelbaum }
7812e4a628cSYitzhak Mandelbaum 
TEST_F(TransformerTest,WithMetadata)7829945bd59SAndy Soffer TEST_F(TransformerTest, WithMetadata) {
783e5b3202bSAndy Soffer   auto makeMetadata = [](const MatchFinder::MatchResult &R) -> llvm::Any {
784e5b3202bSAndy Soffer     int N =
785e5b3202bSAndy Soffer         R.Nodes.getNodeAs<IntegerLiteral>("int")->getValue().getLimitedValue();
786e5b3202bSAndy Soffer     return N;
787e5b3202bSAndy Soffer   };
788e5b3202bSAndy Soffer 
7899945bd59SAndy Soffer   std::string Input = R"cc(
7909945bd59SAndy Soffer     int f() {
7919945bd59SAndy Soffer       int x = 5;
7929945bd59SAndy Soffer       return 7;
7939945bd59SAndy Soffer     }
7949945bd59SAndy Soffer   )cc";
7959945bd59SAndy Soffer 
7969945bd59SAndy Soffer   Transformer T(
797e5b3202bSAndy Soffer       makeRule(
798e5b3202bSAndy Soffer           declStmt(containsDeclaration(0, varDecl(hasInitializer(
799e5b3202bSAndy Soffer                                               integerLiteral().bind("int")))))
800e5b3202bSAndy Soffer               .bind("decl"),
801e5b3202bSAndy Soffer           withMetadata(remove(statement(std::string("decl"))), makeMetadata)),
8029945bd59SAndy Soffer       consumer());
8039945bd59SAndy Soffer   T.registerMatchers(&MatchFinder);
8049945bd59SAndy Soffer   auto Factory = newFrontendActionFactory(&MatchFinder);
8059945bd59SAndy Soffer   EXPECT_TRUE(runToolOnCodeWithArgs(
8069945bd59SAndy Soffer       Factory->create(), Input, std::vector<std::string>(), "input.cc",
8079945bd59SAndy Soffer       "clang-tool", std::make_shared<PCHContainerOperations>(), {}));
8089945bd59SAndy Soffer   ASSERT_EQ(Changes.size(), 1u);
8099945bd59SAndy Soffer   const llvm::Any &Metadata = Changes[0].getMetadata();
810bb7940e2SSebastian Neubauer   ASSERT_TRUE(llvm::any_cast<int>(&Metadata));
811e5b3202bSAndy Soffer   EXPECT_THAT(llvm::any_cast<int>(Metadata), 5);
8129945bd59SAndy Soffer }
8139945bd59SAndy Soffer 
TEST_F(TransformerTest,MultiChange)814fa1552e8SYitzhak Mandelbaum TEST_F(TransformerTest, MultiChange) {
815fa1552e8SYitzhak Mandelbaum   std::string Input = R"cc(
816fa1552e8SYitzhak Mandelbaum     void foo() {
817fa1552e8SYitzhak Mandelbaum       if (10 > 1.0)
818fa1552e8SYitzhak Mandelbaum         log(1) << "oh no!";
819fa1552e8SYitzhak Mandelbaum       else
820fa1552e8SYitzhak Mandelbaum         log(0) << "ok";
821fa1552e8SYitzhak Mandelbaum     }
822fa1552e8SYitzhak Mandelbaum   )cc";
823fa1552e8SYitzhak Mandelbaum   std::string Expected = R"(
824fa1552e8SYitzhak Mandelbaum     void foo() {
825fa1552e8SYitzhak Mandelbaum       if (true) { /* then */ }
826fa1552e8SYitzhak Mandelbaum       else { /* else */ }
827fa1552e8SYitzhak Mandelbaum     }
828fa1552e8SYitzhak Mandelbaum   )";
829fa1552e8SYitzhak Mandelbaum 
830fa1552e8SYitzhak Mandelbaum   StringRef C = "C", T = "T", E = "E";
831adcd0268SBenjamin Kramer   testRule(
832adcd0268SBenjamin Kramer       makeRule(ifStmt(hasCondition(expr().bind(C)), hasThen(stmt().bind(T)),
833adcd0268SBenjamin Kramer                       hasElse(stmt().bind(E))),
834adcd0268SBenjamin Kramer                {changeTo(node(std::string(C)), cat("true")),
835adcd0268SBenjamin Kramer                 changeTo(statement(std::string(T)), cat("{ /* then */ }")),
836adcd0268SBenjamin Kramer                 changeTo(statement(std::string(E)), cat("{ /* else */ }"))}),
837fdd98782SYitzhak Mandelbaum       Input, Expected);
838fdd98782SYitzhak Mandelbaum }
839fdd98782SYitzhak Mandelbaum 
TEST_F(TransformerTest,EditList)840cf428778SYitzhak Mandelbaum TEST_F(TransformerTest, EditList) {
841cf428778SYitzhak Mandelbaum   std::string Input = R"cc(
842cf428778SYitzhak Mandelbaum     void foo() {
843cf428778SYitzhak Mandelbaum       if (10 > 1.0)
844cf428778SYitzhak Mandelbaum         log(1) << "oh no!";
845cf428778SYitzhak Mandelbaum       else
846cf428778SYitzhak Mandelbaum         log(0) << "ok";
847cf428778SYitzhak Mandelbaum     }
848cf428778SYitzhak Mandelbaum   )cc";
849cf428778SYitzhak Mandelbaum   std::string Expected = R"(
850cf428778SYitzhak Mandelbaum     void foo() {
851cf428778SYitzhak Mandelbaum       if (true) { /* then */ }
852cf428778SYitzhak Mandelbaum       else { /* else */ }
853cf428778SYitzhak Mandelbaum     }
854cf428778SYitzhak Mandelbaum   )";
855cf428778SYitzhak Mandelbaum 
856cf428778SYitzhak Mandelbaum   StringRef C = "C", T = "T", E = "E";
857cf428778SYitzhak Mandelbaum   testRule(makeRule(ifStmt(hasCondition(expr().bind(C)),
858cf428778SYitzhak Mandelbaum                            hasThen(stmt().bind(T)), hasElse(stmt().bind(E))),
859cf428778SYitzhak Mandelbaum                     editList({changeTo(node(std::string(C)), cat("true")),
860cf428778SYitzhak Mandelbaum                               changeTo(statement(std::string(T)),
861cf428778SYitzhak Mandelbaum                                        cat("{ /* then */ }")),
862cf428778SYitzhak Mandelbaum                               changeTo(statement(std::string(E)),
863cf428778SYitzhak Mandelbaum                                        cat("{ /* else */ }"))})),
864cf428778SYitzhak Mandelbaum            Input, Expected);
865cf428778SYitzhak Mandelbaum }
866cf428778SYitzhak Mandelbaum 
TEST_F(TransformerTest,Flatten)867cf428778SYitzhak Mandelbaum TEST_F(TransformerTest, Flatten) {
868cf428778SYitzhak Mandelbaum   std::string Input = R"cc(
869cf428778SYitzhak Mandelbaum     void foo() {
870cf428778SYitzhak Mandelbaum       if (10 > 1.0)
871cf428778SYitzhak Mandelbaum         log(1) << "oh no!";
872cf428778SYitzhak Mandelbaum       else
873cf428778SYitzhak Mandelbaum         log(0) << "ok";
874cf428778SYitzhak Mandelbaum     }
875cf428778SYitzhak Mandelbaum   )cc";
876cf428778SYitzhak Mandelbaum   std::string Expected = R"(
877cf428778SYitzhak Mandelbaum     void foo() {
878cf428778SYitzhak Mandelbaum       if (true) { /* then */ }
879cf428778SYitzhak Mandelbaum       else { /* else */ }
880cf428778SYitzhak Mandelbaum     }
881cf428778SYitzhak Mandelbaum   )";
882cf428778SYitzhak Mandelbaum 
883cf428778SYitzhak Mandelbaum   StringRef C = "C", T = "T", E = "E";
884cf428778SYitzhak Mandelbaum   testRule(
885cf428778SYitzhak Mandelbaum       makeRule(
886cf428778SYitzhak Mandelbaum           ifStmt(hasCondition(expr().bind(C)), hasThen(stmt().bind(T)),
887cf428778SYitzhak Mandelbaum                  hasElse(stmt().bind(E))),
888cf428778SYitzhak Mandelbaum           flatten(changeTo(node(std::string(C)), cat("true")),
889cf428778SYitzhak Mandelbaum                   changeTo(statement(std::string(T)), cat("{ /* then */ }")),
890cf428778SYitzhak Mandelbaum                   changeTo(statement(std::string(E)), cat("{ /* else */ }")))),
891cf428778SYitzhak Mandelbaum       Input, Expected);
892cf428778SYitzhak Mandelbaum }
893cf428778SYitzhak Mandelbaum 
TEST_F(TransformerTest,FlattenWithMixedArgs)894cf428778SYitzhak Mandelbaum TEST_F(TransformerTest, FlattenWithMixedArgs) {
895cf428778SYitzhak Mandelbaum   using clang::transformer::editList;
896cf428778SYitzhak Mandelbaum   std::string Input = R"cc(
897cf428778SYitzhak Mandelbaum     void foo() {
898cf428778SYitzhak Mandelbaum       if (10 > 1.0)
899cf428778SYitzhak Mandelbaum         log(1) << "oh no!";
900cf428778SYitzhak Mandelbaum       else
901cf428778SYitzhak Mandelbaum         log(0) << "ok";
902cf428778SYitzhak Mandelbaum     }
903cf428778SYitzhak Mandelbaum   )cc";
904cf428778SYitzhak Mandelbaum   std::string Expected = R"(
905cf428778SYitzhak Mandelbaum     void foo() {
906cf428778SYitzhak Mandelbaum       if (true) { /* then */ }
907cf428778SYitzhak Mandelbaum       else { /* else */ }
908cf428778SYitzhak Mandelbaum     }
909cf428778SYitzhak Mandelbaum   )";
910cf428778SYitzhak Mandelbaum 
911cf428778SYitzhak Mandelbaum   StringRef C = "C", T = "T", E = "E";
912cf428778SYitzhak Mandelbaum   testRule(makeRule(ifStmt(hasCondition(expr().bind(C)),
913cf428778SYitzhak Mandelbaum                            hasThen(stmt().bind(T)), hasElse(stmt().bind(E))),
914cf428778SYitzhak Mandelbaum                     flatten(changeTo(node(std::string(C)), cat("true")),
915cf428778SYitzhak Mandelbaum                             edit(changeTo(statement(std::string(T)),
916cf428778SYitzhak Mandelbaum                                           cat("{ /* then */ }"))),
917cf428778SYitzhak Mandelbaum                             editList({changeTo(statement(std::string(E)),
918cf428778SYitzhak Mandelbaum                                                cat("{ /* else */ }"))}))),
919cf428778SYitzhak Mandelbaum            Input, Expected);
920cf428778SYitzhak Mandelbaum }
921cf428778SYitzhak Mandelbaum 
TEST_F(TransformerTest,OrderedRuleUnrelated)9228369a9beSYitzhak Mandelbaum TEST_F(TransformerTest, OrderedRuleUnrelated) {
9238369a9beSYitzhak Mandelbaum   StringRef Flag = "flag";
9249edeceaeSEric Li   RewriteRuleWith<std::string> FlagRule = makeRule(
9258369a9beSYitzhak Mandelbaum       cxxMemberCallExpr(on(expr(hasType(cxxRecordDecl(
9268369a9beSYitzhak Mandelbaum                                     hasName("proto::ProtoCommandLineFlag"))))
9278369a9beSYitzhak Mandelbaum                                .bind(Flag)),
9288369a9beSYitzhak Mandelbaum                         unless(callee(cxxMethodDecl(hasName("GetProto"))))),
9299edeceaeSEric Li       changeTo(node(std::string(Flag)), cat("PROTO")), cat(""));
9308369a9beSYitzhak Mandelbaum 
9318369a9beSYitzhak Mandelbaum   std::string Input = R"cc(
9328369a9beSYitzhak Mandelbaum     proto::ProtoCommandLineFlag flag;
9338369a9beSYitzhak Mandelbaum     int x = flag.foo();
9348369a9beSYitzhak Mandelbaum     int y = flag.GetProto().foo();
9358369a9beSYitzhak Mandelbaum     int f(string s) { return strlen(s.c_str()); }
9368369a9beSYitzhak Mandelbaum   )cc";
9378369a9beSYitzhak Mandelbaum   std::string Expected = R"cc(
9388369a9beSYitzhak Mandelbaum     proto::ProtoCommandLineFlag flag;
9398369a9beSYitzhak Mandelbaum     int x = PROTO.foo();
9408369a9beSYitzhak Mandelbaum     int y = flag.GetProto().foo();
9418369a9beSYitzhak Mandelbaum     int f(string s) { return REPLACED; }
9428369a9beSYitzhak Mandelbaum   )cc";
9438369a9beSYitzhak Mandelbaum 
9448369a9beSYitzhak Mandelbaum   testRule(applyFirst({ruleStrlenSize(), FlagRule}), Input, Expected);
9458369a9beSYitzhak Mandelbaum }
9468369a9beSYitzhak Mandelbaum 
TEST_F(TransformerTest,OrderedRuleRelated)9478369a9beSYitzhak Mandelbaum TEST_F(TransformerTest, OrderedRuleRelated) {
9488369a9beSYitzhak Mandelbaum   std::string Input = R"cc(
94942b957aaSYitzhak Mandelbaum     void f1();
95042b957aaSYitzhak Mandelbaum     void f2();
95142b957aaSYitzhak Mandelbaum     void call_f1() { f1(); }
95242b957aaSYitzhak Mandelbaum     void call_f2() { f2(); }
9538369a9beSYitzhak Mandelbaum   )cc";
9548369a9beSYitzhak Mandelbaum   std::string Expected = R"cc(
95542b957aaSYitzhak Mandelbaum     void f1();
95642b957aaSYitzhak Mandelbaum     void f2();
95742b957aaSYitzhak Mandelbaum     void call_f1() { REPLACE_F1; }
95842b957aaSYitzhak Mandelbaum     void call_f2() { REPLACE_F1_OR_F2; }
9598369a9beSYitzhak Mandelbaum   )cc";
9608369a9beSYitzhak Mandelbaum 
96142b957aaSYitzhak Mandelbaum   RewriteRule ReplaceF1 =
96242b957aaSYitzhak Mandelbaum       makeRule(callExpr(callee(functionDecl(hasName("f1")))),
9639f97480cSYitzhak Mandelbaum                changeTo(cat("REPLACE_F1")));
96442b957aaSYitzhak Mandelbaum   RewriteRule ReplaceF1OrF2 =
96542b957aaSYitzhak Mandelbaum       makeRule(callExpr(callee(functionDecl(hasAnyName("f1", "f2")))),
9669f97480cSYitzhak Mandelbaum                changeTo(cat("REPLACE_F1_OR_F2")));
96742b957aaSYitzhak Mandelbaum   testRule(applyFirst({ReplaceF1, ReplaceF1OrF2}), Input, Expected);
9688369a9beSYitzhak Mandelbaum }
9698369a9beSYitzhak Mandelbaum 
97042b957aaSYitzhak Mandelbaum // Change the order of the rules to get a different result. When `ReplaceF1OrF2`
97142b957aaSYitzhak Mandelbaum // comes first, it applies for both uses, so `ReplaceF1` never applies.
TEST_F(TransformerTest,OrderedRuleRelatedSwapped)9728369a9beSYitzhak Mandelbaum TEST_F(TransformerTest, OrderedRuleRelatedSwapped) {
9738369a9beSYitzhak Mandelbaum   std::string Input = R"cc(
97442b957aaSYitzhak Mandelbaum     void f1();
97542b957aaSYitzhak Mandelbaum     void f2();
97642b957aaSYitzhak Mandelbaum     void call_f1() { f1(); }
97742b957aaSYitzhak Mandelbaum     void call_f2() { f2(); }
9788369a9beSYitzhak Mandelbaum   )cc";
9798369a9beSYitzhak Mandelbaum   std::string Expected = R"cc(
98042b957aaSYitzhak Mandelbaum     void f1();
98142b957aaSYitzhak Mandelbaum     void f2();
98242b957aaSYitzhak Mandelbaum     void call_f1() { REPLACE_F1_OR_F2; }
98342b957aaSYitzhak Mandelbaum     void call_f2() { REPLACE_F1_OR_F2; }
9848369a9beSYitzhak Mandelbaum   )cc";
9858369a9beSYitzhak Mandelbaum 
98642b957aaSYitzhak Mandelbaum   RewriteRule ReplaceF1 =
98742b957aaSYitzhak Mandelbaum       makeRule(callExpr(callee(functionDecl(hasName("f1")))),
9889f97480cSYitzhak Mandelbaum                changeTo(cat("REPLACE_F1")));
98942b957aaSYitzhak Mandelbaum   RewriteRule ReplaceF1OrF2 =
99042b957aaSYitzhak Mandelbaum       makeRule(callExpr(callee(functionDecl(hasAnyName("f1", "f2")))),
9919f97480cSYitzhak Mandelbaum                changeTo(cat("REPLACE_F1_OR_F2")));
99242b957aaSYitzhak Mandelbaum   testRule(applyFirst({ReplaceF1OrF2, ReplaceF1}), Input, Expected);
99342b957aaSYitzhak Mandelbaum }
99442b957aaSYitzhak Mandelbaum 
99542b957aaSYitzhak Mandelbaum // Verify that a set of rules whose matchers have different base kinds works
99642b957aaSYitzhak Mandelbaum // properly, including that `applyFirst` produces multiple matchers.  We test
99742b957aaSYitzhak Mandelbaum // two different kinds of rules: Expr and Decl. We place the Decl rule in the
99842b957aaSYitzhak Mandelbaum // middle to test that `buildMatchers` works even when the kinds aren't grouped
99942b957aaSYitzhak Mandelbaum // together.
TEST_F(TransformerTest,OrderedRuleMultipleKinds)100042b957aaSYitzhak Mandelbaum TEST_F(TransformerTest, OrderedRuleMultipleKinds) {
100142b957aaSYitzhak Mandelbaum   std::string Input = R"cc(
100242b957aaSYitzhak Mandelbaum     void f1();
100342b957aaSYitzhak Mandelbaum     void f2();
100442b957aaSYitzhak Mandelbaum     void call_f1() { f1(); }
100542b957aaSYitzhak Mandelbaum     void call_f2() { f2(); }
100642b957aaSYitzhak Mandelbaum   )cc";
100742b957aaSYitzhak Mandelbaum   std::string Expected = R"cc(
100842b957aaSYitzhak Mandelbaum     void f1();
100942b957aaSYitzhak Mandelbaum     void DECL_RULE();
101042b957aaSYitzhak Mandelbaum     void call_f1() { REPLACE_F1; }
101142b957aaSYitzhak Mandelbaum     void call_f2() { REPLACE_F1_OR_F2; }
101242b957aaSYitzhak Mandelbaum   )cc";
101342b957aaSYitzhak Mandelbaum 
101442b957aaSYitzhak Mandelbaum   RewriteRule ReplaceF1 =
101542b957aaSYitzhak Mandelbaum       makeRule(callExpr(callee(functionDecl(hasName("f1")))),
10169f97480cSYitzhak Mandelbaum                changeTo(cat("REPLACE_F1")));
101742b957aaSYitzhak Mandelbaum   RewriteRule ReplaceF1OrF2 =
101842b957aaSYitzhak Mandelbaum       makeRule(callExpr(callee(functionDecl(hasAnyName("f1", "f2")))),
10199f97480cSYitzhak Mandelbaum                changeTo(cat("REPLACE_F1_OR_F2")));
102042b957aaSYitzhak Mandelbaum   RewriteRule DeclRule = makeRule(functionDecl(hasName("f2")).bind("fun"),
10219f97480cSYitzhak Mandelbaum                                   changeTo(name("fun"), cat("DECL_RULE")));
102242b957aaSYitzhak Mandelbaum 
102342b957aaSYitzhak Mandelbaum   RewriteRule Rule = applyFirst({ReplaceF1, DeclRule, ReplaceF1OrF2});
10248bb47cd8SYitzhak Mandelbaum   EXPECT_EQ(transformer::detail::buildMatchers(Rule).size(), 2UL);
102542b957aaSYitzhak Mandelbaum   testRule(Rule, Input, Expected);
10268369a9beSYitzhak Mandelbaum }
10278369a9beSYitzhak Mandelbaum 
1028ce5780b8SYitzhak Mandelbaum // Verifies that a rule with a top-level matcher for an implicit node (like
10296f0a3711SYitzhak Mandelbaum // `implicitCastExpr`) works correctly -- the implicit nodes are not skipped.
TEST_F(TransformerTest,OrderedRuleImplicitMatched)1030ce5780b8SYitzhak Mandelbaum TEST_F(TransformerTest, OrderedRuleImplicitMatched) {
1031ce5780b8SYitzhak Mandelbaum   std::string Input = R"cc(
1032ce5780b8SYitzhak Mandelbaum     void f1();
1033ce5780b8SYitzhak Mandelbaum     int f2();
1034ce5780b8SYitzhak Mandelbaum     void call_f1() { f1(); }
1035ce5780b8SYitzhak Mandelbaum     float call_f2() { return f2(); }
1036ce5780b8SYitzhak Mandelbaum   )cc";
1037ce5780b8SYitzhak Mandelbaum   std::string Expected = R"cc(
1038ce5780b8SYitzhak Mandelbaum     void f1();
1039ce5780b8SYitzhak Mandelbaum     int f2();
1040ce5780b8SYitzhak Mandelbaum     void call_f1() { REPLACE_F1; }
1041ce5780b8SYitzhak Mandelbaum     float call_f2() { return REPLACE_F2; }
1042ce5780b8SYitzhak Mandelbaum   )cc";
1043ce5780b8SYitzhak Mandelbaum 
10446f0a3711SYitzhak Mandelbaum   RewriteRule ReplaceF1 =
10456f0a3711SYitzhak Mandelbaum       makeRule(callExpr(callee(functionDecl(hasName("f1")))),
1046ce5780b8SYitzhak Mandelbaum                changeTo(cat("REPLACE_F1")));
1047ce5780b8SYitzhak Mandelbaum   RewriteRule ReplaceF2 =
10486f0a3711SYitzhak Mandelbaum       makeRule(implicitCastExpr(hasSourceExpression(callExpr())),
1049ce5780b8SYitzhak Mandelbaum                changeTo(cat("REPLACE_F2")));
1050ce5780b8SYitzhak Mandelbaum   testRule(applyFirst({ReplaceF1, ReplaceF2}), Input, Expected);
1051ce5780b8SYitzhak Mandelbaum }
1052ce5780b8SYitzhak Mandelbaum 
1053fdd98782SYitzhak Mandelbaum //
1054fdd98782SYitzhak Mandelbaum // Negative tests (where we expect no transformation to occur).
1055fdd98782SYitzhak Mandelbaum //
1056fdd98782SYitzhak Mandelbaum 
1057fa1552e8SYitzhak Mandelbaum // Tests for a conflict in edits from a single match for a rule.
TEST_F(TransformerTest,TextGeneratorFailure)1058aecc59c5SYitzhak Mandelbaum TEST_F(TransformerTest, TextGeneratorFailure) {
1059aecc59c5SYitzhak Mandelbaum   std::string Input = "int conflictOneRule() { return 3 + 7; }";
1060aecc59c5SYitzhak Mandelbaum   // Try to change the whole binary-operator expression AND one its operands:
1061aecc59c5SYitzhak Mandelbaum   StringRef O = "O";
1062489449c2SYitzhak Mandelbaum   class AlwaysFail : public transformer::MatchComputation<std::string> {
1063489449c2SYitzhak Mandelbaum     llvm::Error eval(const ast_matchers::MatchFinder::MatchResult &,
1064489449c2SYitzhak Mandelbaum                      std::string *) const override {
1065aecc59c5SYitzhak Mandelbaum       return llvm::createStringError(llvm::errc::invalid_argument, "ERROR");
1066489449c2SYitzhak Mandelbaum     }
1067489449c2SYitzhak Mandelbaum     std::string toString() const override { return "AlwaysFail"; }
1068aecc59c5SYitzhak Mandelbaum   };
1069adcd0268SBenjamin Kramer   Transformer T(
1070adcd0268SBenjamin Kramer       makeRule(binaryOperator().bind(O),
1071adcd0268SBenjamin Kramer                changeTo(node(std::string(O)), std::make_shared<AlwaysFail>())),
1072aecc59c5SYitzhak Mandelbaum       consumer());
1073aecc59c5SYitzhak Mandelbaum   T.registerMatchers(&MatchFinder);
1074aecc59c5SYitzhak Mandelbaum   EXPECT_FALSE(rewrite(Input));
1075aecc59c5SYitzhak Mandelbaum   EXPECT_THAT(Changes, IsEmpty());
1076aecc59c5SYitzhak Mandelbaum   EXPECT_EQ(ErrorCount, 1);
1077aecc59c5SYitzhak Mandelbaum }
1078aecc59c5SYitzhak Mandelbaum 
1079aecc59c5SYitzhak Mandelbaum // Tests for a conflict in edits from a single match for a rule.
TEST_F(TransformerTest,OverlappingEditsInRule)1080fa1552e8SYitzhak Mandelbaum TEST_F(TransformerTest, OverlappingEditsInRule) {
1081fa1552e8SYitzhak Mandelbaum   std::string Input = "int conflictOneRule() { return 3 + 7; }";
1082fa1552e8SYitzhak Mandelbaum   // Try to change the whole binary-operator expression AND one its operands:
1083fa1552e8SYitzhak Mandelbaum   StringRef O = "O", L = "L";
10843ec50e29SYitzhak Mandelbaum   Transformer T(makeRule(binaryOperator(hasLHS(expr().bind(L))).bind(O),
1085adcd0268SBenjamin Kramer                          {changeTo(node(std::string(O)), cat("DELETE_OP")),
1086adcd0268SBenjamin Kramer                           changeTo(node(std::string(L)), cat("DELETE_LHS"))}),
1087aecc59c5SYitzhak Mandelbaum                 consumer());
1088fa1552e8SYitzhak Mandelbaum   T.registerMatchers(&MatchFinder);
1089aecc59c5SYitzhak Mandelbaum   EXPECT_FALSE(rewrite(Input));
1090aecc59c5SYitzhak Mandelbaum   EXPECT_THAT(Changes, IsEmpty());
1091aecc59c5SYitzhak Mandelbaum   EXPECT_EQ(ErrorCount, 1);
1092fa1552e8SYitzhak Mandelbaum }
1093fa1552e8SYitzhak Mandelbaum 
1094fa1552e8SYitzhak Mandelbaum // Tests for a conflict in edits across multiple matches (of the same rule).
TEST_F(TransformerTest,OverlappingEditsMultipleMatches)1095fa1552e8SYitzhak Mandelbaum TEST_F(TransformerTest, OverlappingEditsMultipleMatches) {
1096fa1552e8SYitzhak Mandelbaum   std::string Input = "int conflictOneRule() { return -7; }";
1097fa1552e8SYitzhak Mandelbaum   // Try to change the whole binary-operator expression AND one its operands:
1098fa1552e8SYitzhak Mandelbaum   StringRef E = "E";
1099adcd0268SBenjamin Kramer   Transformer T(makeRule(expr().bind(E),
1100adcd0268SBenjamin Kramer                          changeTo(node(std::string(E)), cat("DELETE_EXPR"))),
1101aecc59c5SYitzhak Mandelbaum                 consumer());
1102fa1552e8SYitzhak Mandelbaum   T.registerMatchers(&MatchFinder);
1103fa1552e8SYitzhak Mandelbaum   // The rewrite process fails because the changes conflict with each other...
1104fa1552e8SYitzhak Mandelbaum   EXPECT_FALSE(rewrite(Input));
1105aecc59c5SYitzhak Mandelbaum   // ... but two changes were produced.
1106aecc59c5SYitzhak Mandelbaum   EXPECT_EQ(Changes.size(), 2u);
1107aecc59c5SYitzhak Mandelbaum   EXPECT_EQ(ErrorCount, 0);
1108fa1552e8SYitzhak Mandelbaum }
1109fa1552e8SYitzhak Mandelbaum 
TEST_F(TransformerTest,ErrorOccurredMatchSkipped)1110fa1552e8SYitzhak Mandelbaum TEST_F(TransformerTest, ErrorOccurredMatchSkipped) {
1111fa1552e8SYitzhak Mandelbaum   // Syntax error in the function body:
1112fa1552e8SYitzhak Mandelbaum   std::string Input = "void errorOccurred() { 3 }";
1113aecc59c5SYitzhak Mandelbaum   Transformer T(makeRule(functionDecl(hasName("errorOccurred")),
11149f97480cSYitzhak Mandelbaum                          changeTo(cat("DELETED;"))),
1115aecc59c5SYitzhak Mandelbaum                 consumer());
1116fa1552e8SYitzhak Mandelbaum   T.registerMatchers(&MatchFinder);
1117fa1552e8SYitzhak Mandelbaum   // The rewrite process itself fails...
1118fa1552e8SYitzhak Mandelbaum   EXPECT_FALSE(rewrite(Input));
1119aecc59c5SYitzhak Mandelbaum   // ... and no changes or errors are produced in the process.
1120aecc59c5SYitzhak Mandelbaum   EXPECT_THAT(Changes, IsEmpty());
1121aecc59c5SYitzhak Mandelbaum   EXPECT_EQ(ErrorCount, 0);
1122fa1552e8SYitzhak Mandelbaum }
1123fa1552e8SYitzhak Mandelbaum 
TEST_F(TransformerTest,ImplicitNodes_ConstructorDecl)1124246b428fSStephen Kelly TEST_F(TransformerTest, ImplicitNodes_ConstructorDecl) {
1125246b428fSStephen Kelly 
1126246b428fSStephen Kelly   std::string OtherStructPrefix = R"cpp(
1127246b428fSStephen Kelly struct Other {
1128246b428fSStephen Kelly )cpp";
1129246b428fSStephen Kelly   std::string OtherStructSuffix = "};";
1130246b428fSStephen Kelly 
1131246b428fSStephen Kelly   std::string CopyableStructName = "struct Copyable";
1132246b428fSStephen Kelly   std::string BrokenStructName = "struct explicit Copyable";
1133246b428fSStephen Kelly 
1134246b428fSStephen Kelly   std::string CodeSuffix = R"cpp(
1135246b428fSStephen Kelly {
1136246b428fSStephen Kelly     Other m_i;
1137246b428fSStephen Kelly     Copyable();
1138246b428fSStephen Kelly };
1139246b428fSStephen Kelly )cpp";
1140246b428fSStephen Kelly 
1141246b428fSStephen Kelly   std::string CopyCtor = "Other(const Other&) = default;";
1142246b428fSStephen Kelly   std::string ExplicitCopyCtor = "explicit Other(const Other&) = default;";
1143246b428fSStephen Kelly   std::string BrokenExplicitCopyCtor =
1144246b428fSStephen Kelly       "explicit explicit explicit Other(const Other&) = default;";
1145246b428fSStephen Kelly 
1146246b428fSStephen Kelly   std::string RewriteInput = OtherStructPrefix + CopyCtor + OtherStructSuffix +
1147246b428fSStephen Kelly                              CopyableStructName + CodeSuffix;
1148246b428fSStephen Kelly   std::string ExpectedRewriteOutput = OtherStructPrefix + ExplicitCopyCtor +
1149246b428fSStephen Kelly                                       OtherStructSuffix + CopyableStructName +
1150246b428fSStephen Kelly                                       CodeSuffix;
1151246b428fSStephen Kelly   std::string BrokenRewriteOutput = OtherStructPrefix + BrokenExplicitCopyCtor +
1152246b428fSStephen Kelly                                     OtherStructSuffix + BrokenStructName +
1153246b428fSStephen Kelly                                     CodeSuffix;
1154246b428fSStephen Kelly 
1155246b428fSStephen Kelly   auto MatchedRecord =
1156246b428fSStephen Kelly       cxxConstructorDecl(isCopyConstructor()).bind("copyConstructor");
1157246b428fSStephen Kelly 
1158246b428fSStephen Kelly   auto RewriteRule =
1159246b428fSStephen Kelly       changeTo(before(node("copyConstructor")), cat("explicit "));
1160246b428fSStephen Kelly 
1161246b428fSStephen Kelly   testRule(makeRule(traverse(TK_IgnoreUnlessSpelledInSource, MatchedRecord),
1162246b428fSStephen Kelly                     RewriteRule),
1163246b428fSStephen Kelly            RewriteInput, ExpectedRewriteOutput);
1164246b428fSStephen Kelly 
1165246b428fSStephen Kelly   testRule(makeRule(traverse(TK_AsIs, MatchedRecord), RewriteRule),
1166246b428fSStephen Kelly            RewriteInput, BrokenRewriteOutput);
1167246b428fSStephen Kelly }
1168246b428fSStephen Kelly 
TEST_F(TransformerTest,ImplicitNodes_RangeFor)1169246b428fSStephen Kelly TEST_F(TransformerTest, ImplicitNodes_RangeFor) {
1170246b428fSStephen Kelly 
1171246b428fSStephen Kelly   std::string CodePrefix = R"cpp(
1172246b428fSStephen Kelly struct Container
1173246b428fSStephen Kelly {
1174246b428fSStephen Kelly     int* begin() const;
1175246b428fSStephen Kelly     int* end() const;
1176246b428fSStephen Kelly     int* cbegin() const;
1177246b428fSStephen Kelly     int* cend() const;
1178246b428fSStephen Kelly };
1179246b428fSStephen Kelly 
1180246b428fSStephen Kelly void foo()
1181246b428fSStephen Kelly {
1182246b428fSStephen Kelly   const Container c;
1183246b428fSStephen Kelly )cpp";
1184246b428fSStephen Kelly 
1185246b428fSStephen Kelly   std::string BeginCallBefore = "  c.begin();";
1186246b428fSStephen Kelly   std::string BeginCallAfter = "  c.cbegin();";
1187246b428fSStephen Kelly 
1188246b428fSStephen Kelly   std::string ForLoop = "for (auto i : c)";
1189246b428fSStephen Kelly   std::string BrokenForLoop = "for (auto i :.cbegin() c)";
1190246b428fSStephen Kelly 
1191246b428fSStephen Kelly   std::string CodeSuffix = R"cpp(
1192246b428fSStephen Kelly   {
1193246b428fSStephen Kelly   }
1194246b428fSStephen Kelly }
1195246b428fSStephen Kelly )cpp";
1196246b428fSStephen Kelly 
1197246b428fSStephen Kelly   std::string RewriteInput =
1198246b428fSStephen Kelly       CodePrefix + BeginCallBefore + ForLoop + CodeSuffix;
1199246b428fSStephen Kelly   std::string ExpectedRewriteOutput =
1200246b428fSStephen Kelly       CodePrefix + BeginCallAfter + ForLoop + CodeSuffix;
1201246b428fSStephen Kelly   std::string BrokenRewriteOutput =
1202246b428fSStephen Kelly       CodePrefix + BeginCallAfter + BrokenForLoop + CodeSuffix;
1203246b428fSStephen Kelly 
1204246b428fSStephen Kelly   auto MatchedRecord =
1205246b428fSStephen Kelly       cxxMemberCallExpr(on(expr(hasType(qualType(isConstQualified(),
1206246b428fSStephen Kelly                                                  hasDeclaration(cxxRecordDecl(
1207246b428fSStephen Kelly                                                      hasName("Container"))))))
1208246b428fSStephen Kelly                                .bind("callTarget")),
1209246b428fSStephen Kelly                         callee(cxxMethodDecl(hasName("begin"))))
1210246b428fSStephen Kelly           .bind("constBeginCall");
1211246b428fSStephen Kelly 
1212246b428fSStephen Kelly   auto RewriteRule =
1213246b428fSStephen Kelly       changeTo(node("constBeginCall"), cat(name("callTarget"), ".cbegin()"));
1214246b428fSStephen Kelly 
1215246b428fSStephen Kelly   testRule(makeRule(traverse(TK_IgnoreUnlessSpelledInSource, MatchedRecord),
1216246b428fSStephen Kelly                     RewriteRule),
1217246b428fSStephen Kelly            RewriteInput, ExpectedRewriteOutput);
1218246b428fSStephen Kelly 
1219246b428fSStephen Kelly   testRule(makeRule(traverse(TK_AsIs, MatchedRecord), RewriteRule),
1220246b428fSStephen Kelly            RewriteInput, BrokenRewriteOutput);
1221246b428fSStephen Kelly }
1222246b428fSStephen Kelly 
TEST_F(TransformerTest,ImplicitNodes_ForStmt)1223246b428fSStephen Kelly TEST_F(TransformerTest, ImplicitNodes_ForStmt) {
1224246b428fSStephen Kelly 
1225246b428fSStephen Kelly   std::string CodePrefix = R"cpp(
1226246b428fSStephen Kelly struct NonTrivial {
1227246b428fSStephen Kelly     NonTrivial() {}
1228246b428fSStephen Kelly     NonTrivial(NonTrivial&) {}
1229246b428fSStephen Kelly     NonTrivial& operator=(NonTrivial const&) { return *this; }
1230246b428fSStephen Kelly 
1231246b428fSStephen Kelly     ~NonTrivial() {}
1232246b428fSStephen Kelly };
1233246b428fSStephen Kelly 
1234246b428fSStephen Kelly struct ContainsArray {
1235246b428fSStephen Kelly     NonTrivial arr[2];
1236246b428fSStephen Kelly     ContainsArray& operator=(ContainsArray const&) = default;
1237246b428fSStephen Kelly };
1238246b428fSStephen Kelly 
1239246b428fSStephen Kelly void testIt()
1240246b428fSStephen Kelly {
1241246b428fSStephen Kelly     ContainsArray ca1;
1242246b428fSStephen Kelly     ContainsArray ca2;
1243246b428fSStephen Kelly     ca2 = ca1;
1244246b428fSStephen Kelly )cpp";
1245246b428fSStephen Kelly 
1246246b428fSStephen Kelly   auto CodeSuffix = "}";
1247246b428fSStephen Kelly 
1248246b428fSStephen Kelly   auto LoopBody = R"cpp(
1249246b428fSStephen Kelly     {
1250246b428fSStephen Kelly 
1251246b428fSStephen Kelly     }
1252246b428fSStephen Kelly )cpp";
1253246b428fSStephen Kelly 
1254246b428fSStephen Kelly   auto RawLoop = "for (auto i = 0; i != 5; ++i)";
1255246b428fSStephen Kelly 
1256246b428fSStephen Kelly   auto RangeLoop = "for (auto i : boost::irange(5))";
1257246b428fSStephen Kelly 
1258246b428fSStephen Kelly   // Expect to rewrite the raw loop to the ranged loop.
1259246b428fSStephen Kelly   // This works in TK_IgnoreUnlessSpelledInSource mode, but TK_AsIs
1260246b428fSStephen Kelly   // mode also matches the hidden for loop generated in the copy assignment
1261246b428fSStephen Kelly   // operator of ContainsArray. Transformer then fails to transform the code at
1262246b428fSStephen Kelly   // all.
1263246b428fSStephen Kelly 
1264246b428fSStephen Kelly   auto RewriteInput =
1265246b428fSStephen Kelly       CodePrefix + RawLoop + LoopBody + RawLoop + LoopBody + CodeSuffix;
1266246b428fSStephen Kelly 
1267246b428fSStephen Kelly   auto RewriteOutput =
1268246b428fSStephen Kelly       CodePrefix + RangeLoop + LoopBody + RangeLoop + LoopBody + CodeSuffix;
1269ef1a4169SStephen Kelly 
1270246b428fSStephen Kelly   auto MatchedLoop = forStmt(
1271a29fd4d4SEric Li       has(declStmt(hasSingleDecl(
1272a29fd4d4SEric Li           varDecl(hasInitializer(integerLiteral(equals(0)))).bind("loopVar")))),
1273246b428fSStephen Kelly       has(binaryOperator(hasOperatorName("!="),
1274246b428fSStephen Kelly                          hasLHS(ignoringImplicit(declRefExpr(
1275246b428fSStephen Kelly                              to(varDecl(equalsBoundNode("loopVar")))))),
1276246b428fSStephen Kelly                          hasRHS(expr().bind("upperBoundExpr")))),
1277246b428fSStephen Kelly       has(unaryOperator(hasOperatorName("++"),
1278246b428fSStephen Kelly                         hasUnaryOperand(declRefExpr(
1279246b428fSStephen Kelly                             to(varDecl(equalsBoundNode("loopVar"))))))
1280246b428fSStephen Kelly               .bind("incrementOp")));
1281246b428fSStephen Kelly 
1282246b428fSStephen Kelly   auto RewriteRule =
1283246b428fSStephen Kelly       changeTo(transformer::enclose(node("loopVar"), node("incrementOp")),
1284246b428fSStephen Kelly                cat("auto ", name("loopVar"), " : boost::irange(",
1285246b428fSStephen Kelly                    node("upperBoundExpr"), ")"));
1286246b428fSStephen Kelly 
1287246b428fSStephen Kelly   testRule(makeRule(traverse(TK_IgnoreUnlessSpelledInSource, MatchedLoop),
1288246b428fSStephen Kelly                     RewriteRule),
1289246b428fSStephen Kelly            RewriteInput, RewriteOutput);
1290246b428fSStephen Kelly 
1291246b428fSStephen Kelly   testRuleFailure(makeRule(traverse(TK_AsIs, MatchedLoop), RewriteRule),
1292246b428fSStephen Kelly                   RewriteInput);
1293246b428fSStephen Kelly }
1294ef1a4169SStephen Kelly 
TEST_F(TransformerTest,ImplicitNodes_ForStmt2)1295ef1a4169SStephen Kelly TEST_F(TransformerTest, ImplicitNodes_ForStmt2) {
1296ef1a4169SStephen Kelly 
1297ef1a4169SStephen Kelly   std::string CodePrefix = R"cpp(
1298ef1a4169SStephen Kelly struct NonTrivial {
1299ef1a4169SStephen Kelly     NonTrivial() {}
1300ef1a4169SStephen Kelly     NonTrivial(NonTrivial&) {}
1301ef1a4169SStephen Kelly     NonTrivial& operator=(NonTrivial const&) { return *this; }
1302ef1a4169SStephen Kelly 
1303ef1a4169SStephen Kelly     ~NonTrivial() {}
1304ef1a4169SStephen Kelly };
1305ef1a4169SStephen Kelly 
1306ef1a4169SStephen Kelly struct ContainsArray {
1307ef1a4169SStephen Kelly     NonTrivial arr[2];
1308ef1a4169SStephen Kelly     ContainsArray& operator=(ContainsArray const&) = default;
1309ef1a4169SStephen Kelly };
1310ef1a4169SStephen Kelly 
1311ef1a4169SStephen Kelly void testIt()
13124cadb66bSStephen Kelly {
1313ef1a4169SStephen Kelly     ContainsArray ca1;
1314ef1a4169SStephen Kelly     ContainsArray ca2;
1315ef1a4169SStephen Kelly     ca2 = ca1;
1316ef1a4169SStephen Kelly )cpp";
1317ef1a4169SStephen Kelly 
1318ef1a4169SStephen Kelly   auto CodeSuffix = "}";
1319ef1a4169SStephen Kelly 
1320ef1a4169SStephen Kelly   auto LoopBody = R"cpp(
1321ef1a4169SStephen Kelly     {
1322ef1a4169SStephen Kelly 
1323ef1a4169SStephen Kelly     }
1324ef1a4169SStephen Kelly )cpp";
1325ef1a4169SStephen Kelly 
1326ef1a4169SStephen Kelly   auto RawLoop = "for (auto i = 0; i != 5; ++i)";
1327ef1a4169SStephen Kelly 
1328ef1a4169SStephen Kelly   auto RangeLoop = "for (auto i : boost::irange(5))";
1329ef1a4169SStephen Kelly 
1330ef1a4169SStephen Kelly   // Expect to rewrite the raw loop to the ranged loop.
1331ef1a4169SStephen Kelly   // This works in TK_IgnoreUnlessSpelledInSource mode, but TK_AsIs
1332ef1a4169SStephen Kelly   // mode also matches the hidden for loop generated in the copy assignment
1333ef1a4169SStephen Kelly   // operator of ContainsArray. Transformer then fails to transform the code at
1334ef1a4169SStephen Kelly   // all.
1335ef1a4169SStephen Kelly 
1336ef1a4169SStephen Kelly   auto RewriteInput =
1337ef1a4169SStephen Kelly       CodePrefix + RawLoop + LoopBody + RawLoop + LoopBody + CodeSuffix;
1338ef1a4169SStephen Kelly 
1339ef1a4169SStephen Kelly   auto RewriteOutput =
1340ef1a4169SStephen Kelly       CodePrefix + RangeLoop + LoopBody + RangeLoop + LoopBody + CodeSuffix;
13414cadb66bSStephen Kelly   auto MatchedLoop = forStmt(
1342a29fd4d4SEric Li       hasLoopInit(declStmt(hasSingleDecl(
1343a29fd4d4SEric Li           varDecl(hasInitializer(integerLiteral(equals(0)))).bind("loopVar")))),
13444cadb66bSStephen Kelly       hasCondition(binaryOperator(hasOperatorName("!="),
13454cadb66bSStephen Kelly                                   hasLHS(ignoringImplicit(declRefExpr(to(
13464cadb66bSStephen Kelly                                       varDecl(equalsBoundNode("loopVar")))))),
13474cadb66bSStephen Kelly                                   hasRHS(expr().bind("upperBoundExpr")))),
13484cadb66bSStephen Kelly       hasIncrement(unaryOperator(hasOperatorName("++"),
1349a29fd4d4SEric Li                                  hasUnaryOperand(declRefExpr(
1350a29fd4d4SEric Li                                      to(varDecl(equalsBoundNode("loopVar"))))))
13514cadb66bSStephen Kelly                        .bind("incrementOp")));
13524cadb66bSStephen Kelly 
13534cadb66bSStephen Kelly   auto RewriteRule =
13544cadb66bSStephen Kelly       changeTo(transformer::enclose(node("loopVar"), node("incrementOp")),
13554cadb66bSStephen Kelly                cat("auto ", name("loopVar"), " : boost::irange(",
13564cadb66bSStephen Kelly                    node("upperBoundExpr"), ")"));
13574cadb66bSStephen Kelly 
1358ef1a4169SStephen Kelly   testRule(makeRule(traverse(TK_IgnoreUnlessSpelledInSource, MatchedLoop),
1359ef1a4169SStephen Kelly                     RewriteRule),
1360ef1a4169SStephen Kelly            RewriteInput, RewriteOutput);
13614cadb66bSStephen Kelly 
13624cadb66bSStephen Kelly   testRuleFailure(makeRule(traverse(TK_AsIs, MatchedLoop), RewriteRule),
13634cadb66bSStephen Kelly                   RewriteInput);
1364246b428fSStephen Kelly }
1365246b428fSStephen Kelly 
TEST_F(TransformerTest,TemplateInstantiation)1366a6d15d40SMatt Morehouse TEST_F(TransformerTest, TemplateInstantiation) {
1367a6d15d40SMatt Morehouse 
1368a6d15d40SMatt Morehouse   std::string NonTemplatesInput = R"cpp(
1369a6d15d40SMatt Morehouse struct S {
1370a6d15d40SMatt Morehouse   int m_i;
1371a6d15d40SMatt Morehouse };
1372a6d15d40SMatt Morehouse )cpp";
1373a6d15d40SMatt Morehouse   std::string NonTemplatesExpected = R"cpp(
1374a6d15d40SMatt Morehouse struct S {
1375a6d15d40SMatt Morehouse   safe_int m_i;
1376a6d15d40SMatt Morehouse };
1377a6d15d40SMatt Morehouse )cpp";
1378a6d15d40SMatt Morehouse 
1379a6d15d40SMatt Morehouse   std::string TemplatesInput = R"cpp(
1380a6d15d40SMatt Morehouse template<typename T>
1381a6d15d40SMatt Morehouse struct TemplStruct {
1382a6d15d40SMatt Morehouse   TemplStruct() {}
1383a6d15d40SMatt Morehouse   ~TemplStruct() {}
1384a6d15d40SMatt Morehouse 
1385a6d15d40SMatt Morehouse private:
1386a6d15d40SMatt Morehouse   T m_t;
1387a6d15d40SMatt Morehouse };
1388a6d15d40SMatt Morehouse 
1389a6d15d40SMatt Morehouse void instantiate()
1390a6d15d40SMatt Morehouse {
1391a6d15d40SMatt Morehouse   TemplStruct<int> ti;
1392a6d15d40SMatt Morehouse }
1393a6d15d40SMatt Morehouse )cpp";
1394a6d15d40SMatt Morehouse 
1395a6d15d40SMatt Morehouse   auto MatchedField = fieldDecl(hasType(asString("int"))).bind("theField");
1396a6d15d40SMatt Morehouse 
1397a6d15d40SMatt Morehouse   // Changes the 'int' in 'S', but not the 'T' in 'TemplStruct':
1398a6d15d40SMatt Morehouse   testRule(makeRule(traverse(TK_IgnoreUnlessSpelledInSource, MatchedField),
139988e62085SYitzhak Mandelbaum                     changeTo(cat("safe_int ", name("theField"), ";"))),
1400a6d15d40SMatt Morehouse            NonTemplatesInput + TemplatesInput,
1401a6d15d40SMatt Morehouse            NonTemplatesExpected + TemplatesInput);
1402a6d15d40SMatt Morehouse 
1403a6d15d40SMatt Morehouse   // In AsIs mode, template instantiations are modified, which is
1404a6d15d40SMatt Morehouse   // often not desired:
1405a6d15d40SMatt Morehouse 
1406a6d15d40SMatt Morehouse   std::string IncorrectTemplatesExpected = R"cpp(
1407a6d15d40SMatt Morehouse template<typename T>
1408a6d15d40SMatt Morehouse struct TemplStruct {
1409a6d15d40SMatt Morehouse   TemplStruct() {}
1410a6d15d40SMatt Morehouse   ~TemplStruct() {}
1411a6d15d40SMatt Morehouse 
1412a6d15d40SMatt Morehouse private:
1413a6d15d40SMatt Morehouse   safe_int m_t;
1414a6d15d40SMatt Morehouse };
1415a6d15d40SMatt Morehouse 
1416a6d15d40SMatt Morehouse void instantiate()
1417a6d15d40SMatt Morehouse {
1418a6d15d40SMatt Morehouse   TemplStruct<int> ti;
1419a6d15d40SMatt Morehouse }
1420a6d15d40SMatt Morehouse )cpp";
1421a6d15d40SMatt Morehouse 
1422a6d15d40SMatt Morehouse   // Changes the 'int' in 'S', and (incorrectly) the 'T' in 'TemplStruct':
1423a6d15d40SMatt Morehouse   testRule(makeRule(traverse(TK_AsIs, MatchedField),
142488e62085SYitzhak Mandelbaum                     changeTo(cat("safe_int ", name("theField"), ";"))),
1425a6d15d40SMatt Morehouse 
1426a6d15d40SMatt Morehouse            NonTemplatesInput + TemplatesInput,
1427a6d15d40SMatt Morehouse            NonTemplatesExpected + IncorrectTemplatesExpected);
1428a6d15d40SMatt Morehouse }
1429a6d15d40SMatt Morehouse 
14303f1ab737SYitzhak Mandelbaum // Transformation of macro source text when the change encompasses the entirety
14313f1ab737SYitzhak Mandelbaum // of the expanded text.
TEST_F(TransformerTest,SimpleMacro)14323f1ab737SYitzhak Mandelbaum TEST_F(TransformerTest, SimpleMacro) {
1433fdd98782SYitzhak Mandelbaum   std::string Input = R"cc(
14343f1ab737SYitzhak Mandelbaum #define ZERO 0
14353f1ab737SYitzhak Mandelbaum     int f(string s) { return ZERO; }
14363f1ab737SYitzhak Mandelbaum   )cc";
14373f1ab737SYitzhak Mandelbaum   std::string Expected = R"cc(
14383f1ab737SYitzhak Mandelbaum #define ZERO 0
14393f1ab737SYitzhak Mandelbaum     int f(string s) { return 999; }
14403f1ab737SYitzhak Mandelbaum   )cc";
14413f1ab737SYitzhak Mandelbaum 
14423f1ab737SYitzhak Mandelbaum   StringRef zero = "zero";
14433f1ab737SYitzhak Mandelbaum   RewriteRule R = makeRule(integerLiteral(equals(0)).bind(zero),
1444adcd0268SBenjamin Kramer                            changeTo(node(std::string(zero)), cat("999")));
14453f1ab737SYitzhak Mandelbaum   testRule(R, Input, Expected);
1446fdd98782SYitzhak Mandelbaum }
1447fdd98782SYitzhak Mandelbaum 
14483f1ab737SYitzhak Mandelbaum // Transformation of macro source text when the change encompasses the entirety
14493f1ab737SYitzhak Mandelbaum // of the expanded text, for the case of function-style macros.
TEST_F(TransformerTest,FunctionMacro)14503f1ab737SYitzhak Mandelbaum TEST_F(TransformerTest, FunctionMacro) {
14513f1ab737SYitzhak Mandelbaum   std::string Input = R"cc(
14523f1ab737SYitzhak Mandelbaum #define MACRO(str) strlen((str).c_str())
14533f1ab737SYitzhak Mandelbaum     int f(string s) { return MACRO(s); }
14543f1ab737SYitzhak Mandelbaum   )cc";
14553f1ab737SYitzhak Mandelbaum   std::string Expected = R"cc(
14563f1ab737SYitzhak Mandelbaum #define MACRO(str) strlen((str).c_str())
14573f1ab737SYitzhak Mandelbaum     int f(string s) { return REPLACED; }
14583f1ab737SYitzhak Mandelbaum   )cc";
14593f1ab737SYitzhak Mandelbaum 
14603f1ab737SYitzhak Mandelbaum   testRule(ruleStrlenSize(), Input, Expected);
14613f1ab737SYitzhak Mandelbaum }
14623f1ab737SYitzhak Mandelbaum 
14633f1ab737SYitzhak Mandelbaum // Tests that expressions in macro arguments can be rewritten.
TEST_F(TransformerTest,MacroArg)14643f1ab737SYitzhak Mandelbaum TEST_F(TransformerTest, MacroArg) {
14653f1ab737SYitzhak Mandelbaum   std::string Input = R"cc(
14663f1ab737SYitzhak Mandelbaum #define PLUS(e) e + 1
14673f1ab737SYitzhak Mandelbaum     int f(string s) { return PLUS(strlen(s.c_str())); }
14683f1ab737SYitzhak Mandelbaum   )cc";
14693f1ab737SYitzhak Mandelbaum   std::string Expected = R"cc(
14703f1ab737SYitzhak Mandelbaum #define PLUS(e) e + 1
14713f1ab737SYitzhak Mandelbaum     int f(string s) { return PLUS(REPLACED); }
14723f1ab737SYitzhak Mandelbaum   )cc";
14733f1ab737SYitzhak Mandelbaum 
14743f1ab737SYitzhak Mandelbaum   testRule(ruleStrlenSize(), Input, Expected);
14753f1ab737SYitzhak Mandelbaum }
14763f1ab737SYitzhak Mandelbaum 
14773f1ab737SYitzhak Mandelbaum // Tests that expressions in macro arguments can be rewritten, even when the
14783f1ab737SYitzhak Mandelbaum // macro call occurs inside another macro's definition.
TEST_F(TransformerTest,MacroArgInMacroDef)14793f1ab737SYitzhak Mandelbaum TEST_F(TransformerTest, MacroArgInMacroDef) {
1480fdd98782SYitzhak Mandelbaum   std::string Input = R"cc(
1481fdd98782SYitzhak Mandelbaum #define NESTED(e) e
1482fdd98782SYitzhak Mandelbaum #define MACRO(str) NESTED(strlen((str).c_str()))
14833f1ab737SYitzhak Mandelbaum     int f(string s) { return MACRO(s); }
14843f1ab737SYitzhak Mandelbaum   )cc";
14853f1ab737SYitzhak Mandelbaum   std::string Expected = R"cc(
14863f1ab737SYitzhak Mandelbaum #define NESTED(e) e
14873f1ab737SYitzhak Mandelbaum #define MACRO(str) NESTED(strlen((str).c_str()))
14883f1ab737SYitzhak Mandelbaum     int f(string s) { return REPLACED; }
14893f1ab737SYitzhak Mandelbaum   )cc";
14903f1ab737SYitzhak Mandelbaum 
14913f1ab737SYitzhak Mandelbaum   testRule(ruleStrlenSize(), Input, Expected);
14923f1ab737SYitzhak Mandelbaum }
14933f1ab737SYitzhak Mandelbaum 
14943f1ab737SYitzhak Mandelbaum // Tests the corner case of the identity macro, specifically that it is
14953f1ab737SYitzhak Mandelbaum // discarded in the rewrite rather than preserved (like PLUS is preserved in the
14963f1ab737SYitzhak Mandelbaum // previous test).  This behavior is of dubious value (and marked with a FIXME
14973f1ab737SYitzhak Mandelbaum // in the code), but we test it to verify (and demonstrate) how this case is
14983f1ab737SYitzhak Mandelbaum // handled.
TEST_F(TransformerTest,IdentityMacro)14993f1ab737SYitzhak Mandelbaum TEST_F(TransformerTest, IdentityMacro) {
15003f1ab737SYitzhak Mandelbaum   std::string Input = R"cc(
15013f1ab737SYitzhak Mandelbaum #define ID(e) e
15023f1ab737SYitzhak Mandelbaum     int f(string s) { return ID(strlen(s.c_str())); }
15033f1ab737SYitzhak Mandelbaum   )cc";
15043f1ab737SYitzhak Mandelbaum   std::string Expected = R"cc(
15053f1ab737SYitzhak Mandelbaum #define ID(e) e
15063f1ab737SYitzhak Mandelbaum     int f(string s) { return REPLACED; }
15073f1ab737SYitzhak Mandelbaum   )cc";
15083f1ab737SYitzhak Mandelbaum 
15093f1ab737SYitzhak Mandelbaum   testRule(ruleStrlenSize(), Input, Expected);
15103f1ab737SYitzhak Mandelbaum }
15113f1ab737SYitzhak Mandelbaum 
1512db24ef50SYitzhak Mandelbaum // Tests that two changes in a single macro expansion do not lead to conflicts
1513db24ef50SYitzhak Mandelbaum // in applying the changes.
TEST_F(TransformerTest,TwoChangesInOneMacroExpansion)1514db24ef50SYitzhak Mandelbaum TEST_F(TransformerTest, TwoChangesInOneMacroExpansion) {
1515db24ef50SYitzhak Mandelbaum   std::string Input = R"cc(
1516db24ef50SYitzhak Mandelbaum #define PLUS(a,b) (a) + (b)
1517db24ef50SYitzhak Mandelbaum     int f() { return PLUS(3, 4); }
1518db24ef50SYitzhak Mandelbaum   )cc";
1519db24ef50SYitzhak Mandelbaum   std::string Expected = R"cc(
1520db24ef50SYitzhak Mandelbaum #define PLUS(a,b) (a) + (b)
1521db24ef50SYitzhak Mandelbaum     int f() { return PLUS(LIT, LIT); }
1522db24ef50SYitzhak Mandelbaum   )cc";
1523db24ef50SYitzhak Mandelbaum 
15249f97480cSYitzhak Mandelbaum   testRule(makeRule(integerLiteral(), changeTo(cat("LIT"))), Input, Expected);
1525db24ef50SYitzhak Mandelbaum }
1526db24ef50SYitzhak Mandelbaum 
1527db24ef50SYitzhak Mandelbaum // Tests case where the rule's match spans both source from the macro and its
1528db24ef50SYitzhak Mandelbaum // arg, with the begin location (the "anchor") being the arg.
TEST_F(TransformerTest,MatchSpansMacroTextButChangeDoesNot)1529db24ef50SYitzhak Mandelbaum TEST_F(TransformerTest, MatchSpansMacroTextButChangeDoesNot) {
1530db24ef50SYitzhak Mandelbaum   std::string Input = R"cc(
1531db24ef50SYitzhak Mandelbaum #define PLUS_ONE(a) a + 1
1532db24ef50SYitzhak Mandelbaum     int f() { return PLUS_ONE(3); }
1533db24ef50SYitzhak Mandelbaum   )cc";
1534db24ef50SYitzhak Mandelbaum   std::string Expected = R"cc(
1535db24ef50SYitzhak Mandelbaum #define PLUS_ONE(a) a + 1
1536db24ef50SYitzhak Mandelbaum     int f() { return PLUS_ONE(LIT); }
1537db24ef50SYitzhak Mandelbaum   )cc";
1538db24ef50SYitzhak Mandelbaum 
1539db24ef50SYitzhak Mandelbaum   StringRef E = "expr";
1540db24ef50SYitzhak Mandelbaum   testRule(makeRule(binaryOperator(hasLHS(expr().bind(E))),
1541adcd0268SBenjamin Kramer                     changeTo(node(std::string(E)), cat("LIT"))),
1542db24ef50SYitzhak Mandelbaum            Input, Expected);
1543db24ef50SYitzhak Mandelbaum }
1544db24ef50SYitzhak Mandelbaum 
1545db24ef50SYitzhak Mandelbaum // Tests case where the rule's match spans both source from the macro and its
1546db24ef50SYitzhak Mandelbaum // arg, with the begin location (the "anchor") being inside the macro.
TEST_F(TransformerTest,MatchSpansMacroTextButChangeDoesNotAnchoredInMacro)1547db24ef50SYitzhak Mandelbaum TEST_F(TransformerTest, MatchSpansMacroTextButChangeDoesNotAnchoredInMacro) {
1548db24ef50SYitzhak Mandelbaum   std::string Input = R"cc(
1549db24ef50SYitzhak Mandelbaum #define PLUS_ONE(a) 1 + a
1550db24ef50SYitzhak Mandelbaum     int f() { return PLUS_ONE(3); }
1551db24ef50SYitzhak Mandelbaum   )cc";
1552db24ef50SYitzhak Mandelbaum   std::string Expected = R"cc(
1553db24ef50SYitzhak Mandelbaum #define PLUS_ONE(a) 1 + a
1554db24ef50SYitzhak Mandelbaum     int f() { return PLUS_ONE(LIT); }
1555db24ef50SYitzhak Mandelbaum   )cc";
1556db24ef50SYitzhak Mandelbaum 
1557db24ef50SYitzhak Mandelbaum   StringRef E = "expr";
1558db24ef50SYitzhak Mandelbaum   testRule(makeRule(binaryOperator(hasRHS(expr().bind(E))),
1559adcd0268SBenjamin Kramer                     changeTo(node(std::string(E)), cat("LIT"))),
1560db24ef50SYitzhak Mandelbaum            Input, Expected);
1561db24ef50SYitzhak Mandelbaum }
1562db24ef50SYitzhak Mandelbaum 
15633f1ab737SYitzhak Mandelbaum // No rewrite is applied when the changed text does not encompass the entirety
15643f1ab737SYitzhak Mandelbaum // of the expanded text. That is, the edit would have to be applied to the
15653f1ab737SYitzhak Mandelbaum // macro's definition to succeed and editing the expansion point would not
15663f1ab737SYitzhak Mandelbaum // suffice.
TEST_F(TransformerTest,NoPartialRewriteOMacroExpansion)15673f1ab737SYitzhak Mandelbaum TEST_F(TransformerTest, NoPartialRewriteOMacroExpansion) {
15683f1ab737SYitzhak Mandelbaum   std::string Input = R"cc(
15693f1ab737SYitzhak Mandelbaum #define ZERO_PLUS 0 + 3
15703f1ab737SYitzhak Mandelbaum     int f(string s) { return ZERO_PLUS; })cc";
15713f1ab737SYitzhak Mandelbaum 
15723f1ab737SYitzhak Mandelbaum   StringRef zero = "zero";
15733f1ab737SYitzhak Mandelbaum   RewriteRule R = makeRule(integerLiteral(equals(0)).bind(zero),
1574adcd0268SBenjamin Kramer                            changeTo(node(std::string(zero)), cat("0")));
15753f1ab737SYitzhak Mandelbaum   testRule(R, Input, Input);
15763f1ab737SYitzhak Mandelbaum }
15773f1ab737SYitzhak Mandelbaum 
15783f1ab737SYitzhak Mandelbaum // This test handles the corner case where a macro expands within another macro
15793f1ab737SYitzhak Mandelbaum // to matching code, but that code is an argument to the nested macro call.  A
15803f1ab737SYitzhak Mandelbaum // simple check of isMacroArgExpansion() vs. isMacroBodyExpansion() will get
15813f1ab737SYitzhak Mandelbaum // this wrong, and transform the code.
TEST_F(TransformerTest,NoPartialRewriteOfMacroExpansionForMacroArgs)15823f1ab737SYitzhak Mandelbaum TEST_F(TransformerTest, NoPartialRewriteOfMacroExpansionForMacroArgs) {
15833f1ab737SYitzhak Mandelbaum   std::string Input = R"cc(
15843f1ab737SYitzhak Mandelbaum #define NESTED(e) e
15853f1ab737SYitzhak Mandelbaum #define MACRO(str) 1 + NESTED(strlen((str).c_str()))
15863f1ab737SYitzhak Mandelbaum     int f(string s) { return MACRO(s); }
15873f1ab737SYitzhak Mandelbaum   )cc";
15883f1ab737SYitzhak Mandelbaum 
1589fdd98782SYitzhak Mandelbaum   testRule(ruleStrlenSize(), Input, Input);
1590fdd98782SYitzhak Mandelbaum }
159142b957aaSYitzhak Mandelbaum 
159242b957aaSYitzhak Mandelbaum #if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST
159342b957aaSYitzhak Mandelbaum // Verifies that `Type` and `QualType` are not allowed as top-level matchers in
159442b957aaSYitzhak Mandelbaum // rules.
TEST(TransformerDeathTest,OrderedRuleTypes)159542b957aaSYitzhak Mandelbaum TEST(TransformerDeathTest, OrderedRuleTypes) {
15969f97480cSYitzhak Mandelbaum   RewriteRule QualTypeRule = makeRule(qualType(), changeTo(cat("Q")));
15978bb47cd8SYitzhak Mandelbaum   EXPECT_DEATH(transformer::detail::buildMatchers(QualTypeRule),
159842b957aaSYitzhak Mandelbaum                "Matcher must be.*node matcher");
159942b957aaSYitzhak Mandelbaum 
16009f97480cSYitzhak Mandelbaum   RewriteRule TypeRule = makeRule(arrayType(), changeTo(cat("T")));
16018bb47cd8SYitzhak Mandelbaum   EXPECT_DEATH(transformer::detail::buildMatchers(TypeRule),
160242b957aaSYitzhak Mandelbaum                "Matcher must be.*node matcher");
160342b957aaSYitzhak Mandelbaum }
160442b957aaSYitzhak Mandelbaum #endif
1605ff2743bfSYitzhak Mandelbaum 
1606ff2743bfSYitzhak Mandelbaum // Edits are able to span multiple files; in this case, a header and an
1607ff2743bfSYitzhak Mandelbaum // implementation file.
TEST_F(TransformerTest,MultipleFiles)1608ff2743bfSYitzhak Mandelbaum TEST_F(TransformerTest, MultipleFiles) {
1609ff2743bfSYitzhak Mandelbaum   std::string Header = R"cc(void RemoveThisFunction();)cc";
1610ff2743bfSYitzhak Mandelbaum   std::string Source = R"cc(#include "input.h"
1611ff2743bfSYitzhak Mandelbaum                             void RemoveThisFunction();)cc";
1612ff2743bfSYitzhak Mandelbaum   Transformer T(
1613ff2743bfSYitzhak Mandelbaum       makeRule(functionDecl(hasName("RemoveThisFunction")), changeTo(cat(""))),
1614ff2743bfSYitzhak Mandelbaum       consumer());
1615ff2743bfSYitzhak Mandelbaum   T.registerMatchers(&MatchFinder);
1616ff2743bfSYitzhak Mandelbaum   auto Factory = newFrontendActionFactory(&MatchFinder);
1617ff2743bfSYitzhak Mandelbaum   EXPECT_TRUE(runToolOnCodeWithArgs(
1618ff2743bfSYitzhak Mandelbaum       Factory->create(), Source, std::vector<std::string>(), "input.cc",
1619ff2743bfSYitzhak Mandelbaum       "clang-tool", std::make_shared<PCHContainerOperations>(),
1620ff2743bfSYitzhak Mandelbaum       {{"input.h", Header}}));
1621ff2743bfSYitzhak Mandelbaum 
1622aba43035SDmitri Gribenko   llvm::sort(Changes, [](const AtomicChange &L, const AtomicChange &R) {
1623ff2743bfSYitzhak Mandelbaum     return L.getFilePath() < R.getFilePath();
1624ff2743bfSYitzhak Mandelbaum   });
1625ff2743bfSYitzhak Mandelbaum 
1626*5523fefbSJan Svoboda   ASSERT_EQ(llvm::sys::path::convert_to_slash(Changes[0].getFilePath()),
1627*5523fefbSJan Svoboda             "./input.h");
1628ff2743bfSYitzhak Mandelbaum   EXPECT_THAT(Changes[0].getInsertedHeaders(), IsEmpty());
1629ff2743bfSYitzhak Mandelbaum   EXPECT_THAT(Changes[0].getRemovedHeaders(), IsEmpty());
1630ff2743bfSYitzhak Mandelbaum   llvm::Expected<std::string> UpdatedCode =
1631ff2743bfSYitzhak Mandelbaum       clang::tooling::applyAllReplacements(Header,
1632ff2743bfSYitzhak Mandelbaum                                            Changes[0].getReplacements());
1633ff2743bfSYitzhak Mandelbaum   ASSERT_TRUE(static_cast<bool>(UpdatedCode))
1634ff2743bfSYitzhak Mandelbaum       << "Could not update code: " << llvm::toString(UpdatedCode.takeError());
163588e62085SYitzhak Mandelbaum   EXPECT_EQ(format(*UpdatedCode), "");
1636ff2743bfSYitzhak Mandelbaum 
1637ff2743bfSYitzhak Mandelbaum   ASSERT_EQ(Changes[1].getFilePath(), "input.cc");
1638ff2743bfSYitzhak Mandelbaum   EXPECT_THAT(Changes[1].getInsertedHeaders(), IsEmpty());
1639ff2743bfSYitzhak Mandelbaum   EXPECT_THAT(Changes[1].getRemovedHeaders(), IsEmpty());
1640ff2743bfSYitzhak Mandelbaum   UpdatedCode = clang::tooling::applyAllReplacements(
1641ff2743bfSYitzhak Mandelbaum       Source, Changes[1].getReplacements());
1642ff2743bfSYitzhak Mandelbaum   ASSERT_TRUE(static_cast<bool>(UpdatedCode))
1643ff2743bfSYitzhak Mandelbaum       << "Could not update code: " << llvm::toString(UpdatedCode.takeError());
164488e62085SYitzhak Mandelbaum   EXPECT_EQ(format(*UpdatedCode), format("#include \"input.h\"\n"));
1645ff2743bfSYitzhak Mandelbaum }
1646d8c1f43dSYitzhak Mandelbaum 
TEST_F(TransformerTest,AddIncludeMultipleFiles)1647d8c1f43dSYitzhak Mandelbaum TEST_F(TransformerTest, AddIncludeMultipleFiles) {
1648d8c1f43dSYitzhak Mandelbaum   std::string Header = R"cc(void RemoveThisFunction();)cc";
1649d8c1f43dSYitzhak Mandelbaum   std::string Source = R"cc(#include "input.h"
1650d8c1f43dSYitzhak Mandelbaum                             void Foo() {RemoveThisFunction();})cc";
1651d8c1f43dSYitzhak Mandelbaum   Transformer T(
1652d8c1f43dSYitzhak Mandelbaum       makeRule(callExpr(callee(
1653d8c1f43dSYitzhak Mandelbaum                    functionDecl(hasName("RemoveThisFunction")).bind("fun"))),
1654d8c1f43dSYitzhak Mandelbaum                addInclude(node("fun"), "header.h")),
1655d8c1f43dSYitzhak Mandelbaum       consumer());
1656d8c1f43dSYitzhak Mandelbaum   T.registerMatchers(&MatchFinder);
1657d8c1f43dSYitzhak Mandelbaum   auto Factory = newFrontendActionFactory(&MatchFinder);
1658d8c1f43dSYitzhak Mandelbaum   EXPECT_TRUE(runToolOnCodeWithArgs(
1659d8c1f43dSYitzhak Mandelbaum       Factory->create(), Source, std::vector<std::string>(), "input.cc",
1660d8c1f43dSYitzhak Mandelbaum       "clang-tool", std::make_shared<PCHContainerOperations>(),
1661d8c1f43dSYitzhak Mandelbaum       {{"input.h", Header}}));
1662d8c1f43dSYitzhak Mandelbaum 
1663d8c1f43dSYitzhak Mandelbaum   ASSERT_EQ(Changes.size(), 1U);
1664*5523fefbSJan Svoboda   ASSERT_EQ(llvm::sys::path::convert_to_slash(Changes[0].getFilePath()),
1665*5523fefbSJan Svoboda             "./input.h");
1666d8c1f43dSYitzhak Mandelbaum   EXPECT_THAT(Changes[0].getInsertedHeaders(), ElementsAre("header.h"));
1667d8c1f43dSYitzhak Mandelbaum   EXPECT_THAT(Changes[0].getRemovedHeaders(), IsEmpty());
1668d8c1f43dSYitzhak Mandelbaum   llvm::Expected<std::string> UpdatedCode =
1669d8c1f43dSYitzhak Mandelbaum       clang::tooling::applyAllReplacements(Header,
1670d8c1f43dSYitzhak Mandelbaum                                            Changes[0].getReplacements());
1671d8c1f43dSYitzhak Mandelbaum   ASSERT_TRUE(static_cast<bool>(UpdatedCode))
1672d8c1f43dSYitzhak Mandelbaum       << "Could not update code: " << llvm::toString(UpdatedCode.takeError());
1673d8c1f43dSYitzhak Mandelbaum   EXPECT_EQ(format(*UpdatedCode), format(Header));
1674d8c1f43dSYitzhak Mandelbaum }
1675d1e3235fSEric Li 
1676d1e3235fSEric Li // A single change set can span multiple files.
TEST_F(TransformerTest,MultiFileEdit)1677d1e3235fSEric Li TEST_F(TransformerTest, MultiFileEdit) {
1678d1e3235fSEric Li   // NB: The fixture is unused for this test, but kept for the test suite name.
1679d1e3235fSEric Li   std::string Header = R"cc(void Func(int id);)cc";
1680d1e3235fSEric Li   std::string Source = R"cc(#include "input.h"
1681d1e3235fSEric Li                             void Caller() {
1682d1e3235fSEric Li                               int id = 0;
1683d1e3235fSEric Li                               Func(id);
1684d1e3235fSEric Li                             })cc";
1685d1e3235fSEric Li   int ErrorCount = 0;
1686d1e3235fSEric Li   std::vector<AtomicChanges> ChangeSets;
1687d1e3235fSEric Li   clang::ast_matchers::MatchFinder MatchFinder;
1688d1e3235fSEric Li   Transformer T(
1689d1e3235fSEric Li       makeRule(callExpr(callee(functionDecl(hasName("Func"))),
1690d1e3235fSEric Li                         forEachArgumentWithParam(expr().bind("arg"),
1691d1e3235fSEric Li                                                  parmVarDecl().bind("param"))),
16929edeceaeSEric Li                {changeTo(node("arg"), cat("ARG")),
16939edeceaeSEric Li                 changeTo(node("param"), cat("PARAM"))}),
1694d1e3235fSEric Li       [&](Expected<MutableArrayRef<AtomicChange>> Changes) {
1695d1e3235fSEric Li         if (Changes)
1696d1e3235fSEric Li           ChangeSets.push_back(AtomicChanges(Changes->begin(), Changes->end()));
1697d1e3235fSEric Li         else
1698d1e3235fSEric Li           ++ErrorCount;
1699d1e3235fSEric Li       });
1700d1e3235fSEric Li   T.registerMatchers(&MatchFinder);
1701d1e3235fSEric Li   auto Factory = newFrontendActionFactory(&MatchFinder);
1702d1e3235fSEric Li   EXPECT_TRUE(runToolOnCodeWithArgs(
1703d1e3235fSEric Li       Factory->create(), Source, std::vector<std::string>(), "input.cc",
1704d1e3235fSEric Li       "clang-tool", std::make_shared<PCHContainerOperations>(),
1705d1e3235fSEric Li       {{"input.h", Header}}));
1706d1e3235fSEric Li 
1707*5523fefbSJan Svoboda   auto GetPathWithSlashes = [](const AtomicChange &C) {
1708*5523fefbSJan Svoboda     return llvm::sys::path::convert_to_slash(C.getFilePath());
1709*5523fefbSJan Svoboda   };
1710*5523fefbSJan Svoboda 
1711d1e3235fSEric Li   EXPECT_EQ(ErrorCount, 0);
1712*5523fefbSJan Svoboda   EXPECT_THAT(ChangeSets, UnorderedElementsAre(UnorderedElementsAre(
1713*5523fefbSJan Svoboda                               ResultOf(GetPathWithSlashes, "input.cc"),
1714*5523fefbSJan Svoboda                               ResultOf(GetPathWithSlashes, "./input.h"))));
1715d1e3235fSEric Li }
1716d1e3235fSEric Li 
TEST_F(TransformerTest,GeneratesMetadata)17179edeceaeSEric Li TEST_F(TransformerTest, GeneratesMetadata) {
17189edeceaeSEric Li   std::string Input = R"cc(int target = 0;)cc";
17199edeceaeSEric Li   std::string Expected = R"cc(REPLACE)cc";
17209edeceaeSEric Li   RewriteRuleWith<std::string> Rule = makeRule(
17219edeceaeSEric Li       varDecl(hasName("target")), changeTo(cat("REPLACE")), cat("METADATA"));
17229edeceaeSEric Li   testRule(std::move(Rule), Input, Expected);
17239edeceaeSEric Li   EXPECT_EQ(ErrorCount, 0);
17249edeceaeSEric Li   EXPECT_THAT(StringMetadata, UnorderedElementsAre("METADATA"));
17259edeceaeSEric Li }
17269edeceaeSEric Li 
TEST_F(TransformerTest,GeneratesMetadataWithNoEdits)17279edeceaeSEric Li TEST_F(TransformerTest, GeneratesMetadataWithNoEdits) {
17289edeceaeSEric Li   std::string Input = R"cc(int target = 0;)cc";
17299edeceaeSEric Li   RewriteRuleWith<std::string> Rule = makeRule(
17309edeceaeSEric Li       varDecl(hasName("target")).bind("var"), noEdits(), cat("METADATA"));
17319edeceaeSEric Li   testRule(std::move(Rule), Input, Input);
17329edeceaeSEric Li   EXPECT_EQ(ErrorCount, 0);
17339edeceaeSEric Li   EXPECT_THAT(StringMetadata, UnorderedElementsAre("METADATA"));
17349edeceaeSEric Li }
17359edeceaeSEric Li 
TEST_F(TransformerTest,PropagateMetadataErrors)17369edeceaeSEric Li TEST_F(TransformerTest, PropagateMetadataErrors) {
17379edeceaeSEric Li   class AlwaysFail : public transformer::MatchComputation<std::string> {
17389edeceaeSEric Li     llvm::Error eval(const ast_matchers::MatchFinder::MatchResult &,
17399edeceaeSEric Li                      std::string *) const override {
17409edeceaeSEric Li       return llvm::createStringError(llvm::errc::invalid_argument, "ERROR");
17419edeceaeSEric Li     }
17429edeceaeSEric Li     std::string toString() const override { return "AlwaysFail"; }
17439edeceaeSEric Li   };
17449edeceaeSEric Li   std::string Input = R"cc(int target = 0;)cc";
17459edeceaeSEric Li   RewriteRuleWith<std::string> Rule = makeRule<std::string>(
17469edeceaeSEric Li       varDecl(hasName("target")).bind("var"), changeTo(cat("REPLACE")),
17479edeceaeSEric Li       std::make_shared<AlwaysFail>());
17489edeceaeSEric Li   testRuleFailure(std::move(Rule), Input);
17499edeceaeSEric Li   EXPECT_EQ(ErrorCount, 1);
17509edeceaeSEric Li }
17519edeceaeSEric Li 
1752fdd98782SYitzhak Mandelbaum } // namespace
1753