xref: /llvm-project/clang/unittests/Tooling/TransformerTest.cpp (revision 4cadb66b490e3323f79a89120c3442456e4c24fa)
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"
15aecc59c5SYitzhak Mandelbaum #include "llvm/Support/Errc.h"
16aecc59c5SYitzhak Mandelbaum #include "llvm/Support/Error.h"
17fdd98782SYitzhak Mandelbaum #include "gmock/gmock.h"
18fdd98782SYitzhak Mandelbaum #include "gtest/gtest.h"
19fdd98782SYitzhak Mandelbaum 
20fa1552e8SYitzhak Mandelbaum using namespace clang;
21fa1552e8SYitzhak Mandelbaum using namespace tooling;
22fa1552e8SYitzhak Mandelbaum using namespace ast_matchers;
23fdd98782SYitzhak Mandelbaum namespace {
24d8c1f43dSYitzhak Mandelbaum using ::testing::ElementsAre;
25aecc59c5SYitzhak Mandelbaum using ::testing::IsEmpty;
266c683aa8SYitzhak Mandelbaum using transformer::cat;
276c683aa8SYitzhak Mandelbaum using transformer::changeTo;
28d4f39031SYitzhak Mandelbaum using transformer::rewriteDescendants;
298bb47cd8SYitzhak Mandelbaum using transformer::RewriteRule;
30aecc59c5SYitzhak Mandelbaum 
31fdd98782SYitzhak Mandelbaum constexpr char KHeaderContents[] = R"cc(
32fdd98782SYitzhak Mandelbaum   struct string {
33fdd98782SYitzhak Mandelbaum     string(const char*);
34fdd98782SYitzhak Mandelbaum     char* c_str();
35fdd98782SYitzhak Mandelbaum     int size();
36fdd98782SYitzhak Mandelbaum   };
37fdd98782SYitzhak Mandelbaum   int strlen(const char*);
38fdd98782SYitzhak Mandelbaum 
39fdd98782SYitzhak Mandelbaum   namespace proto {
40fdd98782SYitzhak Mandelbaum   struct PCFProto {
41fdd98782SYitzhak Mandelbaum     int foo();
42fdd98782SYitzhak Mandelbaum   };
43fdd98782SYitzhak Mandelbaum   struct ProtoCommandLineFlag : PCFProto {
44fdd98782SYitzhak Mandelbaum     PCFProto& GetProto();
45fdd98782SYitzhak Mandelbaum   };
46fdd98782SYitzhak Mandelbaum   }  // namespace proto
47fa1552e8SYitzhak Mandelbaum   class Logger {};
48fa1552e8SYitzhak Mandelbaum   void operator<<(Logger& l, string msg);
49fa1552e8SYitzhak Mandelbaum   Logger& log(int level);
50fdd98782SYitzhak Mandelbaum )cc";
51fdd98782SYitzhak Mandelbaum 
52fdd98782SYitzhak Mandelbaum static ast_matchers::internal::Matcher<clang::QualType>
53fdd98782SYitzhak Mandelbaum isOrPointsTo(const clang::ast_matchers::DeclarationMatcher &TypeMatcher) {
54fdd98782SYitzhak Mandelbaum   return anyOf(hasDeclaration(TypeMatcher), pointsTo(TypeMatcher));
55fdd98782SYitzhak Mandelbaum }
56fdd98782SYitzhak Mandelbaum 
57fdd98782SYitzhak Mandelbaum static std::string format(StringRef Code) {
58fdd98782SYitzhak Mandelbaum   const std::vector<Range> Ranges(1, Range(0, Code.size()));
59fdd98782SYitzhak Mandelbaum   auto Style = format::getLLVMStyle();
60fdd98782SYitzhak Mandelbaum   const auto Replacements = format::reformat(Style, Code, Ranges);
61fdd98782SYitzhak Mandelbaum   auto Formatted = applyAllReplacements(Code, Replacements);
62fdd98782SYitzhak Mandelbaum   if (!Formatted) {
63fdd98782SYitzhak Mandelbaum     ADD_FAILURE() << "Could not format code: "
64fdd98782SYitzhak Mandelbaum                   << llvm::toString(Formatted.takeError());
65fdd98782SYitzhak Mandelbaum     return std::string();
66fdd98782SYitzhak Mandelbaum   }
67fdd98782SYitzhak Mandelbaum   return *Formatted;
68fdd98782SYitzhak Mandelbaum }
69fdd98782SYitzhak Mandelbaum 
70fdd98782SYitzhak Mandelbaum static void compareSnippets(StringRef Expected,
71fdd98782SYitzhak Mandelbaum                      const llvm::Optional<std::string> &MaybeActual) {
72fdd98782SYitzhak Mandelbaum   ASSERT_TRUE(MaybeActual) << "Rewrite failed. Expecting: " << Expected;
73fdd98782SYitzhak Mandelbaum   auto Actual = *MaybeActual;
74fdd98782SYitzhak Mandelbaum   std::string HL = "#include \"header.h\"\n";
75fdd98782SYitzhak Mandelbaum   auto I = Actual.find(HL);
76fdd98782SYitzhak Mandelbaum   if (I != std::string::npos)
77fdd98782SYitzhak Mandelbaum     Actual.erase(I, HL.size());
78fdd98782SYitzhak Mandelbaum   EXPECT_EQ(format(Expected), format(Actual));
79fdd98782SYitzhak Mandelbaum }
80fdd98782SYitzhak Mandelbaum 
81fdd98782SYitzhak Mandelbaum // FIXME: consider separating this class into its own file(s).
82fdd98782SYitzhak Mandelbaum class ClangRefactoringTestBase : public testing::Test {
83fdd98782SYitzhak Mandelbaum protected:
84fdd98782SYitzhak Mandelbaum   void appendToHeader(StringRef S) { FileContents[0].second += S; }
85fdd98782SYitzhak Mandelbaum 
86fdd98782SYitzhak Mandelbaum   void addFile(StringRef Filename, StringRef Content) {
87757bdc64SBenjamin Kramer     FileContents.emplace_back(std::string(Filename), std::string(Content));
88fdd98782SYitzhak Mandelbaum   }
89fdd98782SYitzhak Mandelbaum 
90fdd98782SYitzhak Mandelbaum   llvm::Optional<std::string> rewrite(StringRef Input) {
91fdd98782SYitzhak Mandelbaum     std::string Code = ("#include \"header.h\"\n" + Input).str();
92fdd98782SYitzhak Mandelbaum     auto Factory = newFrontendActionFactory(&MatchFinder);
93fdd98782SYitzhak Mandelbaum     if (!runToolOnCodeWithArgs(
94fdd98782SYitzhak Mandelbaum             Factory->create(), Code, std::vector<std::string>(), "input.cc",
95fdd98782SYitzhak Mandelbaum             "clang-tool", std::make_shared<PCHContainerOperations>(),
96fdd98782SYitzhak Mandelbaum             FileContents)) {
97aecc59c5SYitzhak Mandelbaum       llvm::errs() << "Running tool failed.\n";
98fdd98782SYitzhak Mandelbaum       return None;
99fdd98782SYitzhak Mandelbaum     }
100aecc59c5SYitzhak Mandelbaum     if (ErrorCount != 0) {
101aecc59c5SYitzhak Mandelbaum       llvm::errs() << "Generating changes failed.\n";
102aecc59c5SYitzhak Mandelbaum       return None;
103aecc59c5SYitzhak Mandelbaum     }
104aecc59c5SYitzhak Mandelbaum     auto ChangedCode =
105fdd98782SYitzhak Mandelbaum         applyAtomicChanges("input.cc", Code, Changes, ApplyChangesSpec());
106aecc59c5SYitzhak Mandelbaum     if (!ChangedCode) {
107aecc59c5SYitzhak Mandelbaum       llvm::errs() << "Applying changes failed: "
108aecc59c5SYitzhak Mandelbaum                    << llvm::toString(ChangedCode.takeError()) << "\n";
109fdd98782SYitzhak Mandelbaum       return None;
110fdd98782SYitzhak Mandelbaum     }
111aecc59c5SYitzhak Mandelbaum     return *ChangedCode;
112aecc59c5SYitzhak Mandelbaum   }
113aecc59c5SYitzhak Mandelbaum 
114aecc59c5SYitzhak Mandelbaum   Transformer::ChangeConsumer consumer() {
115aecc59c5SYitzhak Mandelbaum     return [this](Expected<AtomicChange> C) {
116aecc59c5SYitzhak Mandelbaum       if (C) {
117aecc59c5SYitzhak Mandelbaum         Changes.push_back(std::move(*C));
118aecc59c5SYitzhak Mandelbaum       } else {
119c332a984SYitzhak Mandelbaum         // FIXME: stash this error rather then printing.
120c332a984SYitzhak Mandelbaum         llvm::errs() << "Error generating changes: "
121c332a984SYitzhak Mandelbaum                      << llvm::toString(C.takeError()) << "\n";
122aecc59c5SYitzhak Mandelbaum         ++ErrorCount;
123aecc59c5SYitzhak Mandelbaum       }
124aecc59c5SYitzhak Mandelbaum     };
125fdd98782SYitzhak Mandelbaum   }
126fdd98782SYitzhak Mandelbaum 
1278369a9beSYitzhak Mandelbaum   template <typename R>
1288369a9beSYitzhak Mandelbaum   void testRule(R Rule, StringRef Input, StringRef Expected) {
12996ed6793SFangrui Song     Transformers.push_back(
13096ed6793SFangrui Song         std::make_unique<Transformer>(std::move(Rule), consumer()));
13196ed6793SFangrui Song     Transformers.back()->registerMatchers(&MatchFinder);
132fdd98782SYitzhak Mandelbaum     compareSnippets(Expected, rewrite(Input));
133fdd98782SYitzhak Mandelbaum   }
134fdd98782SYitzhak Mandelbaum 
135246b428fSStephen Kelly   template <typename R> void testRuleFailure(R Rule, StringRef Input) {
136246b428fSStephen Kelly     Transformers.push_back(
137246b428fSStephen Kelly         std::make_unique<Transformer>(std::move(Rule), consumer()));
138246b428fSStephen Kelly     Transformers.back()->registerMatchers(&MatchFinder);
139246b428fSStephen Kelly     ASSERT_FALSE(rewrite(Input)) << "Expected failure to rewrite code";
140246b428fSStephen Kelly   }
141246b428fSStephen Kelly 
14296ed6793SFangrui Song   // Transformers are referenced by MatchFinder.
14396ed6793SFangrui Song   std::vector<std::unique_ptr<Transformer>> Transformers;
144fdd98782SYitzhak Mandelbaum   clang::ast_matchers::MatchFinder MatchFinder;
145aecc59c5SYitzhak Mandelbaum   // Records whether any errors occurred in individual changes.
146aecc59c5SYitzhak Mandelbaum   int ErrorCount = 0;
147fdd98782SYitzhak Mandelbaum   AtomicChanges Changes;
148fdd98782SYitzhak Mandelbaum 
149fdd98782SYitzhak Mandelbaum private:
150fdd98782SYitzhak Mandelbaum   FileContentMappings FileContents = {{"header.h", ""}};
151fdd98782SYitzhak Mandelbaum };
152fdd98782SYitzhak Mandelbaum 
153fdd98782SYitzhak Mandelbaum class TransformerTest : public ClangRefactoringTestBase {
154fdd98782SYitzhak Mandelbaum protected:
155fdd98782SYitzhak Mandelbaum   TransformerTest() { appendToHeader(KHeaderContents); }
156fdd98782SYitzhak Mandelbaum };
157fdd98782SYitzhak Mandelbaum 
1583f1ab737SYitzhak Mandelbaum // Given string s, change strlen($s.c_str()) to REPLACED.
159fdd98782SYitzhak Mandelbaum static RewriteRule ruleStrlenSize() {
160fdd98782SYitzhak Mandelbaum   StringRef StringExpr = "strexpr";
161fdd98782SYitzhak Mandelbaum   auto StringType = namedDecl(hasAnyName("::basic_string", "::string"));
162fa1552e8SYitzhak Mandelbaum   auto R = makeRule(
163fa1552e8SYitzhak Mandelbaum       callExpr(callee(functionDecl(hasName("strlen"))),
164fdd98782SYitzhak Mandelbaum                hasArgument(0, cxxMemberCallExpr(
165fdd98782SYitzhak Mandelbaum                                   on(expr(hasType(isOrPointsTo(StringType)))
166fdd98782SYitzhak Mandelbaum                                          .bind(StringExpr)),
167fa1552e8SYitzhak Mandelbaum                                   callee(cxxMethodDecl(hasName("c_str")))))),
1689f97480cSYitzhak Mandelbaum       changeTo(cat("REPLACED")), cat("Use size() method directly on string."));
169fa1552e8SYitzhak Mandelbaum   return R;
170fdd98782SYitzhak Mandelbaum }
171fdd98782SYitzhak Mandelbaum 
172fdd98782SYitzhak Mandelbaum TEST_F(TransformerTest, StrlenSize) {
173fdd98782SYitzhak Mandelbaum   std::string Input = "int f(string s) { return strlen(s.c_str()); }";
174fdd98782SYitzhak Mandelbaum   std::string Expected = "int f(string s) { return REPLACED; }";
175fdd98782SYitzhak Mandelbaum   testRule(ruleStrlenSize(), Input, Expected);
176fdd98782SYitzhak Mandelbaum }
177fdd98782SYitzhak Mandelbaum 
178fdd98782SYitzhak Mandelbaum // Tests that no change is applied when a match is not expected.
179fdd98782SYitzhak Mandelbaum TEST_F(TransformerTest, NoMatch) {
180fdd98782SYitzhak Mandelbaum   std::string Input = "int f(string s) { return s.size(); }";
181fdd98782SYitzhak Mandelbaum   testRule(ruleStrlenSize(), Input, Input);
182fdd98782SYitzhak Mandelbaum }
183fdd98782SYitzhak Mandelbaum 
184fdd98782SYitzhak Mandelbaum // Tests replacing an expression.
185fdd98782SYitzhak Mandelbaum TEST_F(TransformerTest, Flag) {
186fdd98782SYitzhak Mandelbaum   StringRef Flag = "flag";
187fa1552e8SYitzhak Mandelbaum   RewriteRule Rule = makeRule(
188fa1552e8SYitzhak Mandelbaum       cxxMemberCallExpr(on(expr(hasType(cxxRecordDecl(
189fa1552e8SYitzhak Mandelbaum                                     hasName("proto::ProtoCommandLineFlag"))))
190fdd98782SYitzhak Mandelbaum                                .bind(Flag)),
191fa1552e8SYitzhak Mandelbaum                         unless(callee(cxxMethodDecl(hasName("GetProto"))))),
192adcd0268SBenjamin Kramer       changeTo(node(std::string(Flag)), cat("EXPR")));
193fdd98782SYitzhak Mandelbaum 
194fdd98782SYitzhak Mandelbaum   std::string Input = R"cc(
195fdd98782SYitzhak Mandelbaum     proto::ProtoCommandLineFlag flag;
196fdd98782SYitzhak Mandelbaum     int x = flag.foo();
197fdd98782SYitzhak Mandelbaum     int y = flag.GetProto().foo();
198fdd98782SYitzhak Mandelbaum   )cc";
199fdd98782SYitzhak Mandelbaum   std::string Expected = R"cc(
200fdd98782SYitzhak Mandelbaum     proto::ProtoCommandLineFlag flag;
201fdd98782SYitzhak Mandelbaum     int x = EXPR.foo();
202fdd98782SYitzhak Mandelbaum     int y = flag.GetProto().foo();
203fdd98782SYitzhak Mandelbaum   )cc";
204fdd98782SYitzhak Mandelbaum 
205fdd98782SYitzhak Mandelbaum   testRule(std::move(Rule), Input, Expected);
206fdd98782SYitzhak Mandelbaum }
207fdd98782SYitzhak Mandelbaum 
208727bdcb2SYitzhak Mandelbaum TEST_F(TransformerTest, AddIncludeQuoted) {
209d8c1f43dSYitzhak Mandelbaum   RewriteRule Rule =
210d8c1f43dSYitzhak Mandelbaum       makeRule(callExpr(callee(functionDecl(hasName("f")))),
211d8c1f43dSYitzhak Mandelbaum                {addInclude("clang/OtherLib.h"), changeTo(cat("other()"))});
212d8c1f43dSYitzhak Mandelbaum 
213d8c1f43dSYitzhak Mandelbaum   std::string Input = R"cc(
214d8c1f43dSYitzhak Mandelbaum     int f(int x);
215d8c1f43dSYitzhak Mandelbaum     int h(int x) { return f(x); }
216d8c1f43dSYitzhak Mandelbaum   )cc";
217d8c1f43dSYitzhak Mandelbaum   std::string Expected = R"cc(#include "clang/OtherLib.h"
218d8c1f43dSYitzhak Mandelbaum 
219d8c1f43dSYitzhak Mandelbaum     int f(int x);
220d8c1f43dSYitzhak Mandelbaum     int h(int x) { return other(); }
221d8c1f43dSYitzhak Mandelbaum   )cc";
222d8c1f43dSYitzhak Mandelbaum 
223d8c1f43dSYitzhak Mandelbaum   testRule(Rule, Input, Expected);
224d8c1f43dSYitzhak Mandelbaum }
225d8c1f43dSYitzhak Mandelbaum 
226d8c1f43dSYitzhak Mandelbaum TEST_F(TransformerTest, AddIncludeAngled) {
227d8c1f43dSYitzhak Mandelbaum   RewriteRule Rule = makeRule(
228d8c1f43dSYitzhak Mandelbaum       callExpr(callee(functionDecl(hasName("f")))),
229d8c1f43dSYitzhak Mandelbaum       {addInclude("clang/OtherLib.h", transformer::IncludeFormat::Angled),
230d8c1f43dSYitzhak Mandelbaum        changeTo(cat("other()"))});
231d8c1f43dSYitzhak Mandelbaum 
232d8c1f43dSYitzhak Mandelbaum   std::string Input = R"cc(
233d8c1f43dSYitzhak Mandelbaum     int f(int x);
234d8c1f43dSYitzhak Mandelbaum     int h(int x) { return f(x); }
235d8c1f43dSYitzhak Mandelbaum   )cc";
236d8c1f43dSYitzhak Mandelbaum   std::string Expected = R"cc(#include <clang/OtherLib.h>
237d8c1f43dSYitzhak Mandelbaum 
238d8c1f43dSYitzhak Mandelbaum     int f(int x);
239d8c1f43dSYitzhak Mandelbaum     int h(int x) { return other(); }
240d8c1f43dSYitzhak Mandelbaum   )cc";
241d8c1f43dSYitzhak Mandelbaum 
242d8c1f43dSYitzhak Mandelbaum   testRule(Rule, Input, Expected);
243d8c1f43dSYitzhak Mandelbaum }
244d8c1f43dSYitzhak Mandelbaum 
245d8c1f43dSYitzhak Mandelbaum TEST_F(TransformerTest, AddIncludeQuotedForRule) {
246727bdcb2SYitzhak Mandelbaum   RewriteRule Rule = makeRule(callExpr(callee(functionDecl(hasName("f")))),
2479f97480cSYitzhak Mandelbaum                               changeTo(cat("other()")));
248727bdcb2SYitzhak Mandelbaum   addInclude(Rule, "clang/OtherLib.h");
249727bdcb2SYitzhak Mandelbaum 
250727bdcb2SYitzhak Mandelbaum   std::string Input = R"cc(
251727bdcb2SYitzhak Mandelbaum     int f(int x);
252727bdcb2SYitzhak Mandelbaum     int h(int x) { return f(x); }
253727bdcb2SYitzhak Mandelbaum   )cc";
254727bdcb2SYitzhak Mandelbaum   std::string Expected = R"cc(#include "clang/OtherLib.h"
255727bdcb2SYitzhak Mandelbaum 
256727bdcb2SYitzhak Mandelbaum     int f(int x);
257727bdcb2SYitzhak Mandelbaum     int h(int x) { return other(); }
258727bdcb2SYitzhak Mandelbaum   )cc";
259727bdcb2SYitzhak Mandelbaum 
260727bdcb2SYitzhak Mandelbaum   testRule(Rule, Input, Expected);
261727bdcb2SYitzhak Mandelbaum }
262727bdcb2SYitzhak Mandelbaum 
263d8c1f43dSYitzhak Mandelbaum TEST_F(TransformerTest, AddIncludeAngledForRule) {
264727bdcb2SYitzhak Mandelbaum   RewriteRule Rule = makeRule(callExpr(callee(functionDecl(hasName("f")))),
2659f97480cSYitzhak Mandelbaum                               changeTo(cat("other()")));
2668bb47cd8SYitzhak Mandelbaum   addInclude(Rule, "clang/OtherLib.h", transformer::IncludeFormat::Angled);
267727bdcb2SYitzhak Mandelbaum 
268727bdcb2SYitzhak Mandelbaum   std::string Input = R"cc(
269727bdcb2SYitzhak Mandelbaum     int f(int x);
270727bdcb2SYitzhak Mandelbaum     int h(int x) { return f(x); }
271727bdcb2SYitzhak Mandelbaum   )cc";
272727bdcb2SYitzhak Mandelbaum   std::string Expected = R"cc(#include <clang/OtherLib.h>
273727bdcb2SYitzhak Mandelbaum 
274727bdcb2SYitzhak Mandelbaum     int f(int x);
275727bdcb2SYitzhak Mandelbaum     int h(int x) { return other(); }
276727bdcb2SYitzhak Mandelbaum   )cc";
277727bdcb2SYitzhak Mandelbaum 
278727bdcb2SYitzhak Mandelbaum   testRule(Rule, Input, Expected);
279727bdcb2SYitzhak Mandelbaum }
280727bdcb2SYitzhak Mandelbaum 
281fdd98782SYitzhak Mandelbaum TEST_F(TransformerTest, NodePartNameNamedDecl) {
282fdd98782SYitzhak Mandelbaum   StringRef Fun = "fun";
2833ec50e29SYitzhak Mandelbaum   RewriteRule Rule = makeRule(functionDecl(hasName("bad")).bind(Fun),
284adcd0268SBenjamin Kramer                               changeTo(name(std::string(Fun)), cat("good")));
285fdd98782SYitzhak Mandelbaum 
286fdd98782SYitzhak Mandelbaum   std::string Input = R"cc(
287fdd98782SYitzhak Mandelbaum     int bad(int x);
288fdd98782SYitzhak Mandelbaum     int bad(int x) { return x * x; }
289fdd98782SYitzhak Mandelbaum   )cc";
290fdd98782SYitzhak Mandelbaum   std::string Expected = R"cc(
291fdd98782SYitzhak Mandelbaum     int good(int x);
292fdd98782SYitzhak Mandelbaum     int good(int x) { return x * x; }
293fdd98782SYitzhak Mandelbaum   )cc";
294fdd98782SYitzhak Mandelbaum 
295fdd98782SYitzhak Mandelbaum   testRule(Rule, Input, Expected);
296fdd98782SYitzhak Mandelbaum }
297fdd98782SYitzhak Mandelbaum 
298fdd98782SYitzhak Mandelbaum TEST_F(TransformerTest, NodePartNameDeclRef) {
299fdd98782SYitzhak Mandelbaum   std::string Input = R"cc(
300fdd98782SYitzhak Mandelbaum     template <typename T>
301fdd98782SYitzhak Mandelbaum     T bad(T x) {
302fdd98782SYitzhak Mandelbaum       return x;
303fdd98782SYitzhak Mandelbaum     }
304fdd98782SYitzhak Mandelbaum     int neutral(int x) { return bad<int>(x) * x; }
305fdd98782SYitzhak Mandelbaum   )cc";
306fdd98782SYitzhak Mandelbaum   std::string Expected = R"cc(
307fdd98782SYitzhak Mandelbaum     template <typename T>
308fdd98782SYitzhak Mandelbaum     T bad(T x) {
309fdd98782SYitzhak Mandelbaum       return x;
310fdd98782SYitzhak Mandelbaum     }
311fdd98782SYitzhak Mandelbaum     int neutral(int x) { return good<int>(x) * x; }
312fdd98782SYitzhak Mandelbaum   )cc";
313fdd98782SYitzhak Mandelbaum 
314fdd98782SYitzhak Mandelbaum   StringRef Ref = "ref";
315fa1552e8SYitzhak Mandelbaum   testRule(makeRule(declRefExpr(to(functionDecl(hasName("bad")))).bind(Ref),
316adcd0268SBenjamin Kramer                     changeTo(name(std::string(Ref)), cat("good"))),
317fdd98782SYitzhak Mandelbaum            Input, Expected);
318fdd98782SYitzhak Mandelbaum }
319fdd98782SYitzhak Mandelbaum 
320fdd98782SYitzhak Mandelbaum TEST_F(TransformerTest, NodePartNameDeclRefFailure) {
321fdd98782SYitzhak Mandelbaum   std::string Input = R"cc(
322fdd98782SYitzhak Mandelbaum     struct Y {
323fdd98782SYitzhak Mandelbaum       int operator*();
324fdd98782SYitzhak Mandelbaum     };
325fdd98782SYitzhak Mandelbaum     int neutral(int x) {
326fdd98782SYitzhak Mandelbaum       Y y;
327fdd98782SYitzhak Mandelbaum       int (Y::*ptr)() = &Y::operator*;
328fdd98782SYitzhak Mandelbaum       return *y + x;
329fdd98782SYitzhak Mandelbaum     }
330fdd98782SYitzhak Mandelbaum   )cc";
331fdd98782SYitzhak Mandelbaum 
332fdd98782SYitzhak Mandelbaum   StringRef Ref = "ref";
333a5dadbe1SYitzhak Mandelbaum   Transformer T(makeRule(declRefExpr(to(functionDecl())).bind(Ref),
334adcd0268SBenjamin Kramer                          changeTo(name(std::string(Ref)), cat("good"))),
335a5dadbe1SYitzhak Mandelbaum                 consumer());
336a5dadbe1SYitzhak Mandelbaum   T.registerMatchers(&MatchFinder);
337a5dadbe1SYitzhak Mandelbaum   EXPECT_FALSE(rewrite(Input));
338fdd98782SYitzhak Mandelbaum }
339fdd98782SYitzhak Mandelbaum 
340fdd98782SYitzhak Mandelbaum TEST_F(TransformerTest, NodePartMember) {
341fdd98782SYitzhak Mandelbaum   StringRef E = "expr";
342fa1552e8SYitzhak Mandelbaum   RewriteRule Rule = makeRule(memberExpr(member(hasName("bad"))).bind(E),
343adcd0268SBenjamin Kramer                               changeTo(member(std::string(E)), cat("good")));
344fdd98782SYitzhak Mandelbaum 
345fdd98782SYitzhak Mandelbaum   std::string Input = R"cc(
346fdd98782SYitzhak Mandelbaum     struct S {
347fdd98782SYitzhak Mandelbaum       int bad;
348fdd98782SYitzhak Mandelbaum     };
349fdd98782SYitzhak Mandelbaum     int g() {
350fdd98782SYitzhak Mandelbaum       S s;
351fdd98782SYitzhak Mandelbaum       return s.bad;
352fdd98782SYitzhak Mandelbaum     }
353fdd98782SYitzhak Mandelbaum   )cc";
354fdd98782SYitzhak Mandelbaum   std::string Expected = R"cc(
355fdd98782SYitzhak Mandelbaum     struct S {
356fdd98782SYitzhak Mandelbaum       int bad;
357fdd98782SYitzhak Mandelbaum     };
358fdd98782SYitzhak Mandelbaum     int g() {
359fdd98782SYitzhak Mandelbaum       S s;
360fdd98782SYitzhak Mandelbaum       return s.good;
361fdd98782SYitzhak Mandelbaum     }
362fdd98782SYitzhak Mandelbaum   )cc";
363fdd98782SYitzhak Mandelbaum 
364fdd98782SYitzhak Mandelbaum   testRule(Rule, Input, Expected);
365fdd98782SYitzhak Mandelbaum }
366fdd98782SYitzhak Mandelbaum 
367fdd98782SYitzhak Mandelbaum TEST_F(TransformerTest, NodePartMemberQualified) {
368fdd98782SYitzhak Mandelbaum   std::string Input = R"cc(
369fdd98782SYitzhak Mandelbaum     struct S {
370fdd98782SYitzhak Mandelbaum       int bad;
371fdd98782SYitzhak Mandelbaum       int good;
372fdd98782SYitzhak Mandelbaum     };
373fdd98782SYitzhak Mandelbaum     struct T : public S {
374fdd98782SYitzhak Mandelbaum       int bad;
375fdd98782SYitzhak Mandelbaum     };
376fdd98782SYitzhak Mandelbaum     int g() {
377fdd98782SYitzhak Mandelbaum       T t;
378fdd98782SYitzhak Mandelbaum       return t.S::bad;
379fdd98782SYitzhak Mandelbaum     }
380fdd98782SYitzhak Mandelbaum   )cc";
381fdd98782SYitzhak Mandelbaum   std::string Expected = R"cc(
382fdd98782SYitzhak Mandelbaum     struct S {
383fdd98782SYitzhak Mandelbaum       int bad;
384fdd98782SYitzhak Mandelbaum       int good;
385fdd98782SYitzhak Mandelbaum     };
386fdd98782SYitzhak Mandelbaum     struct T : public S {
387fdd98782SYitzhak Mandelbaum       int bad;
388fdd98782SYitzhak Mandelbaum     };
389fdd98782SYitzhak Mandelbaum     int g() {
390fdd98782SYitzhak Mandelbaum       T t;
391fdd98782SYitzhak Mandelbaum       return t.S::good;
392fdd98782SYitzhak Mandelbaum     }
393fdd98782SYitzhak Mandelbaum   )cc";
394fdd98782SYitzhak Mandelbaum 
395fdd98782SYitzhak Mandelbaum   StringRef E = "expr";
396adcd0268SBenjamin Kramer   testRule(makeRule(memberExpr().bind(E),
397adcd0268SBenjamin Kramer                     changeTo(member(std::string(E)), cat("good"))),
398fdd98782SYitzhak Mandelbaum            Input, Expected);
399fdd98782SYitzhak Mandelbaum }
400fdd98782SYitzhak Mandelbaum 
401fdd98782SYitzhak Mandelbaum TEST_F(TransformerTest, NodePartMemberMultiToken) {
402fdd98782SYitzhak Mandelbaum   std::string Input = R"cc(
403fdd98782SYitzhak Mandelbaum     struct Y {
404fdd98782SYitzhak Mandelbaum       int operator*();
405fdd98782SYitzhak Mandelbaum       int good();
406fdd98782SYitzhak Mandelbaum       template <typename T> void foo(T t);
407fdd98782SYitzhak Mandelbaum     };
408fdd98782SYitzhak Mandelbaum     int neutral(int x) {
409fdd98782SYitzhak Mandelbaum       Y y;
410fdd98782SYitzhak Mandelbaum       y.template foo<int>(3);
411fdd98782SYitzhak Mandelbaum       return y.operator *();
412fdd98782SYitzhak Mandelbaum     }
413fdd98782SYitzhak Mandelbaum   )cc";
414fdd98782SYitzhak Mandelbaum   std::string Expected = R"cc(
415fdd98782SYitzhak Mandelbaum     struct Y {
416fdd98782SYitzhak Mandelbaum       int operator*();
417fdd98782SYitzhak Mandelbaum       int good();
418fdd98782SYitzhak Mandelbaum       template <typename T> void foo(T t);
419fdd98782SYitzhak Mandelbaum     };
420fdd98782SYitzhak Mandelbaum     int neutral(int x) {
421fdd98782SYitzhak Mandelbaum       Y y;
422fdd98782SYitzhak Mandelbaum       y.template good<int>(3);
423fdd98782SYitzhak Mandelbaum       return y.good();
424fdd98782SYitzhak Mandelbaum     }
425fdd98782SYitzhak Mandelbaum   )cc";
426fdd98782SYitzhak Mandelbaum 
427fdd98782SYitzhak Mandelbaum   StringRef MemExpr = "member";
428fa1552e8SYitzhak Mandelbaum   testRule(makeRule(memberExpr().bind(MemExpr),
429adcd0268SBenjamin Kramer                     changeTo(member(std::string(MemExpr)), cat("good"))),
430fa1552e8SYitzhak Mandelbaum            Input, Expected);
431fa1552e8SYitzhak Mandelbaum }
432fa1552e8SYitzhak Mandelbaum 
433cf428778SYitzhak Mandelbaum TEST_F(TransformerTest, NoEdits) {
434cf428778SYitzhak Mandelbaum   using transformer::noEdits;
435cf428778SYitzhak Mandelbaum   std::string Input = "int f(int x) { return x; }";
436cf428778SYitzhak Mandelbaum   testRule(makeRule(returnStmt().bind("return"), noEdits()), Input, Input);
437cf428778SYitzhak Mandelbaum }
438cf428778SYitzhak Mandelbaum 
4396f8f5cb7SYitzhak Mandelbaum TEST_F(TransformerTest, NoopEdit) {
4406f8f5cb7SYitzhak Mandelbaum   using transformer::node;
4416f8f5cb7SYitzhak Mandelbaum   using transformer::noopEdit;
4426f8f5cb7SYitzhak Mandelbaum   std::string Input = "int f(int x) { return x; }";
4436f8f5cb7SYitzhak Mandelbaum   testRule(makeRule(returnStmt().bind("return"), noopEdit(node("return"))),
4446f8f5cb7SYitzhak Mandelbaum            Input, Input);
4456f8f5cb7SYitzhak Mandelbaum }
4466f8f5cb7SYitzhak Mandelbaum 
447cf428778SYitzhak Mandelbaum TEST_F(TransformerTest, IfBound2Args) {
448cf428778SYitzhak Mandelbaum   using transformer::ifBound;
449cf428778SYitzhak Mandelbaum   std::string Input = "int f(int x) { return x; }";
450cf428778SYitzhak Mandelbaum   std::string Expected = "int f(int x) { CHANGE; }";
451cf428778SYitzhak Mandelbaum   testRule(makeRule(returnStmt().bind("return"),
452cf428778SYitzhak Mandelbaum                     ifBound("return", changeTo(cat("CHANGE;")))),
453cf428778SYitzhak Mandelbaum            Input, Expected);
454cf428778SYitzhak Mandelbaum }
455cf428778SYitzhak Mandelbaum 
456cf428778SYitzhak Mandelbaum TEST_F(TransformerTest, IfBound3Args) {
457cf428778SYitzhak Mandelbaum   using transformer::ifBound;
458cf428778SYitzhak Mandelbaum   std::string Input = "int f(int x) { return x; }";
459cf428778SYitzhak Mandelbaum   std::string Expected = "int f(int x) { CHANGE; }";
460cf428778SYitzhak Mandelbaum   testRule(makeRule(returnStmt().bind("return"),
461cf428778SYitzhak Mandelbaum                     ifBound("nothing", changeTo(cat("ERROR")),
462cf428778SYitzhak Mandelbaum                             changeTo(cat("CHANGE;")))),
463cf428778SYitzhak Mandelbaum            Input, Expected);
464cf428778SYitzhak Mandelbaum }
465cf428778SYitzhak Mandelbaum 
466cf428778SYitzhak Mandelbaum TEST_F(TransformerTest, ShrinkTo) {
467cf428778SYitzhak Mandelbaum   using transformer::shrinkTo;
468cf428778SYitzhak Mandelbaum   std::string Input = "int f(int x) { return x; }";
469cf428778SYitzhak Mandelbaum   std::string Expected = "return x;";
470cf428778SYitzhak Mandelbaum   testRule(makeRule(functionDecl(hasDescendant(returnStmt().bind("return")))
471cf428778SYitzhak Mandelbaum                         .bind("function"),
472cf428778SYitzhak Mandelbaum                     shrinkTo(node("function"), node("return"))),
473cf428778SYitzhak Mandelbaum            Input, Expected);
474cf428778SYitzhak Mandelbaum }
475cf428778SYitzhak Mandelbaum 
476c332a984SYitzhak Mandelbaum // Rewrite various Stmts inside a Decl.
477c332a984SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsDeclChangeStmt) {
478c332a984SYitzhak Mandelbaum   std::string Input =
479c332a984SYitzhak Mandelbaum       "int f(int x) { int y = x; { int z = x * x; } return x; }";
480c332a984SYitzhak Mandelbaum   std::string Expected =
481c332a984SYitzhak Mandelbaum       "int f(int x) { int y = 3; { int z = 3 * 3; } return 3; }";
482c332a984SYitzhak Mandelbaum   auto InlineX =
483c332a984SYitzhak Mandelbaum       makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
484c332a984SYitzhak Mandelbaum   testRule(makeRule(functionDecl(hasName("f")).bind("fun"),
485c332a984SYitzhak Mandelbaum                     rewriteDescendants("fun", InlineX)),
486c332a984SYitzhak Mandelbaum            Input, Expected);
487c332a984SYitzhak Mandelbaum }
488c332a984SYitzhak Mandelbaum 
489c332a984SYitzhak Mandelbaum // Rewrite various TypeLocs inside a Decl.
490c332a984SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsDeclChangeTypeLoc) {
491c332a984SYitzhak Mandelbaum   std::string Input = "int f(int *x) { return *x; }";
492c332a984SYitzhak Mandelbaum   std::string Expected = "char f(char *x) { return *x; }";
493c332a984SYitzhak Mandelbaum   auto IntToChar = makeRule(typeLoc(loc(qualType(isInteger(), builtinType()))),
494c332a984SYitzhak Mandelbaum                             changeTo(cat("char")));
495c332a984SYitzhak Mandelbaum   testRule(makeRule(functionDecl(hasName("f")).bind("fun"),
496c332a984SYitzhak Mandelbaum                     rewriteDescendants("fun", IntToChar)),
497c332a984SYitzhak Mandelbaum            Input, Expected);
498c332a984SYitzhak Mandelbaum }
499c332a984SYitzhak Mandelbaum 
500c332a984SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsStmt) {
501c332a984SYitzhak Mandelbaum   // Add an unrelated definition to the header that also has a variable named
502c332a984SYitzhak Mandelbaum   // "x", to test that the rewrite is limited to the scope we intend.
503c332a984SYitzhak Mandelbaum   appendToHeader(R"cc(int g(int x) { return x; })cc");
504c332a984SYitzhak Mandelbaum   std::string Input =
505c332a984SYitzhak Mandelbaum       "int f(int x) { int y = x; { int z = x * x; } return x; }";
506c332a984SYitzhak Mandelbaum   std::string Expected =
507c332a984SYitzhak Mandelbaum       "int f(int x) { int y = 3; { int z = 3 * 3; } return 3; }";
508c332a984SYitzhak Mandelbaum   auto InlineX =
509c332a984SYitzhak Mandelbaum       makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
510c332a984SYitzhak Mandelbaum   testRule(makeRule(functionDecl(hasName("f"), hasBody(stmt().bind("body"))),
511c332a984SYitzhak Mandelbaum                     rewriteDescendants("body", InlineX)),
512c332a984SYitzhak Mandelbaum            Input, Expected);
513c332a984SYitzhak Mandelbaum }
514c332a984SYitzhak Mandelbaum 
515c332a984SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsStmtWithAdditionalChange) {
516c332a984SYitzhak Mandelbaum   std::string Input =
517c332a984SYitzhak Mandelbaum       "int f(int x) { int y = x; { int z = x * x; } return x; }";
518c332a984SYitzhak Mandelbaum   std::string Expected =
519c332a984SYitzhak Mandelbaum       "int newName(int x) { int y = 3; { int z = 3 * 3; } return 3; }";
520c332a984SYitzhak Mandelbaum   auto InlineX =
521c332a984SYitzhak Mandelbaum       makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
522c332a984SYitzhak Mandelbaum   testRule(
523c332a984SYitzhak Mandelbaum       makeRule(
524c332a984SYitzhak Mandelbaum           functionDecl(hasName("f"), hasBody(stmt().bind("body"))).bind("f"),
525c332a984SYitzhak Mandelbaum           flatten(changeTo(name("f"), cat("newName")),
526c332a984SYitzhak Mandelbaum                   rewriteDescendants("body", InlineX))),
527c332a984SYitzhak Mandelbaum       Input, Expected);
528c332a984SYitzhak Mandelbaum }
529c332a984SYitzhak Mandelbaum 
530c332a984SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsTypeLoc) {
531c332a984SYitzhak Mandelbaum   std::string Input = "int f(int *x) { return *x; }";
532c332a984SYitzhak Mandelbaum   std::string Expected = "int f(char *x) { return *x; }";
533c332a984SYitzhak Mandelbaum   auto IntToChar =
534c332a984SYitzhak Mandelbaum       makeRule(typeLoc(loc(qualType(isInteger(), builtinType()))).bind("loc"),
535c332a984SYitzhak Mandelbaum                changeTo(cat("char")));
536c332a984SYitzhak Mandelbaum   testRule(
537c332a984SYitzhak Mandelbaum       makeRule(functionDecl(hasName("f"),
538c332a984SYitzhak Mandelbaum                             hasParameter(0, varDecl(hasTypeLoc(
539c332a984SYitzhak Mandelbaum                                                 typeLoc().bind("parmType"))))),
540c332a984SYitzhak Mandelbaum                rewriteDescendants("parmType", IntToChar)),
541c332a984SYitzhak Mandelbaum       Input, Expected);
542c332a984SYitzhak Mandelbaum }
543c332a984SYitzhak Mandelbaum 
544c332a984SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsReferToParentBinding) {
545c332a984SYitzhak Mandelbaum   std::string Input =
546c332a984SYitzhak Mandelbaum       "int f(int p) { int y = p; { int z = p * p; } return p; }";
547c332a984SYitzhak Mandelbaum   std::string Expected =
548c332a984SYitzhak Mandelbaum       "int f(int p) { int y = 3; { int z = 3 * 3; } return 3; }";
549c332a984SYitzhak Mandelbaum   std::string VarId = "var";
550c332a984SYitzhak Mandelbaum   auto InlineVar = makeRule(declRefExpr(to(varDecl(equalsBoundNode(VarId)))),
551c332a984SYitzhak Mandelbaum                             changeTo(cat("3")));
552c332a984SYitzhak Mandelbaum   testRule(makeRule(functionDecl(hasName("f"),
553c332a984SYitzhak Mandelbaum                                  hasParameter(0, varDecl().bind(VarId)))
554c332a984SYitzhak Mandelbaum                         .bind("fun"),
555c332a984SYitzhak Mandelbaum                     rewriteDescendants("fun", InlineVar)),
556c332a984SYitzhak Mandelbaum            Input, Expected);
557c332a984SYitzhak Mandelbaum }
558c332a984SYitzhak Mandelbaum 
559c332a984SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsUnboundNode) {
560c332a984SYitzhak Mandelbaum   std::string Input =
561c332a984SYitzhak Mandelbaum       "int f(int x) { int y = x; { int z = x * x; } return x; }";
562c332a984SYitzhak Mandelbaum   auto InlineX =
563c332a984SYitzhak Mandelbaum       makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
564c332a984SYitzhak Mandelbaum   Transformer T(makeRule(functionDecl(hasName("f")),
565c332a984SYitzhak Mandelbaum                          rewriteDescendants("UNBOUND", InlineX)),
566c332a984SYitzhak Mandelbaum                 consumer());
567c332a984SYitzhak Mandelbaum   T.registerMatchers(&MatchFinder);
568c332a984SYitzhak Mandelbaum   EXPECT_FALSE(rewrite(Input));
569c332a984SYitzhak Mandelbaum   EXPECT_THAT(Changes, IsEmpty());
570c332a984SYitzhak Mandelbaum   EXPECT_EQ(ErrorCount, 1);
571c332a984SYitzhak Mandelbaum }
572c332a984SYitzhak Mandelbaum 
573c332a984SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsInvalidNodeType) {
574c332a984SYitzhak Mandelbaum   std::string Input =
575c332a984SYitzhak Mandelbaum       "int f(int x) { int y = x; { int z = x * x; } return x; }";
576c332a984SYitzhak Mandelbaum   auto IntToChar =
577c332a984SYitzhak Mandelbaum       makeRule(qualType(isInteger(), builtinType()), changeTo(cat("char")));
578c332a984SYitzhak Mandelbaum   Transformer T(
579c332a984SYitzhak Mandelbaum       makeRule(functionDecl(
580c332a984SYitzhak Mandelbaum                    hasName("f"),
581c332a984SYitzhak Mandelbaum                    hasParameter(0, varDecl(hasType(qualType().bind("type"))))),
582c332a984SYitzhak Mandelbaum                rewriteDescendants("type", IntToChar)),
583c332a984SYitzhak Mandelbaum       consumer());
584c332a984SYitzhak Mandelbaum   T.registerMatchers(&MatchFinder);
585c332a984SYitzhak Mandelbaum   EXPECT_FALSE(rewrite(Input));
586c332a984SYitzhak Mandelbaum   EXPECT_THAT(Changes, IsEmpty());
587c332a984SYitzhak Mandelbaum   EXPECT_EQ(ErrorCount, 1);
588c332a984SYitzhak Mandelbaum }
589c332a984SYitzhak Mandelbaum 
590d4f39031SYitzhak Mandelbaum //
591d4f39031SYitzhak Mandelbaum // We include one test per typed overload. We don't test extensively since that
592d4f39031SYitzhak Mandelbaum // is already covered by the tests above.
593d4f39031SYitzhak Mandelbaum //
594d4f39031SYitzhak Mandelbaum 
595d4f39031SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsTypedStmt) {
596d4f39031SYitzhak Mandelbaum   // Add an unrelated definition to the header that also has a variable named
597d4f39031SYitzhak Mandelbaum   // "x", to test that the rewrite is limited to the scope we intend.
598d4f39031SYitzhak Mandelbaum   appendToHeader(R"cc(int g(int x) { return x; })cc");
599d4f39031SYitzhak Mandelbaum   std::string Input =
600d4f39031SYitzhak Mandelbaum       "int f(int x) { int y = x; { int z = x * x; } return x; }";
601d4f39031SYitzhak Mandelbaum   std::string Expected =
602d4f39031SYitzhak Mandelbaum       "int f(int x) { int y = 3; { int z = 3 * 3; } return 3; }";
603d4f39031SYitzhak Mandelbaum   auto InlineX =
604d4f39031SYitzhak Mandelbaum       makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
605d4f39031SYitzhak Mandelbaum   testRule(makeRule(functionDecl(hasName("f"), hasBody(stmt().bind("body"))),
606d4f39031SYitzhak Mandelbaum                     [&InlineX](const MatchFinder::MatchResult &R) {
607d4f39031SYitzhak Mandelbaum                       const auto *Node = R.Nodes.getNodeAs<Stmt>("body");
608d4f39031SYitzhak Mandelbaum                       assert(Node != nullptr && "body must be bound");
609d4f39031SYitzhak Mandelbaum                       return transformer::detail::rewriteDescendants(
610d4f39031SYitzhak Mandelbaum                           *Node, InlineX, R);
611d4f39031SYitzhak Mandelbaum                     }),
612d4f39031SYitzhak Mandelbaum            Input, Expected);
613d4f39031SYitzhak Mandelbaum }
614d4f39031SYitzhak Mandelbaum 
615d4f39031SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsTypedDecl) {
616d4f39031SYitzhak Mandelbaum   std::string Input =
617d4f39031SYitzhak Mandelbaum       "int f(int x) { int y = x; { int z = x * x; } return x; }";
618d4f39031SYitzhak Mandelbaum   std::string Expected =
619d4f39031SYitzhak Mandelbaum       "int f(int x) { int y = 3; { int z = 3 * 3; } return 3; }";
620d4f39031SYitzhak Mandelbaum   auto InlineX =
621d4f39031SYitzhak Mandelbaum       makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
622d4f39031SYitzhak Mandelbaum   testRule(makeRule(functionDecl(hasName("f")).bind("fun"),
623d4f39031SYitzhak Mandelbaum                     [&InlineX](const MatchFinder::MatchResult &R) {
624d4f39031SYitzhak Mandelbaum                       const auto *Node = R.Nodes.getNodeAs<Decl>("fun");
625d4f39031SYitzhak Mandelbaum                       assert(Node != nullptr && "fun must be bound");
626d4f39031SYitzhak Mandelbaum                       return transformer::detail::rewriteDescendants(
627d4f39031SYitzhak Mandelbaum                           *Node, InlineX, R);
628d4f39031SYitzhak Mandelbaum                     }),
629d4f39031SYitzhak Mandelbaum            Input, Expected);
630d4f39031SYitzhak Mandelbaum }
631d4f39031SYitzhak Mandelbaum 
632d4f39031SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsTypedTypeLoc) {
633d4f39031SYitzhak Mandelbaum   std::string Input = "int f(int *x) { return *x; }";
634d4f39031SYitzhak Mandelbaum   std::string Expected = "int f(char *x) { return *x; }";
635d4f39031SYitzhak Mandelbaum   auto IntToChar =
636d4f39031SYitzhak Mandelbaum       makeRule(typeLoc(loc(qualType(isInteger(), builtinType()))).bind("loc"),
637d4f39031SYitzhak Mandelbaum                changeTo(cat("char")));
638d4f39031SYitzhak Mandelbaum   testRule(
639d4f39031SYitzhak Mandelbaum       makeRule(
640d4f39031SYitzhak Mandelbaum           functionDecl(
641d4f39031SYitzhak Mandelbaum               hasName("f"),
642d4f39031SYitzhak Mandelbaum               hasParameter(0, varDecl(hasTypeLoc(typeLoc().bind("parmType"))))),
643d4f39031SYitzhak Mandelbaum           [&IntToChar](const MatchFinder::MatchResult &R) {
644d4f39031SYitzhak Mandelbaum             const auto *Node = R.Nodes.getNodeAs<TypeLoc>("parmType");
645d4f39031SYitzhak Mandelbaum             assert(Node != nullptr && "parmType must be bound");
646d4f39031SYitzhak Mandelbaum             return transformer::detail::rewriteDescendants(*Node, IntToChar, R);
647d4f39031SYitzhak Mandelbaum           }),
648d4f39031SYitzhak Mandelbaum       Input, Expected);
649d4f39031SYitzhak Mandelbaum }
650d4f39031SYitzhak Mandelbaum 
651d4f39031SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsTypedDynTyped) {
652d4f39031SYitzhak Mandelbaum   // Add an unrelated definition to the header that also has a variable named
653d4f39031SYitzhak Mandelbaum   // "x", to test that the rewrite is limited to the scope we intend.
654d4f39031SYitzhak Mandelbaum   appendToHeader(R"cc(int g(int x) { return x; })cc");
655d4f39031SYitzhak Mandelbaum   std::string Input =
656d4f39031SYitzhak Mandelbaum       "int f(int x) { int y = x; { int z = x * x; } return x; }";
657d4f39031SYitzhak Mandelbaum   std::string Expected =
658d4f39031SYitzhak Mandelbaum       "int f(int x) { int y = 3; { int z = 3 * 3; } return 3; }";
659d4f39031SYitzhak Mandelbaum   auto InlineX =
660d4f39031SYitzhak Mandelbaum       makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
661d4f39031SYitzhak Mandelbaum   testRule(
662d4f39031SYitzhak Mandelbaum       makeRule(functionDecl(hasName("f"), hasBody(stmt().bind("body"))),
663d4f39031SYitzhak Mandelbaum                [&InlineX](const MatchFinder::MatchResult &R) {
664d4f39031SYitzhak Mandelbaum                  auto It = R.Nodes.getMap().find("body");
665d4f39031SYitzhak Mandelbaum                  assert(It != R.Nodes.getMap().end() && "body must be bound");
666d4f39031SYitzhak Mandelbaum                  return transformer::detail::rewriteDescendants(It->second,
667d4f39031SYitzhak Mandelbaum                                                                 InlineX, R);
668d4f39031SYitzhak Mandelbaum                }),
669d4f39031SYitzhak Mandelbaum       Input, Expected);
670d4f39031SYitzhak Mandelbaum }
671d4f39031SYitzhak Mandelbaum 
6722e4a628cSYitzhak Mandelbaum TEST_F(TransformerTest, InsertBeforeEdit) {
6732e4a628cSYitzhak Mandelbaum   std::string Input = R"cc(
6742e4a628cSYitzhak Mandelbaum     int f() {
6752e4a628cSYitzhak Mandelbaum       return 7;
6762e4a628cSYitzhak Mandelbaum     }
6772e4a628cSYitzhak Mandelbaum   )cc";
6782e4a628cSYitzhak Mandelbaum   std::string Expected = R"cc(
6792e4a628cSYitzhak Mandelbaum     int f() {
6802e4a628cSYitzhak Mandelbaum       int y = 3;
6812e4a628cSYitzhak Mandelbaum       return 7;
6822e4a628cSYitzhak Mandelbaum     }
6832e4a628cSYitzhak Mandelbaum   )cc";
6842e4a628cSYitzhak Mandelbaum 
6852e4a628cSYitzhak Mandelbaum   StringRef Ret = "return";
686adcd0268SBenjamin Kramer   testRule(
687adcd0268SBenjamin Kramer       makeRule(returnStmt().bind(Ret),
688adcd0268SBenjamin Kramer                insertBefore(statement(std::string(Ret)), cat("int y = 3;"))),
6892e4a628cSYitzhak Mandelbaum       Input, Expected);
6902e4a628cSYitzhak Mandelbaum }
6912e4a628cSYitzhak Mandelbaum 
6922e4a628cSYitzhak Mandelbaum TEST_F(TransformerTest, InsertAfterEdit) {
6932e4a628cSYitzhak Mandelbaum   std::string Input = R"cc(
6942e4a628cSYitzhak Mandelbaum     int f() {
6952e4a628cSYitzhak Mandelbaum       int x = 5;
6962e4a628cSYitzhak Mandelbaum       return 7;
6972e4a628cSYitzhak Mandelbaum     }
6982e4a628cSYitzhak Mandelbaum   )cc";
6992e4a628cSYitzhak Mandelbaum   std::string Expected = R"cc(
7002e4a628cSYitzhak Mandelbaum     int f() {
7012e4a628cSYitzhak Mandelbaum       int x = 5;
7022e4a628cSYitzhak Mandelbaum       int y = 3;
7032e4a628cSYitzhak Mandelbaum       return 7;
7042e4a628cSYitzhak Mandelbaum     }
7052e4a628cSYitzhak Mandelbaum   )cc";
7062e4a628cSYitzhak Mandelbaum 
7072e4a628cSYitzhak Mandelbaum   StringRef Decl = "decl";
708adcd0268SBenjamin Kramer   testRule(
709adcd0268SBenjamin Kramer       makeRule(declStmt().bind(Decl),
710adcd0268SBenjamin Kramer                insertAfter(statement(std::string(Decl)), cat("int y = 3;"))),
7112e4a628cSYitzhak Mandelbaum       Input, Expected);
7122e4a628cSYitzhak Mandelbaum }
7132e4a628cSYitzhak Mandelbaum 
7142e4a628cSYitzhak Mandelbaum TEST_F(TransformerTest, RemoveEdit) {
7152e4a628cSYitzhak Mandelbaum   std::string Input = R"cc(
7162e4a628cSYitzhak Mandelbaum     int f() {
7172e4a628cSYitzhak Mandelbaum       int x = 5;
7182e4a628cSYitzhak Mandelbaum       return 7;
7192e4a628cSYitzhak Mandelbaum     }
7202e4a628cSYitzhak Mandelbaum   )cc";
7212e4a628cSYitzhak Mandelbaum   std::string Expected = R"cc(
7222e4a628cSYitzhak Mandelbaum     int f() {
7232e4a628cSYitzhak Mandelbaum       return 7;
7242e4a628cSYitzhak Mandelbaum     }
7252e4a628cSYitzhak Mandelbaum   )cc";
7262e4a628cSYitzhak Mandelbaum 
7272e4a628cSYitzhak Mandelbaum   StringRef Decl = "decl";
728adcd0268SBenjamin Kramer   testRule(
729adcd0268SBenjamin Kramer       makeRule(declStmt().bind(Decl), remove(statement(std::string(Decl)))),
730adcd0268SBenjamin Kramer       Input, Expected);
7312e4a628cSYitzhak Mandelbaum }
7322e4a628cSYitzhak Mandelbaum 
7339945bd59SAndy Soffer TEST_F(TransformerTest, WithMetadata) {
734e5b3202bSAndy Soffer   auto makeMetadata = [](const MatchFinder::MatchResult &R) -> llvm::Any {
735e5b3202bSAndy Soffer     int N =
736e5b3202bSAndy Soffer         R.Nodes.getNodeAs<IntegerLiteral>("int")->getValue().getLimitedValue();
737e5b3202bSAndy Soffer     return N;
738e5b3202bSAndy Soffer   };
739e5b3202bSAndy Soffer 
7409945bd59SAndy Soffer   std::string Input = R"cc(
7419945bd59SAndy Soffer     int f() {
7429945bd59SAndy Soffer       int x = 5;
7439945bd59SAndy Soffer       return 7;
7449945bd59SAndy Soffer     }
7459945bd59SAndy Soffer   )cc";
7469945bd59SAndy Soffer 
7479945bd59SAndy Soffer   Transformer T(
748e5b3202bSAndy Soffer       makeRule(
749e5b3202bSAndy Soffer           declStmt(containsDeclaration(0, varDecl(hasInitializer(
750e5b3202bSAndy Soffer                                               integerLiteral().bind("int")))))
751e5b3202bSAndy Soffer               .bind("decl"),
752e5b3202bSAndy Soffer           withMetadata(remove(statement(std::string("decl"))), makeMetadata)),
7539945bd59SAndy Soffer       consumer());
7549945bd59SAndy Soffer   T.registerMatchers(&MatchFinder);
7559945bd59SAndy Soffer   auto Factory = newFrontendActionFactory(&MatchFinder);
7569945bd59SAndy Soffer   EXPECT_TRUE(runToolOnCodeWithArgs(
7579945bd59SAndy Soffer       Factory->create(), Input, std::vector<std::string>(), "input.cc",
7589945bd59SAndy Soffer       "clang-tool", std::make_shared<PCHContainerOperations>(), {}));
7599945bd59SAndy Soffer   ASSERT_EQ(Changes.size(), 1u);
7609945bd59SAndy Soffer   const llvm::Any &Metadata = Changes[0].getMetadata();
7619945bd59SAndy Soffer   ASSERT_TRUE(llvm::any_isa<int>(Metadata));
762e5b3202bSAndy Soffer   EXPECT_THAT(llvm::any_cast<int>(Metadata), 5);
7639945bd59SAndy Soffer }
7649945bd59SAndy Soffer 
765fa1552e8SYitzhak Mandelbaum TEST_F(TransformerTest, MultiChange) {
766fa1552e8SYitzhak Mandelbaum   std::string Input = R"cc(
767fa1552e8SYitzhak Mandelbaum     void foo() {
768fa1552e8SYitzhak Mandelbaum       if (10 > 1.0)
769fa1552e8SYitzhak Mandelbaum         log(1) << "oh no!";
770fa1552e8SYitzhak Mandelbaum       else
771fa1552e8SYitzhak Mandelbaum         log(0) << "ok";
772fa1552e8SYitzhak Mandelbaum     }
773fa1552e8SYitzhak Mandelbaum   )cc";
774fa1552e8SYitzhak Mandelbaum   std::string Expected = R"(
775fa1552e8SYitzhak Mandelbaum     void foo() {
776fa1552e8SYitzhak Mandelbaum       if (true) { /* then */ }
777fa1552e8SYitzhak Mandelbaum       else { /* else */ }
778fa1552e8SYitzhak Mandelbaum     }
779fa1552e8SYitzhak Mandelbaum   )";
780fa1552e8SYitzhak Mandelbaum 
781fa1552e8SYitzhak Mandelbaum   StringRef C = "C", T = "T", E = "E";
782adcd0268SBenjamin Kramer   testRule(
783adcd0268SBenjamin Kramer       makeRule(ifStmt(hasCondition(expr().bind(C)), hasThen(stmt().bind(T)),
784adcd0268SBenjamin Kramer                       hasElse(stmt().bind(E))),
785adcd0268SBenjamin Kramer                {changeTo(node(std::string(C)), cat("true")),
786adcd0268SBenjamin Kramer                 changeTo(statement(std::string(T)), cat("{ /* then */ }")),
787adcd0268SBenjamin Kramer                 changeTo(statement(std::string(E)), cat("{ /* else */ }"))}),
788fdd98782SYitzhak Mandelbaum       Input, Expected);
789fdd98782SYitzhak Mandelbaum }
790fdd98782SYitzhak Mandelbaum 
791cf428778SYitzhak Mandelbaum TEST_F(TransformerTest, EditList) {
792cf428778SYitzhak Mandelbaum   using clang::transformer::editList;
793cf428778SYitzhak Mandelbaum   std::string Input = R"cc(
794cf428778SYitzhak Mandelbaum     void foo() {
795cf428778SYitzhak Mandelbaum       if (10 > 1.0)
796cf428778SYitzhak Mandelbaum         log(1) << "oh no!";
797cf428778SYitzhak Mandelbaum       else
798cf428778SYitzhak Mandelbaum         log(0) << "ok";
799cf428778SYitzhak Mandelbaum     }
800cf428778SYitzhak Mandelbaum   )cc";
801cf428778SYitzhak Mandelbaum   std::string Expected = R"(
802cf428778SYitzhak Mandelbaum     void foo() {
803cf428778SYitzhak Mandelbaum       if (true) { /* then */ }
804cf428778SYitzhak Mandelbaum       else { /* else */ }
805cf428778SYitzhak Mandelbaum     }
806cf428778SYitzhak Mandelbaum   )";
807cf428778SYitzhak Mandelbaum 
808cf428778SYitzhak Mandelbaum   StringRef C = "C", T = "T", E = "E";
809cf428778SYitzhak Mandelbaum   testRule(makeRule(ifStmt(hasCondition(expr().bind(C)),
810cf428778SYitzhak Mandelbaum                            hasThen(stmt().bind(T)), hasElse(stmt().bind(E))),
811cf428778SYitzhak Mandelbaum                     editList({changeTo(node(std::string(C)), cat("true")),
812cf428778SYitzhak Mandelbaum                               changeTo(statement(std::string(T)),
813cf428778SYitzhak Mandelbaum                                        cat("{ /* then */ }")),
814cf428778SYitzhak Mandelbaum                               changeTo(statement(std::string(E)),
815cf428778SYitzhak Mandelbaum                                        cat("{ /* else */ }"))})),
816cf428778SYitzhak Mandelbaum            Input, Expected);
817cf428778SYitzhak Mandelbaum }
818cf428778SYitzhak Mandelbaum 
819cf428778SYitzhak Mandelbaum TEST_F(TransformerTest, Flatten) {
820cf428778SYitzhak Mandelbaum   using clang::transformer::editList;
821cf428778SYitzhak Mandelbaum   std::string Input = R"cc(
822cf428778SYitzhak Mandelbaum     void foo() {
823cf428778SYitzhak Mandelbaum       if (10 > 1.0)
824cf428778SYitzhak Mandelbaum         log(1) << "oh no!";
825cf428778SYitzhak Mandelbaum       else
826cf428778SYitzhak Mandelbaum         log(0) << "ok";
827cf428778SYitzhak Mandelbaum     }
828cf428778SYitzhak Mandelbaum   )cc";
829cf428778SYitzhak Mandelbaum   std::string Expected = R"(
830cf428778SYitzhak Mandelbaum     void foo() {
831cf428778SYitzhak Mandelbaum       if (true) { /* then */ }
832cf428778SYitzhak Mandelbaum       else { /* else */ }
833cf428778SYitzhak Mandelbaum     }
834cf428778SYitzhak Mandelbaum   )";
835cf428778SYitzhak Mandelbaum 
836cf428778SYitzhak Mandelbaum   StringRef C = "C", T = "T", E = "E";
837cf428778SYitzhak Mandelbaum   testRule(
838cf428778SYitzhak Mandelbaum       makeRule(
839cf428778SYitzhak Mandelbaum           ifStmt(hasCondition(expr().bind(C)), hasThen(stmt().bind(T)),
840cf428778SYitzhak Mandelbaum                  hasElse(stmt().bind(E))),
841cf428778SYitzhak Mandelbaum           flatten(changeTo(node(std::string(C)), cat("true")),
842cf428778SYitzhak Mandelbaum                   changeTo(statement(std::string(T)), cat("{ /* then */ }")),
843cf428778SYitzhak Mandelbaum                   changeTo(statement(std::string(E)), cat("{ /* else */ }")))),
844cf428778SYitzhak Mandelbaum       Input, Expected);
845cf428778SYitzhak Mandelbaum }
846cf428778SYitzhak Mandelbaum 
847cf428778SYitzhak Mandelbaum TEST_F(TransformerTest, FlattenWithMixedArgs) {
848cf428778SYitzhak Mandelbaum   using clang::transformer::editList;
849cf428778SYitzhak Mandelbaum   std::string Input = R"cc(
850cf428778SYitzhak Mandelbaum     void foo() {
851cf428778SYitzhak Mandelbaum       if (10 > 1.0)
852cf428778SYitzhak Mandelbaum         log(1) << "oh no!";
853cf428778SYitzhak Mandelbaum       else
854cf428778SYitzhak Mandelbaum         log(0) << "ok";
855cf428778SYitzhak Mandelbaum     }
856cf428778SYitzhak Mandelbaum   )cc";
857cf428778SYitzhak Mandelbaum   std::string Expected = R"(
858cf428778SYitzhak Mandelbaum     void foo() {
859cf428778SYitzhak Mandelbaum       if (true) { /* then */ }
860cf428778SYitzhak Mandelbaum       else { /* else */ }
861cf428778SYitzhak Mandelbaum     }
862cf428778SYitzhak Mandelbaum   )";
863cf428778SYitzhak Mandelbaum 
864cf428778SYitzhak Mandelbaum   StringRef C = "C", T = "T", E = "E";
865cf428778SYitzhak Mandelbaum   testRule(makeRule(ifStmt(hasCondition(expr().bind(C)),
866cf428778SYitzhak Mandelbaum                            hasThen(stmt().bind(T)), hasElse(stmt().bind(E))),
867cf428778SYitzhak Mandelbaum                     flatten(changeTo(node(std::string(C)), cat("true")),
868cf428778SYitzhak Mandelbaum                             edit(changeTo(statement(std::string(T)),
869cf428778SYitzhak Mandelbaum                                           cat("{ /* then */ }"))),
870cf428778SYitzhak Mandelbaum                             editList({changeTo(statement(std::string(E)),
871cf428778SYitzhak Mandelbaum                                                cat("{ /* else */ }"))}))),
872cf428778SYitzhak Mandelbaum            Input, Expected);
873cf428778SYitzhak Mandelbaum }
874cf428778SYitzhak Mandelbaum 
8758369a9beSYitzhak Mandelbaum TEST_F(TransformerTest, OrderedRuleUnrelated) {
8768369a9beSYitzhak Mandelbaum   StringRef Flag = "flag";
8778369a9beSYitzhak Mandelbaum   RewriteRule FlagRule = makeRule(
8788369a9beSYitzhak Mandelbaum       cxxMemberCallExpr(on(expr(hasType(cxxRecordDecl(
8798369a9beSYitzhak Mandelbaum                                     hasName("proto::ProtoCommandLineFlag"))))
8808369a9beSYitzhak Mandelbaum                                .bind(Flag)),
8818369a9beSYitzhak Mandelbaum                         unless(callee(cxxMethodDecl(hasName("GetProto"))))),
882adcd0268SBenjamin Kramer       changeTo(node(std::string(Flag)), cat("PROTO")));
8838369a9beSYitzhak Mandelbaum 
8848369a9beSYitzhak Mandelbaum   std::string Input = R"cc(
8858369a9beSYitzhak Mandelbaum     proto::ProtoCommandLineFlag flag;
8868369a9beSYitzhak Mandelbaum     int x = flag.foo();
8878369a9beSYitzhak Mandelbaum     int y = flag.GetProto().foo();
8888369a9beSYitzhak Mandelbaum     int f(string s) { return strlen(s.c_str()); }
8898369a9beSYitzhak Mandelbaum   )cc";
8908369a9beSYitzhak Mandelbaum   std::string Expected = R"cc(
8918369a9beSYitzhak Mandelbaum     proto::ProtoCommandLineFlag flag;
8928369a9beSYitzhak Mandelbaum     int x = PROTO.foo();
8938369a9beSYitzhak Mandelbaum     int y = flag.GetProto().foo();
8948369a9beSYitzhak Mandelbaum     int f(string s) { return REPLACED; }
8958369a9beSYitzhak Mandelbaum   )cc";
8968369a9beSYitzhak Mandelbaum 
8978369a9beSYitzhak Mandelbaum   testRule(applyFirst({ruleStrlenSize(), FlagRule}), Input, Expected);
8988369a9beSYitzhak Mandelbaum }
8998369a9beSYitzhak Mandelbaum 
9008369a9beSYitzhak Mandelbaum TEST_F(TransformerTest, OrderedRuleRelated) {
9018369a9beSYitzhak Mandelbaum   std::string Input = R"cc(
90242b957aaSYitzhak Mandelbaum     void f1();
90342b957aaSYitzhak Mandelbaum     void f2();
90442b957aaSYitzhak Mandelbaum     void call_f1() { f1(); }
90542b957aaSYitzhak Mandelbaum     void call_f2() { f2(); }
9068369a9beSYitzhak Mandelbaum   )cc";
9078369a9beSYitzhak Mandelbaum   std::string Expected = R"cc(
90842b957aaSYitzhak Mandelbaum     void f1();
90942b957aaSYitzhak Mandelbaum     void f2();
91042b957aaSYitzhak Mandelbaum     void call_f1() { REPLACE_F1; }
91142b957aaSYitzhak Mandelbaum     void call_f2() { REPLACE_F1_OR_F2; }
9128369a9beSYitzhak Mandelbaum   )cc";
9138369a9beSYitzhak Mandelbaum 
91442b957aaSYitzhak Mandelbaum   RewriteRule ReplaceF1 =
91542b957aaSYitzhak Mandelbaum       makeRule(callExpr(callee(functionDecl(hasName("f1")))),
9169f97480cSYitzhak Mandelbaum                changeTo(cat("REPLACE_F1")));
91742b957aaSYitzhak Mandelbaum   RewriteRule ReplaceF1OrF2 =
91842b957aaSYitzhak Mandelbaum       makeRule(callExpr(callee(functionDecl(hasAnyName("f1", "f2")))),
9199f97480cSYitzhak Mandelbaum                changeTo(cat("REPLACE_F1_OR_F2")));
92042b957aaSYitzhak Mandelbaum   testRule(applyFirst({ReplaceF1, ReplaceF1OrF2}), Input, Expected);
9218369a9beSYitzhak Mandelbaum }
9228369a9beSYitzhak Mandelbaum 
92342b957aaSYitzhak Mandelbaum // Change the order of the rules to get a different result. When `ReplaceF1OrF2`
92442b957aaSYitzhak Mandelbaum // comes first, it applies for both uses, so `ReplaceF1` never applies.
9258369a9beSYitzhak Mandelbaum TEST_F(TransformerTest, OrderedRuleRelatedSwapped) {
9268369a9beSYitzhak Mandelbaum   std::string Input = R"cc(
92742b957aaSYitzhak Mandelbaum     void f1();
92842b957aaSYitzhak Mandelbaum     void f2();
92942b957aaSYitzhak Mandelbaum     void call_f1() { f1(); }
93042b957aaSYitzhak Mandelbaum     void call_f2() { f2(); }
9318369a9beSYitzhak Mandelbaum   )cc";
9328369a9beSYitzhak Mandelbaum   std::string Expected = R"cc(
93342b957aaSYitzhak Mandelbaum     void f1();
93442b957aaSYitzhak Mandelbaum     void f2();
93542b957aaSYitzhak Mandelbaum     void call_f1() { REPLACE_F1_OR_F2; }
93642b957aaSYitzhak Mandelbaum     void call_f2() { REPLACE_F1_OR_F2; }
9378369a9beSYitzhak Mandelbaum   )cc";
9388369a9beSYitzhak Mandelbaum 
93942b957aaSYitzhak Mandelbaum   RewriteRule ReplaceF1 =
94042b957aaSYitzhak Mandelbaum       makeRule(callExpr(callee(functionDecl(hasName("f1")))),
9419f97480cSYitzhak Mandelbaum                changeTo(cat("REPLACE_F1")));
94242b957aaSYitzhak Mandelbaum   RewriteRule ReplaceF1OrF2 =
94342b957aaSYitzhak Mandelbaum       makeRule(callExpr(callee(functionDecl(hasAnyName("f1", "f2")))),
9449f97480cSYitzhak Mandelbaum                changeTo(cat("REPLACE_F1_OR_F2")));
94542b957aaSYitzhak Mandelbaum   testRule(applyFirst({ReplaceF1OrF2, ReplaceF1}), Input, Expected);
94642b957aaSYitzhak Mandelbaum }
94742b957aaSYitzhak Mandelbaum 
94842b957aaSYitzhak Mandelbaum // Verify that a set of rules whose matchers have different base kinds works
94942b957aaSYitzhak Mandelbaum // properly, including that `applyFirst` produces multiple matchers.  We test
95042b957aaSYitzhak Mandelbaum // two different kinds of rules: Expr and Decl. We place the Decl rule in the
95142b957aaSYitzhak Mandelbaum // middle to test that `buildMatchers` works even when the kinds aren't grouped
95242b957aaSYitzhak Mandelbaum // together.
95342b957aaSYitzhak Mandelbaum TEST_F(TransformerTest, OrderedRuleMultipleKinds) {
95442b957aaSYitzhak Mandelbaum   std::string Input = R"cc(
95542b957aaSYitzhak Mandelbaum     void f1();
95642b957aaSYitzhak Mandelbaum     void f2();
95742b957aaSYitzhak Mandelbaum     void call_f1() { f1(); }
95842b957aaSYitzhak Mandelbaum     void call_f2() { f2(); }
95942b957aaSYitzhak Mandelbaum   )cc";
96042b957aaSYitzhak Mandelbaum   std::string Expected = R"cc(
96142b957aaSYitzhak Mandelbaum     void f1();
96242b957aaSYitzhak Mandelbaum     void DECL_RULE();
96342b957aaSYitzhak Mandelbaum     void call_f1() { REPLACE_F1; }
96442b957aaSYitzhak Mandelbaum     void call_f2() { REPLACE_F1_OR_F2; }
96542b957aaSYitzhak Mandelbaum   )cc";
96642b957aaSYitzhak Mandelbaum 
96742b957aaSYitzhak Mandelbaum   RewriteRule ReplaceF1 =
96842b957aaSYitzhak Mandelbaum       makeRule(callExpr(callee(functionDecl(hasName("f1")))),
9699f97480cSYitzhak Mandelbaum                changeTo(cat("REPLACE_F1")));
97042b957aaSYitzhak Mandelbaum   RewriteRule ReplaceF1OrF2 =
97142b957aaSYitzhak Mandelbaum       makeRule(callExpr(callee(functionDecl(hasAnyName("f1", "f2")))),
9729f97480cSYitzhak Mandelbaum                changeTo(cat("REPLACE_F1_OR_F2")));
97342b957aaSYitzhak Mandelbaum   RewriteRule DeclRule = makeRule(functionDecl(hasName("f2")).bind("fun"),
9749f97480cSYitzhak Mandelbaum                                   changeTo(name("fun"), cat("DECL_RULE")));
97542b957aaSYitzhak Mandelbaum 
97642b957aaSYitzhak Mandelbaum   RewriteRule Rule = applyFirst({ReplaceF1, DeclRule, ReplaceF1OrF2});
9778bb47cd8SYitzhak Mandelbaum   EXPECT_EQ(transformer::detail::buildMatchers(Rule).size(), 2UL);
97842b957aaSYitzhak Mandelbaum   testRule(Rule, Input, Expected);
9798369a9beSYitzhak Mandelbaum }
9808369a9beSYitzhak Mandelbaum 
981ce5780b8SYitzhak Mandelbaum // Verifies that a rule with a top-level matcher for an implicit node (like
9826f0a3711SYitzhak Mandelbaum // `implicitCastExpr`) works correctly -- the implicit nodes are not skipped.
983ce5780b8SYitzhak Mandelbaum TEST_F(TransformerTest, OrderedRuleImplicitMatched) {
984ce5780b8SYitzhak Mandelbaum   std::string Input = R"cc(
985ce5780b8SYitzhak Mandelbaum     void f1();
986ce5780b8SYitzhak Mandelbaum     int f2();
987ce5780b8SYitzhak Mandelbaum     void call_f1() { f1(); }
988ce5780b8SYitzhak Mandelbaum     float call_f2() { return f2(); }
989ce5780b8SYitzhak Mandelbaum   )cc";
990ce5780b8SYitzhak Mandelbaum   std::string Expected = R"cc(
991ce5780b8SYitzhak Mandelbaum     void f1();
992ce5780b8SYitzhak Mandelbaum     int f2();
993ce5780b8SYitzhak Mandelbaum     void call_f1() { REPLACE_F1; }
994ce5780b8SYitzhak Mandelbaum     float call_f2() { return REPLACE_F2; }
995ce5780b8SYitzhak Mandelbaum   )cc";
996ce5780b8SYitzhak Mandelbaum 
9976f0a3711SYitzhak Mandelbaum   RewriteRule ReplaceF1 =
9986f0a3711SYitzhak Mandelbaum       makeRule(callExpr(callee(functionDecl(hasName("f1")))),
999ce5780b8SYitzhak Mandelbaum                changeTo(cat("REPLACE_F1")));
1000ce5780b8SYitzhak Mandelbaum   RewriteRule ReplaceF2 =
10016f0a3711SYitzhak Mandelbaum       makeRule(implicitCastExpr(hasSourceExpression(callExpr())),
1002ce5780b8SYitzhak Mandelbaum                changeTo(cat("REPLACE_F2")));
1003ce5780b8SYitzhak Mandelbaum   testRule(applyFirst({ReplaceF1, ReplaceF2}), Input, Expected);
1004ce5780b8SYitzhak Mandelbaum }
1005ce5780b8SYitzhak Mandelbaum 
1006fdd98782SYitzhak Mandelbaum //
1007fdd98782SYitzhak Mandelbaum // Negative tests (where we expect no transformation to occur).
1008fdd98782SYitzhak Mandelbaum //
1009fdd98782SYitzhak Mandelbaum 
1010fa1552e8SYitzhak Mandelbaum // Tests for a conflict in edits from a single match for a rule.
1011aecc59c5SYitzhak Mandelbaum TEST_F(TransformerTest, TextGeneratorFailure) {
1012aecc59c5SYitzhak Mandelbaum   std::string Input = "int conflictOneRule() { return 3 + 7; }";
1013aecc59c5SYitzhak Mandelbaum   // Try to change the whole binary-operator expression AND one its operands:
1014aecc59c5SYitzhak Mandelbaum   StringRef O = "O";
1015489449c2SYitzhak Mandelbaum   class AlwaysFail : public transformer::MatchComputation<std::string> {
1016489449c2SYitzhak Mandelbaum     llvm::Error eval(const ast_matchers::MatchFinder::MatchResult &,
1017489449c2SYitzhak Mandelbaum                      std::string *) const override {
1018aecc59c5SYitzhak Mandelbaum       return llvm::createStringError(llvm::errc::invalid_argument, "ERROR");
1019489449c2SYitzhak Mandelbaum     }
1020489449c2SYitzhak Mandelbaum     std::string toString() const override { return "AlwaysFail"; }
1021aecc59c5SYitzhak Mandelbaum   };
1022adcd0268SBenjamin Kramer   Transformer T(
1023adcd0268SBenjamin Kramer       makeRule(binaryOperator().bind(O),
1024adcd0268SBenjamin Kramer                changeTo(node(std::string(O)), std::make_shared<AlwaysFail>())),
1025aecc59c5SYitzhak Mandelbaum       consumer());
1026aecc59c5SYitzhak Mandelbaum   T.registerMatchers(&MatchFinder);
1027aecc59c5SYitzhak Mandelbaum   EXPECT_FALSE(rewrite(Input));
1028aecc59c5SYitzhak Mandelbaum   EXPECT_THAT(Changes, IsEmpty());
1029aecc59c5SYitzhak Mandelbaum   EXPECT_EQ(ErrorCount, 1);
1030aecc59c5SYitzhak Mandelbaum }
1031aecc59c5SYitzhak Mandelbaum 
1032aecc59c5SYitzhak Mandelbaum // Tests for a conflict in edits from a single match for a rule.
1033fa1552e8SYitzhak Mandelbaum TEST_F(TransformerTest, OverlappingEditsInRule) {
1034fa1552e8SYitzhak Mandelbaum   std::string Input = "int conflictOneRule() { return 3 + 7; }";
1035fa1552e8SYitzhak Mandelbaum   // Try to change the whole binary-operator expression AND one its operands:
1036fa1552e8SYitzhak Mandelbaum   StringRef O = "O", L = "L";
10373ec50e29SYitzhak Mandelbaum   Transformer T(makeRule(binaryOperator(hasLHS(expr().bind(L))).bind(O),
1038adcd0268SBenjamin Kramer                          {changeTo(node(std::string(O)), cat("DELETE_OP")),
1039adcd0268SBenjamin Kramer                           changeTo(node(std::string(L)), cat("DELETE_LHS"))}),
1040aecc59c5SYitzhak Mandelbaum                 consumer());
1041fa1552e8SYitzhak Mandelbaum   T.registerMatchers(&MatchFinder);
1042aecc59c5SYitzhak Mandelbaum   EXPECT_FALSE(rewrite(Input));
1043aecc59c5SYitzhak Mandelbaum   EXPECT_THAT(Changes, IsEmpty());
1044aecc59c5SYitzhak Mandelbaum   EXPECT_EQ(ErrorCount, 1);
1045fa1552e8SYitzhak Mandelbaum }
1046fa1552e8SYitzhak Mandelbaum 
1047fa1552e8SYitzhak Mandelbaum // Tests for a conflict in edits across multiple matches (of the same rule).
1048fa1552e8SYitzhak Mandelbaum TEST_F(TransformerTest, OverlappingEditsMultipleMatches) {
1049fa1552e8SYitzhak Mandelbaum   std::string Input = "int conflictOneRule() { return -7; }";
1050fa1552e8SYitzhak Mandelbaum   // Try to change the whole binary-operator expression AND one its operands:
1051fa1552e8SYitzhak Mandelbaum   StringRef E = "E";
1052adcd0268SBenjamin Kramer   Transformer T(makeRule(expr().bind(E),
1053adcd0268SBenjamin Kramer                          changeTo(node(std::string(E)), cat("DELETE_EXPR"))),
1054aecc59c5SYitzhak Mandelbaum                 consumer());
1055fa1552e8SYitzhak Mandelbaum   T.registerMatchers(&MatchFinder);
1056fa1552e8SYitzhak Mandelbaum   // The rewrite process fails because the changes conflict with each other...
1057fa1552e8SYitzhak Mandelbaum   EXPECT_FALSE(rewrite(Input));
1058aecc59c5SYitzhak Mandelbaum   // ... but two changes were produced.
1059aecc59c5SYitzhak Mandelbaum   EXPECT_EQ(Changes.size(), 2u);
1060aecc59c5SYitzhak Mandelbaum   EXPECT_EQ(ErrorCount, 0);
1061fa1552e8SYitzhak Mandelbaum }
1062fa1552e8SYitzhak Mandelbaum 
1063fa1552e8SYitzhak Mandelbaum TEST_F(TransformerTest, ErrorOccurredMatchSkipped) {
1064fa1552e8SYitzhak Mandelbaum   // Syntax error in the function body:
1065fa1552e8SYitzhak Mandelbaum   std::string Input = "void errorOccurred() { 3 }";
1066aecc59c5SYitzhak Mandelbaum   Transformer T(makeRule(functionDecl(hasName("errorOccurred")),
10679f97480cSYitzhak Mandelbaum                          changeTo(cat("DELETED;"))),
1068aecc59c5SYitzhak Mandelbaum                 consumer());
1069fa1552e8SYitzhak Mandelbaum   T.registerMatchers(&MatchFinder);
1070fa1552e8SYitzhak Mandelbaum   // The rewrite process itself fails...
1071fa1552e8SYitzhak Mandelbaum   EXPECT_FALSE(rewrite(Input));
1072aecc59c5SYitzhak Mandelbaum   // ... and no changes or errors are produced in the process.
1073aecc59c5SYitzhak Mandelbaum   EXPECT_THAT(Changes, IsEmpty());
1074aecc59c5SYitzhak Mandelbaum   EXPECT_EQ(ErrorCount, 0);
1075fa1552e8SYitzhak Mandelbaum }
1076fa1552e8SYitzhak Mandelbaum 
1077246b428fSStephen Kelly TEST_F(TransformerTest, ImplicitNodes_ConstructorDecl) {
1078246b428fSStephen Kelly 
1079246b428fSStephen Kelly   std::string OtherStructPrefix = R"cpp(
1080246b428fSStephen Kelly struct Other {
1081246b428fSStephen Kelly )cpp";
1082246b428fSStephen Kelly   std::string OtherStructSuffix = "};";
1083246b428fSStephen Kelly 
1084246b428fSStephen Kelly   std::string CopyableStructName = "struct Copyable";
1085246b428fSStephen Kelly   std::string BrokenStructName = "struct explicit Copyable";
1086246b428fSStephen Kelly 
1087246b428fSStephen Kelly   std::string CodeSuffix = R"cpp(
1088246b428fSStephen Kelly {
1089246b428fSStephen Kelly     Other m_i;
1090246b428fSStephen Kelly     Copyable();
1091246b428fSStephen Kelly };
1092246b428fSStephen Kelly )cpp";
1093246b428fSStephen Kelly 
1094246b428fSStephen Kelly   std::string CopyCtor = "Other(const Other&) = default;";
1095246b428fSStephen Kelly   std::string ExplicitCopyCtor = "explicit Other(const Other&) = default;";
1096246b428fSStephen Kelly   std::string BrokenExplicitCopyCtor =
1097246b428fSStephen Kelly       "explicit explicit explicit Other(const Other&) = default;";
1098246b428fSStephen Kelly 
1099246b428fSStephen Kelly   std::string RewriteInput = OtherStructPrefix + CopyCtor + OtherStructSuffix +
1100246b428fSStephen Kelly                              CopyableStructName + CodeSuffix;
1101246b428fSStephen Kelly   std::string ExpectedRewriteOutput = OtherStructPrefix + ExplicitCopyCtor +
1102246b428fSStephen Kelly                                       OtherStructSuffix + CopyableStructName +
1103246b428fSStephen Kelly                                       CodeSuffix;
1104246b428fSStephen Kelly   std::string BrokenRewriteOutput = OtherStructPrefix + BrokenExplicitCopyCtor +
1105246b428fSStephen Kelly                                     OtherStructSuffix + BrokenStructName +
1106246b428fSStephen Kelly                                     CodeSuffix;
1107246b428fSStephen Kelly 
1108246b428fSStephen Kelly   auto MatchedRecord =
1109246b428fSStephen Kelly       cxxConstructorDecl(isCopyConstructor()).bind("copyConstructor");
1110246b428fSStephen Kelly 
1111246b428fSStephen Kelly   auto RewriteRule =
1112246b428fSStephen Kelly       changeTo(before(node("copyConstructor")), cat("explicit "));
1113246b428fSStephen Kelly 
1114246b428fSStephen Kelly   testRule(makeRule(traverse(TK_IgnoreUnlessSpelledInSource, MatchedRecord),
1115246b428fSStephen Kelly                     RewriteRule),
1116246b428fSStephen Kelly            RewriteInput, ExpectedRewriteOutput);
1117246b428fSStephen Kelly 
1118246b428fSStephen Kelly   testRule(makeRule(traverse(TK_AsIs, MatchedRecord), RewriteRule),
1119246b428fSStephen Kelly            RewriteInput, BrokenRewriteOutput);
1120246b428fSStephen Kelly }
1121246b428fSStephen Kelly 
1122246b428fSStephen Kelly TEST_F(TransformerTest, ImplicitNodes_RangeFor) {
1123246b428fSStephen Kelly 
1124246b428fSStephen Kelly   std::string CodePrefix = R"cpp(
1125246b428fSStephen Kelly struct Container
1126246b428fSStephen Kelly {
1127246b428fSStephen Kelly     int* begin() const;
1128246b428fSStephen Kelly     int* end() const;
1129246b428fSStephen Kelly     int* cbegin() const;
1130246b428fSStephen Kelly     int* cend() const;
1131246b428fSStephen Kelly };
1132246b428fSStephen Kelly 
1133246b428fSStephen Kelly void foo()
1134246b428fSStephen Kelly {
1135246b428fSStephen Kelly   const Container c;
1136246b428fSStephen Kelly )cpp";
1137246b428fSStephen Kelly 
1138246b428fSStephen Kelly   std::string BeginCallBefore = "  c.begin();";
1139246b428fSStephen Kelly   std::string BeginCallAfter = "  c.cbegin();";
1140246b428fSStephen Kelly 
1141246b428fSStephen Kelly   std::string ForLoop = "for (auto i : c)";
1142246b428fSStephen Kelly   std::string BrokenForLoop = "for (auto i :.cbegin() c)";
1143246b428fSStephen Kelly 
1144246b428fSStephen Kelly   std::string CodeSuffix = R"cpp(
1145246b428fSStephen Kelly   {
1146246b428fSStephen Kelly   }
1147246b428fSStephen Kelly }
1148246b428fSStephen Kelly )cpp";
1149246b428fSStephen Kelly 
1150246b428fSStephen Kelly   std::string RewriteInput =
1151246b428fSStephen Kelly       CodePrefix + BeginCallBefore + ForLoop + CodeSuffix;
1152246b428fSStephen Kelly   std::string ExpectedRewriteOutput =
1153246b428fSStephen Kelly       CodePrefix + BeginCallAfter + ForLoop + CodeSuffix;
1154246b428fSStephen Kelly   std::string BrokenRewriteOutput =
1155246b428fSStephen Kelly       CodePrefix + BeginCallAfter + BrokenForLoop + CodeSuffix;
1156246b428fSStephen Kelly 
1157246b428fSStephen Kelly   auto MatchedRecord =
1158246b428fSStephen Kelly       cxxMemberCallExpr(on(expr(hasType(qualType(isConstQualified(),
1159246b428fSStephen Kelly                                                  hasDeclaration(cxxRecordDecl(
1160246b428fSStephen Kelly                                                      hasName("Container"))))))
1161246b428fSStephen Kelly                                .bind("callTarget")),
1162246b428fSStephen Kelly                         callee(cxxMethodDecl(hasName("begin"))))
1163246b428fSStephen Kelly           .bind("constBeginCall");
1164246b428fSStephen Kelly 
1165246b428fSStephen Kelly   auto RewriteRule =
1166246b428fSStephen Kelly       changeTo(node("constBeginCall"), cat(name("callTarget"), ".cbegin()"));
1167246b428fSStephen Kelly 
1168246b428fSStephen Kelly   testRule(makeRule(traverse(TK_IgnoreUnlessSpelledInSource, MatchedRecord),
1169246b428fSStephen Kelly                     RewriteRule),
1170246b428fSStephen Kelly            RewriteInput, ExpectedRewriteOutput);
1171246b428fSStephen Kelly 
1172246b428fSStephen Kelly   testRule(makeRule(traverse(TK_AsIs, MatchedRecord), RewriteRule),
1173246b428fSStephen Kelly            RewriteInput, BrokenRewriteOutput);
1174246b428fSStephen Kelly }
1175246b428fSStephen Kelly 
1176246b428fSStephen Kelly TEST_F(TransformerTest, ImplicitNodes_ForStmt) {
1177246b428fSStephen Kelly 
1178246b428fSStephen Kelly   std::string CodePrefix = R"cpp(
1179246b428fSStephen Kelly struct NonTrivial {
1180246b428fSStephen Kelly     NonTrivial() {}
1181246b428fSStephen Kelly     NonTrivial(NonTrivial&) {}
1182246b428fSStephen Kelly     NonTrivial& operator=(NonTrivial const&) { return *this; }
1183246b428fSStephen Kelly 
1184246b428fSStephen Kelly     ~NonTrivial() {}
1185246b428fSStephen Kelly };
1186246b428fSStephen Kelly 
1187246b428fSStephen Kelly struct ContainsArray {
1188246b428fSStephen Kelly     NonTrivial arr[2];
1189246b428fSStephen Kelly     ContainsArray& operator=(ContainsArray const&) = default;
1190246b428fSStephen Kelly };
1191246b428fSStephen Kelly 
1192246b428fSStephen Kelly void testIt()
1193246b428fSStephen Kelly {
1194246b428fSStephen Kelly     ContainsArray ca1;
1195246b428fSStephen Kelly     ContainsArray ca2;
1196246b428fSStephen Kelly     ca2 = ca1;
1197246b428fSStephen Kelly )cpp";
1198246b428fSStephen Kelly 
1199246b428fSStephen Kelly   auto CodeSuffix = "}";
1200246b428fSStephen Kelly 
1201246b428fSStephen Kelly   auto LoopBody = R"cpp(
1202246b428fSStephen Kelly     {
1203246b428fSStephen Kelly 
1204246b428fSStephen Kelly     }
1205246b428fSStephen Kelly )cpp";
1206246b428fSStephen Kelly 
1207246b428fSStephen Kelly   auto RawLoop = "for (auto i = 0; i != 5; ++i)";
1208246b428fSStephen Kelly 
1209246b428fSStephen Kelly   auto RangeLoop = "for (auto i : boost::irange(5))";
1210246b428fSStephen Kelly 
1211246b428fSStephen Kelly   // Expect to rewrite the raw loop to the ranged loop.
1212246b428fSStephen Kelly   // This works in TK_IgnoreUnlessSpelledInSource mode, but TK_AsIs
1213246b428fSStephen Kelly   // mode also matches the hidden for loop generated in the copy assignment
1214246b428fSStephen Kelly   // operator of ContainsArray. Transformer then fails to transform the code at
1215246b428fSStephen Kelly   // all.
1216246b428fSStephen Kelly 
1217246b428fSStephen Kelly   auto RewriteInput =
1218246b428fSStephen Kelly       CodePrefix + RawLoop + LoopBody + RawLoop + LoopBody + CodeSuffix;
1219246b428fSStephen Kelly 
1220246b428fSStephen Kelly   auto RewriteOutput =
1221246b428fSStephen Kelly       CodePrefix + RangeLoop + LoopBody + RangeLoop + LoopBody + CodeSuffix;
1222246b428fSStephen Kelly   {
1223246b428fSStephen Kelly     auto MatchedLoop = forStmt(
1224246b428fSStephen Kelly         has(declStmt(
1225246b428fSStephen Kelly             hasSingleDecl(varDecl(hasInitializer(integerLiteral(equals(0))))
1226246b428fSStephen Kelly                               .bind("loopVar")))),
1227246b428fSStephen Kelly         has(binaryOperator(hasOperatorName("!="),
1228246b428fSStephen Kelly                            hasLHS(ignoringImplicit(declRefExpr(
1229246b428fSStephen Kelly                                to(varDecl(equalsBoundNode("loopVar")))))),
1230246b428fSStephen Kelly                            hasRHS(expr().bind("upperBoundExpr")))),
1231246b428fSStephen Kelly         has(unaryOperator(hasOperatorName("++"),
1232246b428fSStephen Kelly                           hasUnaryOperand(declRefExpr(
1233246b428fSStephen Kelly                               to(varDecl(equalsBoundNode("loopVar"))))))
1234246b428fSStephen Kelly                 .bind("incrementOp")));
1235246b428fSStephen Kelly 
1236246b428fSStephen Kelly     auto RewriteRule =
1237246b428fSStephen Kelly         changeTo(transformer::enclose(node("loopVar"), node("incrementOp")),
1238246b428fSStephen Kelly                  cat("auto ", name("loopVar"), " : boost::irange(",
1239246b428fSStephen Kelly                      node("upperBoundExpr"), ")"));
1240246b428fSStephen Kelly 
1241246b428fSStephen Kelly     testRule(makeRule(traverse(TK_IgnoreUnlessSpelledInSource, MatchedLoop),
1242246b428fSStephen Kelly                       RewriteRule),
1243246b428fSStephen Kelly              RewriteInput, RewriteOutput);
1244246b428fSStephen Kelly 
1245246b428fSStephen Kelly     testRuleFailure(makeRule(traverse(TK_AsIs, MatchedLoop), RewriteRule),
1246246b428fSStephen Kelly                     RewriteInput);
1247246b428fSStephen Kelly   }
1248*4cadb66bSStephen Kelly   {
1249*4cadb66bSStephen Kelly     auto MatchedLoop = forStmt(
1250*4cadb66bSStephen Kelly         hasLoopInit(declStmt(
1251*4cadb66bSStephen Kelly             hasSingleDecl(varDecl(hasInitializer(integerLiteral(equals(0))))
1252*4cadb66bSStephen Kelly                               .bind("loopVar")))),
1253*4cadb66bSStephen Kelly         hasCondition(binaryOperator(hasOperatorName("!="),
1254*4cadb66bSStephen Kelly                                     hasLHS(ignoringImplicit(declRefExpr(to(
1255*4cadb66bSStephen Kelly                                         varDecl(equalsBoundNode("loopVar")))))),
1256*4cadb66bSStephen Kelly                                     hasRHS(expr().bind("upperBoundExpr")))),
1257*4cadb66bSStephen Kelly         hasIncrement(unaryOperator(hasOperatorName("++"),
1258*4cadb66bSStephen Kelly                                    hasUnaryOperand(declRefExpr(to(
1259*4cadb66bSStephen Kelly                                        varDecl(equalsBoundNode("loopVar"))))))
1260*4cadb66bSStephen Kelly                          .bind("incrementOp")));
1261*4cadb66bSStephen Kelly 
1262*4cadb66bSStephen Kelly     auto RewriteRule =
1263*4cadb66bSStephen Kelly         changeTo(transformer::enclose(node("loopVar"), node("incrementOp")),
1264*4cadb66bSStephen Kelly                  cat("auto ", name("loopVar"), " : boost::irange(",
1265*4cadb66bSStephen Kelly                      node("upperBoundExpr"), ")"));
1266*4cadb66bSStephen Kelly 
1267*4cadb66bSStephen Kelly     testRule(makeRule(traverse(TK_IgnoreUnlessSpelledInSource, MatchedLoop),
1268*4cadb66bSStephen Kelly                       RewriteRule),
1269*4cadb66bSStephen Kelly              RewriteInput, RewriteOutput);
1270*4cadb66bSStephen Kelly 
1271*4cadb66bSStephen Kelly     testRuleFailure(makeRule(traverse(TK_AsIs, MatchedLoop), RewriteRule),
1272*4cadb66bSStephen Kelly                     RewriteInput);
1273*4cadb66bSStephen Kelly   }
1274246b428fSStephen Kelly }
1275246b428fSStephen Kelly 
1276a6d15d40SMatt Morehouse TEST_F(TransformerTest, TemplateInstantiation) {
1277a6d15d40SMatt Morehouse 
1278a6d15d40SMatt Morehouse   std::string NonTemplatesInput = R"cpp(
1279a6d15d40SMatt Morehouse struct S {
1280a6d15d40SMatt Morehouse   int m_i;
1281a6d15d40SMatt Morehouse };
1282a6d15d40SMatt Morehouse )cpp";
1283a6d15d40SMatt Morehouse   std::string NonTemplatesExpected = R"cpp(
1284a6d15d40SMatt Morehouse struct S {
1285a6d15d40SMatt Morehouse   safe_int m_i;
1286a6d15d40SMatt Morehouse };
1287a6d15d40SMatt Morehouse )cpp";
1288a6d15d40SMatt Morehouse 
1289a6d15d40SMatt Morehouse   std::string TemplatesInput = R"cpp(
1290a6d15d40SMatt Morehouse template<typename T>
1291a6d15d40SMatt Morehouse struct TemplStruct {
1292a6d15d40SMatt Morehouse   TemplStruct() {}
1293a6d15d40SMatt Morehouse   ~TemplStruct() {}
1294a6d15d40SMatt Morehouse 
1295a6d15d40SMatt Morehouse private:
1296a6d15d40SMatt Morehouse   T m_t;
1297a6d15d40SMatt Morehouse };
1298a6d15d40SMatt Morehouse 
1299a6d15d40SMatt Morehouse void instantiate()
1300a6d15d40SMatt Morehouse {
1301a6d15d40SMatt Morehouse   TemplStruct<int> ti;
1302a6d15d40SMatt Morehouse }
1303a6d15d40SMatt Morehouse )cpp";
1304a6d15d40SMatt Morehouse 
1305a6d15d40SMatt Morehouse   auto MatchedField = fieldDecl(hasType(asString("int"))).bind("theField");
1306a6d15d40SMatt Morehouse 
1307a6d15d40SMatt Morehouse   // Changes the 'int' in 'S', but not the 'T' in 'TemplStruct':
1308a6d15d40SMatt Morehouse   testRule(makeRule(traverse(TK_IgnoreUnlessSpelledInSource, MatchedField),
1309a6d15d40SMatt Morehouse                     changeTo(cat("safe_int ", name("theField")))),
1310a6d15d40SMatt Morehouse            NonTemplatesInput + TemplatesInput,
1311a6d15d40SMatt Morehouse            NonTemplatesExpected + TemplatesInput);
1312a6d15d40SMatt Morehouse 
1313a6d15d40SMatt Morehouse   // In AsIs mode, template instantiations are modified, which is
1314a6d15d40SMatt Morehouse   // often not desired:
1315a6d15d40SMatt Morehouse 
1316a6d15d40SMatt Morehouse   std::string IncorrectTemplatesExpected = R"cpp(
1317a6d15d40SMatt Morehouse template<typename T>
1318a6d15d40SMatt Morehouse struct TemplStruct {
1319a6d15d40SMatt Morehouse   TemplStruct() {}
1320a6d15d40SMatt Morehouse   ~TemplStruct() {}
1321a6d15d40SMatt Morehouse 
1322a6d15d40SMatt Morehouse private:
1323a6d15d40SMatt Morehouse   safe_int m_t;
1324a6d15d40SMatt Morehouse };
1325a6d15d40SMatt Morehouse 
1326a6d15d40SMatt Morehouse void instantiate()
1327a6d15d40SMatt Morehouse {
1328a6d15d40SMatt Morehouse   TemplStruct<int> ti;
1329a6d15d40SMatt Morehouse }
1330a6d15d40SMatt Morehouse )cpp";
1331a6d15d40SMatt Morehouse 
1332a6d15d40SMatt Morehouse   // Changes the 'int' in 'S', and (incorrectly) the 'T' in 'TemplStruct':
1333a6d15d40SMatt Morehouse   testRule(makeRule(traverse(TK_AsIs, MatchedField),
1334a6d15d40SMatt Morehouse                     changeTo(cat("safe_int ", name("theField")))),
1335a6d15d40SMatt Morehouse 
1336a6d15d40SMatt Morehouse            NonTemplatesInput + TemplatesInput,
1337a6d15d40SMatt Morehouse            NonTemplatesExpected + IncorrectTemplatesExpected);
1338a6d15d40SMatt Morehouse }
1339a6d15d40SMatt Morehouse 
13403f1ab737SYitzhak Mandelbaum // Transformation of macro source text when the change encompasses the entirety
13413f1ab737SYitzhak Mandelbaum // of the expanded text.
13423f1ab737SYitzhak Mandelbaum TEST_F(TransformerTest, SimpleMacro) {
1343fdd98782SYitzhak Mandelbaum   std::string Input = R"cc(
13443f1ab737SYitzhak Mandelbaum #define ZERO 0
13453f1ab737SYitzhak Mandelbaum     int f(string s) { return ZERO; }
13463f1ab737SYitzhak Mandelbaum   )cc";
13473f1ab737SYitzhak Mandelbaum   std::string Expected = R"cc(
13483f1ab737SYitzhak Mandelbaum #define ZERO 0
13493f1ab737SYitzhak Mandelbaum     int f(string s) { return 999; }
13503f1ab737SYitzhak Mandelbaum   )cc";
13513f1ab737SYitzhak Mandelbaum 
13523f1ab737SYitzhak Mandelbaum   StringRef zero = "zero";
13533f1ab737SYitzhak Mandelbaum   RewriteRule R = makeRule(integerLiteral(equals(0)).bind(zero),
1354adcd0268SBenjamin Kramer                            changeTo(node(std::string(zero)), cat("999")));
13553f1ab737SYitzhak Mandelbaum   testRule(R, Input, Expected);
1356fdd98782SYitzhak Mandelbaum }
1357fdd98782SYitzhak Mandelbaum 
13583f1ab737SYitzhak Mandelbaum // Transformation of macro source text when the change encompasses the entirety
13593f1ab737SYitzhak Mandelbaum // of the expanded text, for the case of function-style macros.
13603f1ab737SYitzhak Mandelbaum TEST_F(TransformerTest, FunctionMacro) {
13613f1ab737SYitzhak Mandelbaum   std::string Input = R"cc(
13623f1ab737SYitzhak Mandelbaum #define MACRO(str) strlen((str).c_str())
13633f1ab737SYitzhak Mandelbaum     int f(string s) { return MACRO(s); }
13643f1ab737SYitzhak Mandelbaum   )cc";
13653f1ab737SYitzhak Mandelbaum   std::string Expected = R"cc(
13663f1ab737SYitzhak Mandelbaum #define MACRO(str) strlen((str).c_str())
13673f1ab737SYitzhak Mandelbaum     int f(string s) { return REPLACED; }
13683f1ab737SYitzhak Mandelbaum   )cc";
13693f1ab737SYitzhak Mandelbaum 
13703f1ab737SYitzhak Mandelbaum   testRule(ruleStrlenSize(), Input, Expected);
13713f1ab737SYitzhak Mandelbaum }
13723f1ab737SYitzhak Mandelbaum 
13733f1ab737SYitzhak Mandelbaum // Tests that expressions in macro arguments can be rewritten.
13743f1ab737SYitzhak Mandelbaum TEST_F(TransformerTest, MacroArg) {
13753f1ab737SYitzhak Mandelbaum   std::string Input = R"cc(
13763f1ab737SYitzhak Mandelbaum #define PLUS(e) e + 1
13773f1ab737SYitzhak Mandelbaum     int f(string s) { return PLUS(strlen(s.c_str())); }
13783f1ab737SYitzhak Mandelbaum   )cc";
13793f1ab737SYitzhak Mandelbaum   std::string Expected = R"cc(
13803f1ab737SYitzhak Mandelbaum #define PLUS(e) e + 1
13813f1ab737SYitzhak Mandelbaum     int f(string s) { return PLUS(REPLACED); }
13823f1ab737SYitzhak Mandelbaum   )cc";
13833f1ab737SYitzhak Mandelbaum 
13843f1ab737SYitzhak Mandelbaum   testRule(ruleStrlenSize(), Input, Expected);
13853f1ab737SYitzhak Mandelbaum }
13863f1ab737SYitzhak Mandelbaum 
13873f1ab737SYitzhak Mandelbaum // Tests that expressions in macro arguments can be rewritten, even when the
13883f1ab737SYitzhak Mandelbaum // macro call occurs inside another macro's definition.
13893f1ab737SYitzhak Mandelbaum TEST_F(TransformerTest, MacroArgInMacroDef) {
1390fdd98782SYitzhak Mandelbaum   std::string Input = R"cc(
1391fdd98782SYitzhak Mandelbaum #define NESTED(e) e
1392fdd98782SYitzhak Mandelbaum #define MACRO(str) NESTED(strlen((str).c_str()))
13933f1ab737SYitzhak Mandelbaum     int f(string s) { return MACRO(s); }
13943f1ab737SYitzhak Mandelbaum   )cc";
13953f1ab737SYitzhak Mandelbaum   std::string Expected = R"cc(
13963f1ab737SYitzhak Mandelbaum #define NESTED(e) e
13973f1ab737SYitzhak Mandelbaum #define MACRO(str) NESTED(strlen((str).c_str()))
13983f1ab737SYitzhak Mandelbaum     int f(string s) { return REPLACED; }
13993f1ab737SYitzhak Mandelbaum   )cc";
14003f1ab737SYitzhak Mandelbaum 
14013f1ab737SYitzhak Mandelbaum   testRule(ruleStrlenSize(), Input, Expected);
14023f1ab737SYitzhak Mandelbaum }
14033f1ab737SYitzhak Mandelbaum 
14043f1ab737SYitzhak Mandelbaum // Tests the corner case of the identity macro, specifically that it is
14053f1ab737SYitzhak Mandelbaum // discarded in the rewrite rather than preserved (like PLUS is preserved in the
14063f1ab737SYitzhak Mandelbaum // previous test).  This behavior is of dubious value (and marked with a FIXME
14073f1ab737SYitzhak Mandelbaum // in the code), but we test it to verify (and demonstrate) how this case is
14083f1ab737SYitzhak Mandelbaum // handled.
14093f1ab737SYitzhak Mandelbaum TEST_F(TransformerTest, IdentityMacro) {
14103f1ab737SYitzhak Mandelbaum   std::string Input = R"cc(
14113f1ab737SYitzhak Mandelbaum #define ID(e) e
14123f1ab737SYitzhak Mandelbaum     int f(string s) { return ID(strlen(s.c_str())); }
14133f1ab737SYitzhak Mandelbaum   )cc";
14143f1ab737SYitzhak Mandelbaum   std::string Expected = R"cc(
14153f1ab737SYitzhak Mandelbaum #define ID(e) e
14163f1ab737SYitzhak Mandelbaum     int f(string s) { return REPLACED; }
14173f1ab737SYitzhak Mandelbaum   )cc";
14183f1ab737SYitzhak Mandelbaum 
14193f1ab737SYitzhak Mandelbaum   testRule(ruleStrlenSize(), Input, Expected);
14203f1ab737SYitzhak Mandelbaum }
14213f1ab737SYitzhak Mandelbaum 
1422db24ef50SYitzhak Mandelbaum // Tests that two changes in a single macro expansion do not lead to conflicts
1423db24ef50SYitzhak Mandelbaum // in applying the changes.
1424db24ef50SYitzhak Mandelbaum TEST_F(TransformerTest, TwoChangesInOneMacroExpansion) {
1425db24ef50SYitzhak Mandelbaum   std::string Input = R"cc(
1426db24ef50SYitzhak Mandelbaum #define PLUS(a,b) (a) + (b)
1427db24ef50SYitzhak Mandelbaum     int f() { return PLUS(3, 4); }
1428db24ef50SYitzhak Mandelbaum   )cc";
1429db24ef50SYitzhak Mandelbaum   std::string Expected = R"cc(
1430db24ef50SYitzhak Mandelbaum #define PLUS(a,b) (a) + (b)
1431db24ef50SYitzhak Mandelbaum     int f() { return PLUS(LIT, LIT); }
1432db24ef50SYitzhak Mandelbaum   )cc";
1433db24ef50SYitzhak Mandelbaum 
14349f97480cSYitzhak Mandelbaum   testRule(makeRule(integerLiteral(), changeTo(cat("LIT"))), Input, Expected);
1435db24ef50SYitzhak Mandelbaum }
1436db24ef50SYitzhak Mandelbaum 
1437db24ef50SYitzhak Mandelbaum // Tests case where the rule's match spans both source from the macro and its
1438db24ef50SYitzhak Mandelbaum // arg, with the begin location (the "anchor") being the arg.
1439db24ef50SYitzhak Mandelbaum TEST_F(TransformerTest, MatchSpansMacroTextButChangeDoesNot) {
1440db24ef50SYitzhak Mandelbaum   std::string Input = R"cc(
1441db24ef50SYitzhak Mandelbaum #define PLUS_ONE(a) a + 1
1442db24ef50SYitzhak Mandelbaum     int f() { return PLUS_ONE(3); }
1443db24ef50SYitzhak Mandelbaum   )cc";
1444db24ef50SYitzhak Mandelbaum   std::string Expected = R"cc(
1445db24ef50SYitzhak Mandelbaum #define PLUS_ONE(a) a + 1
1446db24ef50SYitzhak Mandelbaum     int f() { return PLUS_ONE(LIT); }
1447db24ef50SYitzhak Mandelbaum   )cc";
1448db24ef50SYitzhak Mandelbaum 
1449db24ef50SYitzhak Mandelbaum   StringRef E = "expr";
1450db24ef50SYitzhak Mandelbaum   testRule(makeRule(binaryOperator(hasLHS(expr().bind(E))),
1451adcd0268SBenjamin Kramer                     changeTo(node(std::string(E)), cat("LIT"))),
1452db24ef50SYitzhak Mandelbaum            Input, Expected);
1453db24ef50SYitzhak Mandelbaum }
1454db24ef50SYitzhak Mandelbaum 
1455db24ef50SYitzhak Mandelbaum // Tests case where the rule's match spans both source from the macro and its
1456db24ef50SYitzhak Mandelbaum // arg, with the begin location (the "anchor") being inside the macro.
1457db24ef50SYitzhak Mandelbaum TEST_F(TransformerTest, MatchSpansMacroTextButChangeDoesNotAnchoredInMacro) {
1458db24ef50SYitzhak Mandelbaum   std::string Input = R"cc(
1459db24ef50SYitzhak Mandelbaum #define PLUS_ONE(a) 1 + a
1460db24ef50SYitzhak Mandelbaum     int f() { return PLUS_ONE(3); }
1461db24ef50SYitzhak Mandelbaum   )cc";
1462db24ef50SYitzhak Mandelbaum   std::string Expected = R"cc(
1463db24ef50SYitzhak Mandelbaum #define PLUS_ONE(a) 1 + a
1464db24ef50SYitzhak Mandelbaum     int f() { return PLUS_ONE(LIT); }
1465db24ef50SYitzhak Mandelbaum   )cc";
1466db24ef50SYitzhak Mandelbaum 
1467db24ef50SYitzhak Mandelbaum   StringRef E = "expr";
1468db24ef50SYitzhak Mandelbaum   testRule(makeRule(binaryOperator(hasRHS(expr().bind(E))),
1469adcd0268SBenjamin Kramer                     changeTo(node(std::string(E)), cat("LIT"))),
1470db24ef50SYitzhak Mandelbaum            Input, Expected);
1471db24ef50SYitzhak Mandelbaum }
1472db24ef50SYitzhak Mandelbaum 
14733f1ab737SYitzhak Mandelbaum // No rewrite is applied when the changed text does not encompass the entirety
14743f1ab737SYitzhak Mandelbaum // of the expanded text. That is, the edit would have to be applied to the
14753f1ab737SYitzhak Mandelbaum // macro's definition to succeed and editing the expansion point would not
14763f1ab737SYitzhak Mandelbaum // suffice.
14773f1ab737SYitzhak Mandelbaum TEST_F(TransformerTest, NoPartialRewriteOMacroExpansion) {
14783f1ab737SYitzhak Mandelbaum   std::string Input = R"cc(
14793f1ab737SYitzhak Mandelbaum #define ZERO_PLUS 0 + 3
14803f1ab737SYitzhak Mandelbaum     int f(string s) { return ZERO_PLUS; })cc";
14813f1ab737SYitzhak Mandelbaum 
14823f1ab737SYitzhak Mandelbaum   StringRef zero = "zero";
14833f1ab737SYitzhak Mandelbaum   RewriteRule R = makeRule(integerLiteral(equals(0)).bind(zero),
1484adcd0268SBenjamin Kramer                            changeTo(node(std::string(zero)), cat("0")));
14853f1ab737SYitzhak Mandelbaum   testRule(R, Input, Input);
14863f1ab737SYitzhak Mandelbaum }
14873f1ab737SYitzhak Mandelbaum 
14883f1ab737SYitzhak Mandelbaum // This test handles the corner case where a macro expands within another macro
14893f1ab737SYitzhak Mandelbaum // to matching code, but that code is an argument to the nested macro call.  A
14903f1ab737SYitzhak Mandelbaum // simple check of isMacroArgExpansion() vs. isMacroBodyExpansion() will get
14913f1ab737SYitzhak Mandelbaum // this wrong, and transform the code.
14923f1ab737SYitzhak Mandelbaum TEST_F(TransformerTest, NoPartialRewriteOfMacroExpansionForMacroArgs) {
14933f1ab737SYitzhak Mandelbaum   std::string Input = R"cc(
14943f1ab737SYitzhak Mandelbaum #define NESTED(e) e
14953f1ab737SYitzhak Mandelbaum #define MACRO(str) 1 + NESTED(strlen((str).c_str()))
14963f1ab737SYitzhak Mandelbaum     int f(string s) { return MACRO(s); }
14973f1ab737SYitzhak Mandelbaum   )cc";
14983f1ab737SYitzhak Mandelbaum 
1499fdd98782SYitzhak Mandelbaum   testRule(ruleStrlenSize(), Input, Input);
1500fdd98782SYitzhak Mandelbaum }
150142b957aaSYitzhak Mandelbaum 
150242b957aaSYitzhak Mandelbaum #if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST
150342b957aaSYitzhak Mandelbaum // Verifies that `Type` and `QualType` are not allowed as top-level matchers in
150442b957aaSYitzhak Mandelbaum // rules.
150542b957aaSYitzhak Mandelbaum TEST(TransformerDeathTest, OrderedRuleTypes) {
15069f97480cSYitzhak Mandelbaum   RewriteRule QualTypeRule = makeRule(qualType(), changeTo(cat("Q")));
15078bb47cd8SYitzhak Mandelbaum   EXPECT_DEATH(transformer::detail::buildMatchers(QualTypeRule),
150842b957aaSYitzhak Mandelbaum                "Matcher must be.*node matcher");
150942b957aaSYitzhak Mandelbaum 
15109f97480cSYitzhak Mandelbaum   RewriteRule TypeRule = makeRule(arrayType(), changeTo(cat("T")));
15118bb47cd8SYitzhak Mandelbaum   EXPECT_DEATH(transformer::detail::buildMatchers(TypeRule),
151242b957aaSYitzhak Mandelbaum                "Matcher must be.*node matcher");
151342b957aaSYitzhak Mandelbaum }
151442b957aaSYitzhak Mandelbaum #endif
1515ff2743bfSYitzhak Mandelbaum 
1516ff2743bfSYitzhak Mandelbaum // Edits are able to span multiple files; in this case, a header and an
1517ff2743bfSYitzhak Mandelbaum // implementation file.
1518ff2743bfSYitzhak Mandelbaum TEST_F(TransformerTest, MultipleFiles) {
1519ff2743bfSYitzhak Mandelbaum   std::string Header = R"cc(void RemoveThisFunction();)cc";
1520ff2743bfSYitzhak Mandelbaum   std::string Source = R"cc(#include "input.h"
1521ff2743bfSYitzhak Mandelbaum                             void RemoveThisFunction();)cc";
1522ff2743bfSYitzhak Mandelbaum   Transformer T(
1523ff2743bfSYitzhak Mandelbaum       makeRule(functionDecl(hasName("RemoveThisFunction")), changeTo(cat(""))),
1524ff2743bfSYitzhak Mandelbaum       consumer());
1525ff2743bfSYitzhak Mandelbaum   T.registerMatchers(&MatchFinder);
1526ff2743bfSYitzhak Mandelbaum   auto Factory = newFrontendActionFactory(&MatchFinder);
1527ff2743bfSYitzhak Mandelbaum   EXPECT_TRUE(runToolOnCodeWithArgs(
1528ff2743bfSYitzhak Mandelbaum       Factory->create(), Source, std::vector<std::string>(), "input.cc",
1529ff2743bfSYitzhak Mandelbaum       "clang-tool", std::make_shared<PCHContainerOperations>(),
1530ff2743bfSYitzhak Mandelbaum       {{"input.h", Header}}));
1531ff2743bfSYitzhak Mandelbaum 
1532ff2743bfSYitzhak Mandelbaum   std::sort(Changes.begin(), Changes.end(),
1533ff2743bfSYitzhak Mandelbaum             [](const AtomicChange &L, const AtomicChange &R) {
1534ff2743bfSYitzhak Mandelbaum               return L.getFilePath() < R.getFilePath();
1535ff2743bfSYitzhak Mandelbaum             });
1536ff2743bfSYitzhak Mandelbaum 
1537ff2743bfSYitzhak Mandelbaum   ASSERT_EQ(Changes[0].getFilePath(), "./input.h");
1538ff2743bfSYitzhak Mandelbaum   EXPECT_THAT(Changes[0].getInsertedHeaders(), IsEmpty());
1539ff2743bfSYitzhak Mandelbaum   EXPECT_THAT(Changes[0].getRemovedHeaders(), IsEmpty());
1540ff2743bfSYitzhak Mandelbaum   llvm::Expected<std::string> UpdatedCode =
1541ff2743bfSYitzhak Mandelbaum       clang::tooling::applyAllReplacements(Header,
1542ff2743bfSYitzhak Mandelbaum                                            Changes[0].getReplacements());
1543ff2743bfSYitzhak Mandelbaum   ASSERT_TRUE(static_cast<bool>(UpdatedCode))
1544ff2743bfSYitzhak Mandelbaum       << "Could not update code: " << llvm::toString(UpdatedCode.takeError());
1545ff2743bfSYitzhak Mandelbaum   EXPECT_EQ(format(*UpdatedCode), format(R"cc(;)cc"));
1546ff2743bfSYitzhak Mandelbaum 
1547ff2743bfSYitzhak Mandelbaum   ASSERT_EQ(Changes[1].getFilePath(), "input.cc");
1548ff2743bfSYitzhak Mandelbaum   EXPECT_THAT(Changes[1].getInsertedHeaders(), IsEmpty());
1549ff2743bfSYitzhak Mandelbaum   EXPECT_THAT(Changes[1].getRemovedHeaders(), IsEmpty());
1550ff2743bfSYitzhak Mandelbaum   UpdatedCode = clang::tooling::applyAllReplacements(
1551ff2743bfSYitzhak Mandelbaum       Source, Changes[1].getReplacements());
1552ff2743bfSYitzhak Mandelbaum   ASSERT_TRUE(static_cast<bool>(UpdatedCode))
1553ff2743bfSYitzhak Mandelbaum       << "Could not update code: " << llvm::toString(UpdatedCode.takeError());
1554ff2743bfSYitzhak Mandelbaum   EXPECT_EQ(format(*UpdatedCode), format(R"cc(#include "input.h"
1555ff2743bfSYitzhak Mandelbaum                         ;)cc"));
1556ff2743bfSYitzhak Mandelbaum }
1557d8c1f43dSYitzhak Mandelbaum 
1558d8c1f43dSYitzhak Mandelbaum TEST_F(TransformerTest, AddIncludeMultipleFiles) {
1559d8c1f43dSYitzhak Mandelbaum   std::string Header = R"cc(void RemoveThisFunction();)cc";
1560d8c1f43dSYitzhak Mandelbaum   std::string Source = R"cc(#include "input.h"
1561d8c1f43dSYitzhak Mandelbaum                             void Foo() {RemoveThisFunction();})cc";
1562d8c1f43dSYitzhak Mandelbaum   Transformer T(
1563d8c1f43dSYitzhak Mandelbaum       makeRule(callExpr(callee(
1564d8c1f43dSYitzhak Mandelbaum                    functionDecl(hasName("RemoveThisFunction")).bind("fun"))),
1565d8c1f43dSYitzhak Mandelbaum                addInclude(node("fun"), "header.h")),
1566d8c1f43dSYitzhak Mandelbaum       consumer());
1567d8c1f43dSYitzhak Mandelbaum   T.registerMatchers(&MatchFinder);
1568d8c1f43dSYitzhak Mandelbaum   auto Factory = newFrontendActionFactory(&MatchFinder);
1569d8c1f43dSYitzhak Mandelbaum   EXPECT_TRUE(runToolOnCodeWithArgs(
1570d8c1f43dSYitzhak Mandelbaum       Factory->create(), Source, std::vector<std::string>(), "input.cc",
1571d8c1f43dSYitzhak Mandelbaum       "clang-tool", std::make_shared<PCHContainerOperations>(),
1572d8c1f43dSYitzhak Mandelbaum       {{"input.h", Header}}));
1573d8c1f43dSYitzhak Mandelbaum 
1574d8c1f43dSYitzhak Mandelbaum   ASSERT_EQ(Changes.size(), 1U);
1575d8c1f43dSYitzhak Mandelbaum   ASSERT_EQ(Changes[0].getFilePath(), "./input.h");
1576d8c1f43dSYitzhak Mandelbaum   EXPECT_THAT(Changes[0].getInsertedHeaders(), ElementsAre("header.h"));
1577d8c1f43dSYitzhak Mandelbaum   EXPECT_THAT(Changes[0].getRemovedHeaders(), IsEmpty());
1578d8c1f43dSYitzhak Mandelbaum   llvm::Expected<std::string> UpdatedCode =
1579d8c1f43dSYitzhak Mandelbaum       clang::tooling::applyAllReplacements(Header,
1580d8c1f43dSYitzhak Mandelbaum                                            Changes[0].getReplacements());
1581d8c1f43dSYitzhak Mandelbaum   ASSERT_TRUE(static_cast<bool>(UpdatedCode))
1582d8c1f43dSYitzhak Mandelbaum       << "Could not update code: " << llvm::toString(UpdatedCode.takeError());
1583d8c1f43dSYitzhak Mandelbaum   EXPECT_EQ(format(*UpdatedCode), format(Header));
1584d8c1f43dSYitzhak Mandelbaum }
1585fdd98782SYitzhak Mandelbaum } // namespace
1586