xref: /llvm-project/clang/unittests/Tooling/TransformerTest.cpp (revision 96ed6793b35e8267b0c94ebe69ae94f07024f476)
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) {
129*96ed6793SFangrui Song     Transformers.push_back(
130*96ed6793SFangrui Song         std::make_unique<Transformer>(std::move(Rule), consumer()));
131*96ed6793SFangrui Song     Transformers.back()->registerMatchers(&MatchFinder);
132fdd98782SYitzhak Mandelbaum     compareSnippets(Expected, rewrite(Input));
133fdd98782SYitzhak Mandelbaum   }
134fdd98782SYitzhak Mandelbaum 
135*96ed6793SFangrui Song   // Transformers are referenced by MatchFinder.
136*96ed6793SFangrui Song   std::vector<std::unique_ptr<Transformer>> Transformers;
137fdd98782SYitzhak Mandelbaum   clang::ast_matchers::MatchFinder MatchFinder;
138aecc59c5SYitzhak Mandelbaum   // Records whether any errors occurred in individual changes.
139aecc59c5SYitzhak Mandelbaum   int ErrorCount = 0;
140fdd98782SYitzhak Mandelbaum   AtomicChanges Changes;
141fdd98782SYitzhak Mandelbaum 
142fdd98782SYitzhak Mandelbaum private:
143fdd98782SYitzhak Mandelbaum   FileContentMappings FileContents = {{"header.h", ""}};
144fdd98782SYitzhak Mandelbaum };
145fdd98782SYitzhak Mandelbaum 
146fdd98782SYitzhak Mandelbaum class TransformerTest : public ClangRefactoringTestBase {
147fdd98782SYitzhak Mandelbaum protected:
148fdd98782SYitzhak Mandelbaum   TransformerTest() { appendToHeader(KHeaderContents); }
149fdd98782SYitzhak Mandelbaum };
150fdd98782SYitzhak Mandelbaum 
1513f1ab737SYitzhak Mandelbaum // Given string s, change strlen($s.c_str()) to REPLACED.
152fdd98782SYitzhak Mandelbaum static RewriteRule ruleStrlenSize() {
153fdd98782SYitzhak Mandelbaum   StringRef StringExpr = "strexpr";
154fdd98782SYitzhak Mandelbaum   auto StringType = namedDecl(hasAnyName("::basic_string", "::string"));
155fa1552e8SYitzhak Mandelbaum   auto R = makeRule(
156fa1552e8SYitzhak Mandelbaum       callExpr(callee(functionDecl(hasName("strlen"))),
157fdd98782SYitzhak Mandelbaum                hasArgument(0, cxxMemberCallExpr(
158fdd98782SYitzhak Mandelbaum                                   on(expr(hasType(isOrPointsTo(StringType)))
159fdd98782SYitzhak Mandelbaum                                          .bind(StringExpr)),
160fa1552e8SYitzhak Mandelbaum                                   callee(cxxMethodDecl(hasName("c_str")))))),
1619f97480cSYitzhak Mandelbaum       changeTo(cat("REPLACED")), cat("Use size() method directly on string."));
162fa1552e8SYitzhak Mandelbaum   return R;
163fdd98782SYitzhak Mandelbaum }
164fdd98782SYitzhak Mandelbaum 
165fdd98782SYitzhak Mandelbaum TEST_F(TransformerTest, StrlenSize) {
166fdd98782SYitzhak Mandelbaum   std::string Input = "int f(string s) { return strlen(s.c_str()); }";
167fdd98782SYitzhak Mandelbaum   std::string Expected = "int f(string s) { return REPLACED; }";
168fdd98782SYitzhak Mandelbaum   testRule(ruleStrlenSize(), Input, Expected);
169fdd98782SYitzhak Mandelbaum }
170fdd98782SYitzhak Mandelbaum 
171fdd98782SYitzhak Mandelbaum // Tests that no change is applied when a match is not expected.
172fdd98782SYitzhak Mandelbaum TEST_F(TransformerTest, NoMatch) {
173fdd98782SYitzhak Mandelbaum   std::string Input = "int f(string s) { return s.size(); }";
174fdd98782SYitzhak Mandelbaum   testRule(ruleStrlenSize(), Input, Input);
175fdd98782SYitzhak Mandelbaum }
176fdd98782SYitzhak Mandelbaum 
177fdd98782SYitzhak Mandelbaum // Tests replacing an expression.
178fdd98782SYitzhak Mandelbaum TEST_F(TransformerTest, Flag) {
179fdd98782SYitzhak Mandelbaum   StringRef Flag = "flag";
180fa1552e8SYitzhak Mandelbaum   RewriteRule Rule = makeRule(
181fa1552e8SYitzhak Mandelbaum       cxxMemberCallExpr(on(expr(hasType(cxxRecordDecl(
182fa1552e8SYitzhak Mandelbaum                                     hasName("proto::ProtoCommandLineFlag"))))
183fdd98782SYitzhak Mandelbaum                                .bind(Flag)),
184fa1552e8SYitzhak Mandelbaum                         unless(callee(cxxMethodDecl(hasName("GetProto"))))),
185adcd0268SBenjamin Kramer       changeTo(node(std::string(Flag)), cat("EXPR")));
186fdd98782SYitzhak Mandelbaum 
187fdd98782SYitzhak Mandelbaum   std::string Input = R"cc(
188fdd98782SYitzhak Mandelbaum     proto::ProtoCommandLineFlag flag;
189fdd98782SYitzhak Mandelbaum     int x = flag.foo();
190fdd98782SYitzhak Mandelbaum     int y = flag.GetProto().foo();
191fdd98782SYitzhak Mandelbaum   )cc";
192fdd98782SYitzhak Mandelbaum   std::string Expected = R"cc(
193fdd98782SYitzhak Mandelbaum     proto::ProtoCommandLineFlag flag;
194fdd98782SYitzhak Mandelbaum     int x = EXPR.foo();
195fdd98782SYitzhak Mandelbaum     int y = flag.GetProto().foo();
196fdd98782SYitzhak Mandelbaum   )cc";
197fdd98782SYitzhak Mandelbaum 
198fdd98782SYitzhak Mandelbaum   testRule(std::move(Rule), Input, Expected);
199fdd98782SYitzhak Mandelbaum }
200fdd98782SYitzhak Mandelbaum 
201727bdcb2SYitzhak Mandelbaum TEST_F(TransformerTest, AddIncludeQuoted) {
202d8c1f43dSYitzhak Mandelbaum   RewriteRule Rule =
203d8c1f43dSYitzhak Mandelbaum       makeRule(callExpr(callee(functionDecl(hasName("f")))),
204d8c1f43dSYitzhak Mandelbaum                {addInclude("clang/OtherLib.h"), changeTo(cat("other()"))});
205d8c1f43dSYitzhak Mandelbaum 
206d8c1f43dSYitzhak Mandelbaum   std::string Input = R"cc(
207d8c1f43dSYitzhak Mandelbaum     int f(int x);
208d8c1f43dSYitzhak Mandelbaum     int h(int x) { return f(x); }
209d8c1f43dSYitzhak Mandelbaum   )cc";
210d8c1f43dSYitzhak Mandelbaum   std::string Expected = R"cc(#include "clang/OtherLib.h"
211d8c1f43dSYitzhak Mandelbaum 
212d8c1f43dSYitzhak Mandelbaum     int f(int x);
213d8c1f43dSYitzhak Mandelbaum     int h(int x) { return other(); }
214d8c1f43dSYitzhak Mandelbaum   )cc";
215d8c1f43dSYitzhak Mandelbaum 
216d8c1f43dSYitzhak Mandelbaum   testRule(Rule, Input, Expected);
217d8c1f43dSYitzhak Mandelbaum }
218d8c1f43dSYitzhak Mandelbaum 
219d8c1f43dSYitzhak Mandelbaum TEST_F(TransformerTest, AddIncludeAngled) {
220d8c1f43dSYitzhak Mandelbaum   RewriteRule Rule = makeRule(
221d8c1f43dSYitzhak Mandelbaum       callExpr(callee(functionDecl(hasName("f")))),
222d8c1f43dSYitzhak Mandelbaum       {addInclude("clang/OtherLib.h", transformer::IncludeFormat::Angled),
223d8c1f43dSYitzhak Mandelbaum        changeTo(cat("other()"))});
224d8c1f43dSYitzhak Mandelbaum 
225d8c1f43dSYitzhak Mandelbaum   std::string Input = R"cc(
226d8c1f43dSYitzhak Mandelbaum     int f(int x);
227d8c1f43dSYitzhak Mandelbaum     int h(int x) { return f(x); }
228d8c1f43dSYitzhak Mandelbaum   )cc";
229d8c1f43dSYitzhak Mandelbaum   std::string Expected = R"cc(#include <clang/OtherLib.h>
230d8c1f43dSYitzhak Mandelbaum 
231d8c1f43dSYitzhak Mandelbaum     int f(int x);
232d8c1f43dSYitzhak Mandelbaum     int h(int x) { return other(); }
233d8c1f43dSYitzhak Mandelbaum   )cc";
234d8c1f43dSYitzhak Mandelbaum 
235d8c1f43dSYitzhak Mandelbaum   testRule(Rule, Input, Expected);
236d8c1f43dSYitzhak Mandelbaum }
237d8c1f43dSYitzhak Mandelbaum 
238d8c1f43dSYitzhak Mandelbaum TEST_F(TransformerTest, AddIncludeQuotedForRule) {
239727bdcb2SYitzhak Mandelbaum   RewriteRule Rule = makeRule(callExpr(callee(functionDecl(hasName("f")))),
2409f97480cSYitzhak Mandelbaum                               changeTo(cat("other()")));
241727bdcb2SYitzhak Mandelbaum   addInclude(Rule, "clang/OtherLib.h");
242727bdcb2SYitzhak Mandelbaum 
243727bdcb2SYitzhak Mandelbaum   std::string Input = R"cc(
244727bdcb2SYitzhak Mandelbaum     int f(int x);
245727bdcb2SYitzhak Mandelbaum     int h(int x) { return f(x); }
246727bdcb2SYitzhak Mandelbaum   )cc";
247727bdcb2SYitzhak Mandelbaum   std::string Expected = R"cc(#include "clang/OtherLib.h"
248727bdcb2SYitzhak Mandelbaum 
249727bdcb2SYitzhak Mandelbaum     int f(int x);
250727bdcb2SYitzhak Mandelbaum     int h(int x) { return other(); }
251727bdcb2SYitzhak Mandelbaum   )cc";
252727bdcb2SYitzhak Mandelbaum 
253727bdcb2SYitzhak Mandelbaum   testRule(Rule, Input, Expected);
254727bdcb2SYitzhak Mandelbaum }
255727bdcb2SYitzhak Mandelbaum 
256d8c1f43dSYitzhak Mandelbaum TEST_F(TransformerTest, AddIncludeAngledForRule) {
257727bdcb2SYitzhak Mandelbaum   RewriteRule Rule = makeRule(callExpr(callee(functionDecl(hasName("f")))),
2589f97480cSYitzhak Mandelbaum                               changeTo(cat("other()")));
2598bb47cd8SYitzhak Mandelbaum   addInclude(Rule, "clang/OtherLib.h", transformer::IncludeFormat::Angled);
260727bdcb2SYitzhak Mandelbaum 
261727bdcb2SYitzhak Mandelbaum   std::string Input = R"cc(
262727bdcb2SYitzhak Mandelbaum     int f(int x);
263727bdcb2SYitzhak Mandelbaum     int h(int x) { return f(x); }
264727bdcb2SYitzhak Mandelbaum   )cc";
265727bdcb2SYitzhak Mandelbaum   std::string Expected = R"cc(#include <clang/OtherLib.h>
266727bdcb2SYitzhak Mandelbaum 
267727bdcb2SYitzhak Mandelbaum     int f(int x);
268727bdcb2SYitzhak Mandelbaum     int h(int x) { return other(); }
269727bdcb2SYitzhak Mandelbaum   )cc";
270727bdcb2SYitzhak Mandelbaum 
271727bdcb2SYitzhak Mandelbaum   testRule(Rule, Input, Expected);
272727bdcb2SYitzhak Mandelbaum }
273727bdcb2SYitzhak Mandelbaum 
274fdd98782SYitzhak Mandelbaum TEST_F(TransformerTest, NodePartNameNamedDecl) {
275fdd98782SYitzhak Mandelbaum   StringRef Fun = "fun";
2763ec50e29SYitzhak Mandelbaum   RewriteRule Rule = makeRule(functionDecl(hasName("bad")).bind(Fun),
277adcd0268SBenjamin Kramer                               changeTo(name(std::string(Fun)), cat("good")));
278fdd98782SYitzhak Mandelbaum 
279fdd98782SYitzhak Mandelbaum   std::string Input = R"cc(
280fdd98782SYitzhak Mandelbaum     int bad(int x);
281fdd98782SYitzhak Mandelbaum     int bad(int x) { return x * x; }
282fdd98782SYitzhak Mandelbaum   )cc";
283fdd98782SYitzhak Mandelbaum   std::string Expected = R"cc(
284fdd98782SYitzhak Mandelbaum     int good(int x);
285fdd98782SYitzhak Mandelbaum     int good(int x) { return x * x; }
286fdd98782SYitzhak Mandelbaum   )cc";
287fdd98782SYitzhak Mandelbaum 
288fdd98782SYitzhak Mandelbaum   testRule(Rule, Input, Expected);
289fdd98782SYitzhak Mandelbaum }
290fdd98782SYitzhak Mandelbaum 
291fdd98782SYitzhak Mandelbaum TEST_F(TransformerTest, NodePartNameDeclRef) {
292fdd98782SYitzhak Mandelbaum   std::string Input = R"cc(
293fdd98782SYitzhak Mandelbaum     template <typename T>
294fdd98782SYitzhak Mandelbaum     T bad(T x) {
295fdd98782SYitzhak Mandelbaum       return x;
296fdd98782SYitzhak Mandelbaum     }
297fdd98782SYitzhak Mandelbaum     int neutral(int x) { return bad<int>(x) * x; }
298fdd98782SYitzhak Mandelbaum   )cc";
299fdd98782SYitzhak Mandelbaum   std::string Expected = 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 good<int>(x) * x; }
305fdd98782SYitzhak Mandelbaum   )cc";
306fdd98782SYitzhak Mandelbaum 
307fdd98782SYitzhak Mandelbaum   StringRef Ref = "ref";
308fa1552e8SYitzhak Mandelbaum   testRule(makeRule(declRefExpr(to(functionDecl(hasName("bad")))).bind(Ref),
309adcd0268SBenjamin Kramer                     changeTo(name(std::string(Ref)), cat("good"))),
310fdd98782SYitzhak Mandelbaum            Input, Expected);
311fdd98782SYitzhak Mandelbaum }
312fdd98782SYitzhak Mandelbaum 
313fdd98782SYitzhak Mandelbaum TEST_F(TransformerTest, NodePartNameDeclRefFailure) {
314fdd98782SYitzhak Mandelbaum   std::string Input = R"cc(
315fdd98782SYitzhak Mandelbaum     struct Y {
316fdd98782SYitzhak Mandelbaum       int operator*();
317fdd98782SYitzhak Mandelbaum     };
318fdd98782SYitzhak Mandelbaum     int neutral(int x) {
319fdd98782SYitzhak Mandelbaum       Y y;
320fdd98782SYitzhak Mandelbaum       int (Y::*ptr)() = &Y::operator*;
321fdd98782SYitzhak Mandelbaum       return *y + x;
322fdd98782SYitzhak Mandelbaum     }
323fdd98782SYitzhak Mandelbaum   )cc";
324fdd98782SYitzhak Mandelbaum 
325fdd98782SYitzhak Mandelbaum   StringRef Ref = "ref";
326a5dadbe1SYitzhak Mandelbaum   Transformer T(makeRule(declRefExpr(to(functionDecl())).bind(Ref),
327adcd0268SBenjamin Kramer                          changeTo(name(std::string(Ref)), cat("good"))),
328a5dadbe1SYitzhak Mandelbaum                 consumer());
329a5dadbe1SYitzhak Mandelbaum   T.registerMatchers(&MatchFinder);
330a5dadbe1SYitzhak Mandelbaum   EXPECT_FALSE(rewrite(Input));
331fdd98782SYitzhak Mandelbaum }
332fdd98782SYitzhak Mandelbaum 
333fdd98782SYitzhak Mandelbaum TEST_F(TransformerTest, NodePartMember) {
334fdd98782SYitzhak Mandelbaum   StringRef E = "expr";
335fa1552e8SYitzhak Mandelbaum   RewriteRule Rule = makeRule(memberExpr(member(hasName("bad"))).bind(E),
336adcd0268SBenjamin Kramer                               changeTo(member(std::string(E)), cat("good")));
337fdd98782SYitzhak Mandelbaum 
338fdd98782SYitzhak Mandelbaum   std::string Input = R"cc(
339fdd98782SYitzhak Mandelbaum     struct S {
340fdd98782SYitzhak Mandelbaum       int bad;
341fdd98782SYitzhak Mandelbaum     };
342fdd98782SYitzhak Mandelbaum     int g() {
343fdd98782SYitzhak Mandelbaum       S s;
344fdd98782SYitzhak Mandelbaum       return s.bad;
345fdd98782SYitzhak Mandelbaum     }
346fdd98782SYitzhak Mandelbaum   )cc";
347fdd98782SYitzhak Mandelbaum   std::string Expected = R"cc(
348fdd98782SYitzhak Mandelbaum     struct S {
349fdd98782SYitzhak Mandelbaum       int bad;
350fdd98782SYitzhak Mandelbaum     };
351fdd98782SYitzhak Mandelbaum     int g() {
352fdd98782SYitzhak Mandelbaum       S s;
353fdd98782SYitzhak Mandelbaum       return s.good;
354fdd98782SYitzhak Mandelbaum     }
355fdd98782SYitzhak Mandelbaum   )cc";
356fdd98782SYitzhak Mandelbaum 
357fdd98782SYitzhak Mandelbaum   testRule(Rule, Input, Expected);
358fdd98782SYitzhak Mandelbaum }
359fdd98782SYitzhak Mandelbaum 
360fdd98782SYitzhak Mandelbaum TEST_F(TransformerTest, NodePartMemberQualified) {
361fdd98782SYitzhak Mandelbaum   std::string Input = R"cc(
362fdd98782SYitzhak Mandelbaum     struct S {
363fdd98782SYitzhak Mandelbaum       int bad;
364fdd98782SYitzhak Mandelbaum       int good;
365fdd98782SYitzhak Mandelbaum     };
366fdd98782SYitzhak Mandelbaum     struct T : public S {
367fdd98782SYitzhak Mandelbaum       int bad;
368fdd98782SYitzhak Mandelbaum     };
369fdd98782SYitzhak Mandelbaum     int g() {
370fdd98782SYitzhak Mandelbaum       T t;
371fdd98782SYitzhak Mandelbaum       return t.S::bad;
372fdd98782SYitzhak Mandelbaum     }
373fdd98782SYitzhak Mandelbaum   )cc";
374fdd98782SYitzhak Mandelbaum   std::string Expected = R"cc(
375fdd98782SYitzhak Mandelbaum     struct S {
376fdd98782SYitzhak Mandelbaum       int bad;
377fdd98782SYitzhak Mandelbaum       int good;
378fdd98782SYitzhak Mandelbaum     };
379fdd98782SYitzhak Mandelbaum     struct T : public S {
380fdd98782SYitzhak Mandelbaum       int bad;
381fdd98782SYitzhak Mandelbaum     };
382fdd98782SYitzhak Mandelbaum     int g() {
383fdd98782SYitzhak Mandelbaum       T t;
384fdd98782SYitzhak Mandelbaum       return t.S::good;
385fdd98782SYitzhak Mandelbaum     }
386fdd98782SYitzhak Mandelbaum   )cc";
387fdd98782SYitzhak Mandelbaum 
388fdd98782SYitzhak Mandelbaum   StringRef E = "expr";
389adcd0268SBenjamin Kramer   testRule(makeRule(memberExpr().bind(E),
390adcd0268SBenjamin Kramer                     changeTo(member(std::string(E)), cat("good"))),
391fdd98782SYitzhak Mandelbaum            Input, Expected);
392fdd98782SYitzhak Mandelbaum }
393fdd98782SYitzhak Mandelbaum 
394fdd98782SYitzhak Mandelbaum TEST_F(TransformerTest, NodePartMemberMultiToken) {
395fdd98782SYitzhak Mandelbaum   std::string Input = R"cc(
396fdd98782SYitzhak Mandelbaum     struct Y {
397fdd98782SYitzhak Mandelbaum       int operator*();
398fdd98782SYitzhak Mandelbaum       int good();
399fdd98782SYitzhak Mandelbaum       template <typename T> void foo(T t);
400fdd98782SYitzhak Mandelbaum     };
401fdd98782SYitzhak Mandelbaum     int neutral(int x) {
402fdd98782SYitzhak Mandelbaum       Y y;
403fdd98782SYitzhak Mandelbaum       y.template foo<int>(3);
404fdd98782SYitzhak Mandelbaum       return y.operator *();
405fdd98782SYitzhak Mandelbaum     }
406fdd98782SYitzhak Mandelbaum   )cc";
407fdd98782SYitzhak Mandelbaum   std::string Expected = R"cc(
408fdd98782SYitzhak Mandelbaum     struct Y {
409fdd98782SYitzhak Mandelbaum       int operator*();
410fdd98782SYitzhak Mandelbaum       int good();
411fdd98782SYitzhak Mandelbaum       template <typename T> void foo(T t);
412fdd98782SYitzhak Mandelbaum     };
413fdd98782SYitzhak Mandelbaum     int neutral(int x) {
414fdd98782SYitzhak Mandelbaum       Y y;
415fdd98782SYitzhak Mandelbaum       y.template good<int>(3);
416fdd98782SYitzhak Mandelbaum       return y.good();
417fdd98782SYitzhak Mandelbaum     }
418fdd98782SYitzhak Mandelbaum   )cc";
419fdd98782SYitzhak Mandelbaum 
420fdd98782SYitzhak Mandelbaum   StringRef MemExpr = "member";
421fa1552e8SYitzhak Mandelbaum   testRule(makeRule(memberExpr().bind(MemExpr),
422adcd0268SBenjamin Kramer                     changeTo(member(std::string(MemExpr)), cat("good"))),
423fa1552e8SYitzhak Mandelbaum            Input, Expected);
424fa1552e8SYitzhak Mandelbaum }
425fa1552e8SYitzhak Mandelbaum 
426cf428778SYitzhak Mandelbaum TEST_F(TransformerTest, NoEdits) {
427cf428778SYitzhak Mandelbaum   using transformer::noEdits;
428cf428778SYitzhak Mandelbaum   std::string Input = "int f(int x) { return x; }";
429cf428778SYitzhak Mandelbaum   testRule(makeRule(returnStmt().bind("return"), noEdits()), Input, Input);
430cf428778SYitzhak Mandelbaum }
431cf428778SYitzhak Mandelbaum 
4326f8f5cb7SYitzhak Mandelbaum TEST_F(TransformerTest, NoopEdit) {
4336f8f5cb7SYitzhak Mandelbaum   using transformer::node;
4346f8f5cb7SYitzhak Mandelbaum   using transformer::noopEdit;
4356f8f5cb7SYitzhak Mandelbaum   std::string Input = "int f(int x) { return x; }";
4366f8f5cb7SYitzhak Mandelbaum   testRule(makeRule(returnStmt().bind("return"), noopEdit(node("return"))),
4376f8f5cb7SYitzhak Mandelbaum            Input, Input);
4386f8f5cb7SYitzhak Mandelbaum }
4396f8f5cb7SYitzhak Mandelbaum 
440cf428778SYitzhak Mandelbaum TEST_F(TransformerTest, IfBound2Args) {
441cf428778SYitzhak Mandelbaum   using transformer::ifBound;
442cf428778SYitzhak Mandelbaum   std::string Input = "int f(int x) { return x; }";
443cf428778SYitzhak Mandelbaum   std::string Expected = "int f(int x) { CHANGE; }";
444cf428778SYitzhak Mandelbaum   testRule(makeRule(returnStmt().bind("return"),
445cf428778SYitzhak Mandelbaum                     ifBound("return", changeTo(cat("CHANGE;")))),
446cf428778SYitzhak Mandelbaum            Input, Expected);
447cf428778SYitzhak Mandelbaum }
448cf428778SYitzhak Mandelbaum 
449cf428778SYitzhak Mandelbaum TEST_F(TransformerTest, IfBound3Args) {
450cf428778SYitzhak Mandelbaum   using transformer::ifBound;
451cf428778SYitzhak Mandelbaum   std::string Input = "int f(int x) { return x; }";
452cf428778SYitzhak Mandelbaum   std::string Expected = "int f(int x) { CHANGE; }";
453cf428778SYitzhak Mandelbaum   testRule(makeRule(returnStmt().bind("return"),
454cf428778SYitzhak Mandelbaum                     ifBound("nothing", changeTo(cat("ERROR")),
455cf428778SYitzhak Mandelbaum                             changeTo(cat("CHANGE;")))),
456cf428778SYitzhak Mandelbaum            Input, Expected);
457cf428778SYitzhak Mandelbaum }
458cf428778SYitzhak Mandelbaum 
459cf428778SYitzhak Mandelbaum TEST_F(TransformerTest, ShrinkTo) {
460cf428778SYitzhak Mandelbaum   using transformer::shrinkTo;
461cf428778SYitzhak Mandelbaum   std::string Input = "int f(int x) { return x; }";
462cf428778SYitzhak Mandelbaum   std::string Expected = "return x;";
463cf428778SYitzhak Mandelbaum   testRule(makeRule(functionDecl(hasDescendant(returnStmt().bind("return")))
464cf428778SYitzhak Mandelbaum                         .bind("function"),
465cf428778SYitzhak Mandelbaum                     shrinkTo(node("function"), node("return"))),
466cf428778SYitzhak Mandelbaum            Input, Expected);
467cf428778SYitzhak Mandelbaum }
468cf428778SYitzhak Mandelbaum 
469c332a984SYitzhak Mandelbaum // Rewrite various Stmts inside a Decl.
470c332a984SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsDeclChangeStmt) {
471c332a984SYitzhak Mandelbaum   std::string Input =
472c332a984SYitzhak Mandelbaum       "int f(int x) { int y = x; { int z = x * x; } return x; }";
473c332a984SYitzhak Mandelbaum   std::string Expected =
474c332a984SYitzhak Mandelbaum       "int f(int x) { int y = 3; { int z = 3 * 3; } return 3; }";
475c332a984SYitzhak Mandelbaum   auto InlineX =
476c332a984SYitzhak Mandelbaum       makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
477c332a984SYitzhak Mandelbaum   testRule(makeRule(functionDecl(hasName("f")).bind("fun"),
478c332a984SYitzhak Mandelbaum                     rewriteDescendants("fun", InlineX)),
479c332a984SYitzhak Mandelbaum            Input, Expected);
480c332a984SYitzhak Mandelbaum }
481c332a984SYitzhak Mandelbaum 
482c332a984SYitzhak Mandelbaum // Rewrite various TypeLocs inside a Decl.
483c332a984SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsDeclChangeTypeLoc) {
484c332a984SYitzhak Mandelbaum   std::string Input = "int f(int *x) { return *x; }";
485c332a984SYitzhak Mandelbaum   std::string Expected = "char f(char *x) { return *x; }";
486c332a984SYitzhak Mandelbaum   auto IntToChar = makeRule(typeLoc(loc(qualType(isInteger(), builtinType()))),
487c332a984SYitzhak Mandelbaum                             changeTo(cat("char")));
488c332a984SYitzhak Mandelbaum   testRule(makeRule(functionDecl(hasName("f")).bind("fun"),
489c332a984SYitzhak Mandelbaum                     rewriteDescendants("fun", IntToChar)),
490c332a984SYitzhak Mandelbaum            Input, Expected);
491c332a984SYitzhak Mandelbaum }
492c332a984SYitzhak Mandelbaum 
493c332a984SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsStmt) {
494c332a984SYitzhak Mandelbaum   // Add an unrelated definition to the header that also has a variable named
495c332a984SYitzhak Mandelbaum   // "x", to test that the rewrite is limited to the scope we intend.
496c332a984SYitzhak Mandelbaum   appendToHeader(R"cc(int g(int x) { return x; })cc");
497c332a984SYitzhak Mandelbaum   std::string Input =
498c332a984SYitzhak Mandelbaum       "int f(int x) { int y = x; { int z = x * x; } return x; }";
499c332a984SYitzhak Mandelbaum   std::string Expected =
500c332a984SYitzhak Mandelbaum       "int f(int x) { int y = 3; { int z = 3 * 3; } return 3; }";
501c332a984SYitzhak Mandelbaum   auto InlineX =
502c332a984SYitzhak Mandelbaum       makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
503c332a984SYitzhak Mandelbaum   testRule(makeRule(functionDecl(hasName("f"), hasBody(stmt().bind("body"))),
504c332a984SYitzhak Mandelbaum                     rewriteDescendants("body", InlineX)),
505c332a984SYitzhak Mandelbaum            Input, Expected);
506c332a984SYitzhak Mandelbaum }
507c332a984SYitzhak Mandelbaum 
508c332a984SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsStmtWithAdditionalChange) {
509c332a984SYitzhak Mandelbaum   std::string Input =
510c332a984SYitzhak Mandelbaum       "int f(int x) { int y = x; { int z = x * x; } return x; }";
511c332a984SYitzhak Mandelbaum   std::string Expected =
512c332a984SYitzhak Mandelbaum       "int newName(int x) { int y = 3; { int z = 3 * 3; } return 3; }";
513c332a984SYitzhak Mandelbaum   auto InlineX =
514c332a984SYitzhak Mandelbaum       makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
515c332a984SYitzhak Mandelbaum   testRule(
516c332a984SYitzhak Mandelbaum       makeRule(
517c332a984SYitzhak Mandelbaum           functionDecl(hasName("f"), hasBody(stmt().bind("body"))).bind("f"),
518c332a984SYitzhak Mandelbaum           flatten(changeTo(name("f"), cat("newName")),
519c332a984SYitzhak Mandelbaum                   rewriteDescendants("body", InlineX))),
520c332a984SYitzhak Mandelbaum       Input, Expected);
521c332a984SYitzhak Mandelbaum }
522c332a984SYitzhak Mandelbaum 
523c332a984SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsTypeLoc) {
524c332a984SYitzhak Mandelbaum   std::string Input = "int f(int *x) { return *x; }";
525c332a984SYitzhak Mandelbaum   std::string Expected = "int f(char *x) { return *x; }";
526c332a984SYitzhak Mandelbaum   auto IntToChar =
527c332a984SYitzhak Mandelbaum       makeRule(typeLoc(loc(qualType(isInteger(), builtinType()))).bind("loc"),
528c332a984SYitzhak Mandelbaum                changeTo(cat("char")));
529c332a984SYitzhak Mandelbaum   testRule(
530c332a984SYitzhak Mandelbaum       makeRule(functionDecl(hasName("f"),
531c332a984SYitzhak Mandelbaum                             hasParameter(0, varDecl(hasTypeLoc(
532c332a984SYitzhak Mandelbaum                                                 typeLoc().bind("parmType"))))),
533c332a984SYitzhak Mandelbaum                rewriteDescendants("parmType", IntToChar)),
534c332a984SYitzhak Mandelbaum       Input, Expected);
535c332a984SYitzhak Mandelbaum }
536c332a984SYitzhak Mandelbaum 
537c332a984SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsReferToParentBinding) {
538c332a984SYitzhak Mandelbaum   std::string Input =
539c332a984SYitzhak Mandelbaum       "int f(int p) { int y = p; { int z = p * p; } return p; }";
540c332a984SYitzhak Mandelbaum   std::string Expected =
541c332a984SYitzhak Mandelbaum       "int f(int p) { int y = 3; { int z = 3 * 3; } return 3; }";
542c332a984SYitzhak Mandelbaum   std::string VarId = "var";
543c332a984SYitzhak Mandelbaum   auto InlineVar = makeRule(declRefExpr(to(varDecl(equalsBoundNode(VarId)))),
544c332a984SYitzhak Mandelbaum                             changeTo(cat("3")));
545c332a984SYitzhak Mandelbaum   testRule(makeRule(functionDecl(hasName("f"),
546c332a984SYitzhak Mandelbaum                                  hasParameter(0, varDecl().bind(VarId)))
547c332a984SYitzhak Mandelbaum                         .bind("fun"),
548c332a984SYitzhak Mandelbaum                     rewriteDescendants("fun", InlineVar)),
549c332a984SYitzhak Mandelbaum            Input, Expected);
550c332a984SYitzhak Mandelbaum }
551c332a984SYitzhak Mandelbaum 
552c332a984SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsUnboundNode) {
553c332a984SYitzhak Mandelbaum   std::string Input =
554c332a984SYitzhak Mandelbaum       "int f(int x) { int y = x; { int z = x * x; } return x; }";
555c332a984SYitzhak Mandelbaum   auto InlineX =
556c332a984SYitzhak Mandelbaum       makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
557c332a984SYitzhak Mandelbaum   Transformer T(makeRule(functionDecl(hasName("f")),
558c332a984SYitzhak Mandelbaum                          rewriteDescendants("UNBOUND", InlineX)),
559c332a984SYitzhak Mandelbaum                 consumer());
560c332a984SYitzhak Mandelbaum   T.registerMatchers(&MatchFinder);
561c332a984SYitzhak Mandelbaum   EXPECT_FALSE(rewrite(Input));
562c332a984SYitzhak Mandelbaum   EXPECT_THAT(Changes, IsEmpty());
563c332a984SYitzhak Mandelbaum   EXPECT_EQ(ErrorCount, 1);
564c332a984SYitzhak Mandelbaum }
565c332a984SYitzhak Mandelbaum 
566c332a984SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsInvalidNodeType) {
567c332a984SYitzhak Mandelbaum   std::string Input =
568c332a984SYitzhak Mandelbaum       "int f(int x) { int y = x; { int z = x * x; } return x; }";
569c332a984SYitzhak Mandelbaum   auto IntToChar =
570c332a984SYitzhak Mandelbaum       makeRule(qualType(isInteger(), builtinType()), changeTo(cat("char")));
571c332a984SYitzhak Mandelbaum   Transformer T(
572c332a984SYitzhak Mandelbaum       makeRule(functionDecl(
573c332a984SYitzhak Mandelbaum                    hasName("f"),
574c332a984SYitzhak Mandelbaum                    hasParameter(0, varDecl(hasType(qualType().bind("type"))))),
575c332a984SYitzhak Mandelbaum                rewriteDescendants("type", IntToChar)),
576c332a984SYitzhak Mandelbaum       consumer());
577c332a984SYitzhak Mandelbaum   T.registerMatchers(&MatchFinder);
578c332a984SYitzhak Mandelbaum   EXPECT_FALSE(rewrite(Input));
579c332a984SYitzhak Mandelbaum   EXPECT_THAT(Changes, IsEmpty());
580c332a984SYitzhak Mandelbaum   EXPECT_EQ(ErrorCount, 1);
581c332a984SYitzhak Mandelbaum }
582c332a984SYitzhak Mandelbaum 
583d4f39031SYitzhak Mandelbaum //
584d4f39031SYitzhak Mandelbaum // We include one test per typed overload. We don't test extensively since that
585d4f39031SYitzhak Mandelbaum // is already covered by the tests above.
586d4f39031SYitzhak Mandelbaum //
587d4f39031SYitzhak Mandelbaum 
588d4f39031SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsTypedStmt) {
589d4f39031SYitzhak Mandelbaum   // Add an unrelated definition to the header that also has a variable named
590d4f39031SYitzhak Mandelbaum   // "x", to test that the rewrite is limited to the scope we intend.
591d4f39031SYitzhak Mandelbaum   appendToHeader(R"cc(int g(int x) { return x; })cc");
592d4f39031SYitzhak Mandelbaum   std::string Input =
593d4f39031SYitzhak Mandelbaum       "int f(int x) { int y = x; { int z = x * x; } return x; }";
594d4f39031SYitzhak Mandelbaum   std::string Expected =
595d4f39031SYitzhak Mandelbaum       "int f(int x) { int y = 3; { int z = 3 * 3; } return 3; }";
596d4f39031SYitzhak Mandelbaum   auto InlineX =
597d4f39031SYitzhak Mandelbaum       makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
598d4f39031SYitzhak Mandelbaum   testRule(makeRule(functionDecl(hasName("f"), hasBody(stmt().bind("body"))),
599d4f39031SYitzhak Mandelbaum                     [&InlineX](const MatchFinder::MatchResult &R) {
600d4f39031SYitzhak Mandelbaum                       const auto *Node = R.Nodes.getNodeAs<Stmt>("body");
601d4f39031SYitzhak Mandelbaum                       assert(Node != nullptr && "body must be bound");
602d4f39031SYitzhak Mandelbaum                       return transformer::detail::rewriteDescendants(
603d4f39031SYitzhak Mandelbaum                           *Node, InlineX, R);
604d4f39031SYitzhak Mandelbaum                     }),
605d4f39031SYitzhak Mandelbaum            Input, Expected);
606d4f39031SYitzhak Mandelbaum }
607d4f39031SYitzhak Mandelbaum 
608d4f39031SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsTypedDecl) {
609d4f39031SYitzhak Mandelbaum   std::string Input =
610d4f39031SYitzhak Mandelbaum       "int f(int x) { int y = x; { int z = x * x; } return x; }";
611d4f39031SYitzhak Mandelbaum   std::string Expected =
612d4f39031SYitzhak Mandelbaum       "int f(int x) { int y = 3; { int z = 3 * 3; } return 3; }";
613d4f39031SYitzhak Mandelbaum   auto InlineX =
614d4f39031SYitzhak Mandelbaum       makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
615d4f39031SYitzhak Mandelbaum   testRule(makeRule(functionDecl(hasName("f")).bind("fun"),
616d4f39031SYitzhak Mandelbaum                     [&InlineX](const MatchFinder::MatchResult &R) {
617d4f39031SYitzhak Mandelbaum                       const auto *Node = R.Nodes.getNodeAs<Decl>("fun");
618d4f39031SYitzhak Mandelbaum                       assert(Node != nullptr && "fun must be bound");
619d4f39031SYitzhak Mandelbaum                       return transformer::detail::rewriteDescendants(
620d4f39031SYitzhak Mandelbaum                           *Node, InlineX, R);
621d4f39031SYitzhak Mandelbaum                     }),
622d4f39031SYitzhak Mandelbaum            Input, Expected);
623d4f39031SYitzhak Mandelbaum }
624d4f39031SYitzhak Mandelbaum 
625d4f39031SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsTypedTypeLoc) {
626d4f39031SYitzhak Mandelbaum   std::string Input = "int f(int *x) { return *x; }";
627d4f39031SYitzhak Mandelbaum   std::string Expected = "int f(char *x) { return *x; }";
628d4f39031SYitzhak Mandelbaum   auto IntToChar =
629d4f39031SYitzhak Mandelbaum       makeRule(typeLoc(loc(qualType(isInteger(), builtinType()))).bind("loc"),
630d4f39031SYitzhak Mandelbaum                changeTo(cat("char")));
631d4f39031SYitzhak Mandelbaum   testRule(
632d4f39031SYitzhak Mandelbaum       makeRule(
633d4f39031SYitzhak Mandelbaum           functionDecl(
634d4f39031SYitzhak Mandelbaum               hasName("f"),
635d4f39031SYitzhak Mandelbaum               hasParameter(0, varDecl(hasTypeLoc(typeLoc().bind("parmType"))))),
636d4f39031SYitzhak Mandelbaum           [&IntToChar](const MatchFinder::MatchResult &R) {
637d4f39031SYitzhak Mandelbaum             const auto *Node = R.Nodes.getNodeAs<TypeLoc>("parmType");
638d4f39031SYitzhak Mandelbaum             assert(Node != nullptr && "parmType must be bound");
639d4f39031SYitzhak Mandelbaum             return transformer::detail::rewriteDescendants(*Node, IntToChar, R);
640d4f39031SYitzhak Mandelbaum           }),
641d4f39031SYitzhak Mandelbaum       Input, Expected);
642d4f39031SYitzhak Mandelbaum }
643d4f39031SYitzhak Mandelbaum 
644d4f39031SYitzhak Mandelbaum TEST_F(TransformerTest, RewriteDescendantsTypedDynTyped) {
645d4f39031SYitzhak Mandelbaum   // Add an unrelated definition to the header that also has a variable named
646d4f39031SYitzhak Mandelbaum   // "x", to test that the rewrite is limited to the scope we intend.
647d4f39031SYitzhak Mandelbaum   appendToHeader(R"cc(int g(int x) { return x; })cc");
648d4f39031SYitzhak Mandelbaum   std::string Input =
649d4f39031SYitzhak Mandelbaum       "int f(int x) { int y = x; { int z = x * x; } return x; }";
650d4f39031SYitzhak Mandelbaum   std::string Expected =
651d4f39031SYitzhak Mandelbaum       "int f(int x) { int y = 3; { int z = 3 * 3; } return 3; }";
652d4f39031SYitzhak Mandelbaum   auto InlineX =
653d4f39031SYitzhak Mandelbaum       makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
654d4f39031SYitzhak Mandelbaum   testRule(
655d4f39031SYitzhak Mandelbaum       makeRule(functionDecl(hasName("f"), hasBody(stmt().bind("body"))),
656d4f39031SYitzhak Mandelbaum                [&InlineX](const MatchFinder::MatchResult &R) {
657d4f39031SYitzhak Mandelbaum                  auto It = R.Nodes.getMap().find("body");
658d4f39031SYitzhak Mandelbaum                  assert(It != R.Nodes.getMap().end() && "body must be bound");
659d4f39031SYitzhak Mandelbaum                  return transformer::detail::rewriteDescendants(It->second,
660d4f39031SYitzhak Mandelbaum                                                                 InlineX, R);
661d4f39031SYitzhak Mandelbaum                }),
662d4f39031SYitzhak Mandelbaum       Input, Expected);
663d4f39031SYitzhak Mandelbaum }
664d4f39031SYitzhak Mandelbaum 
6652e4a628cSYitzhak Mandelbaum TEST_F(TransformerTest, InsertBeforeEdit) {
6662e4a628cSYitzhak Mandelbaum   std::string Input = R"cc(
6672e4a628cSYitzhak Mandelbaum     int f() {
6682e4a628cSYitzhak Mandelbaum       return 7;
6692e4a628cSYitzhak Mandelbaum     }
6702e4a628cSYitzhak Mandelbaum   )cc";
6712e4a628cSYitzhak Mandelbaum   std::string Expected = R"cc(
6722e4a628cSYitzhak Mandelbaum     int f() {
6732e4a628cSYitzhak Mandelbaum       int y = 3;
6742e4a628cSYitzhak Mandelbaum       return 7;
6752e4a628cSYitzhak Mandelbaum     }
6762e4a628cSYitzhak Mandelbaum   )cc";
6772e4a628cSYitzhak Mandelbaum 
6782e4a628cSYitzhak Mandelbaum   StringRef Ret = "return";
679adcd0268SBenjamin Kramer   testRule(
680adcd0268SBenjamin Kramer       makeRule(returnStmt().bind(Ret),
681adcd0268SBenjamin Kramer                insertBefore(statement(std::string(Ret)), cat("int y = 3;"))),
6822e4a628cSYitzhak Mandelbaum       Input, Expected);
6832e4a628cSYitzhak Mandelbaum }
6842e4a628cSYitzhak Mandelbaum 
6852e4a628cSYitzhak Mandelbaum TEST_F(TransformerTest, InsertAfterEdit) {
6862e4a628cSYitzhak Mandelbaum   std::string Input = R"cc(
6872e4a628cSYitzhak Mandelbaum     int f() {
6882e4a628cSYitzhak Mandelbaum       int x = 5;
6892e4a628cSYitzhak Mandelbaum       return 7;
6902e4a628cSYitzhak Mandelbaum     }
6912e4a628cSYitzhak Mandelbaum   )cc";
6922e4a628cSYitzhak Mandelbaum   std::string Expected = R"cc(
6932e4a628cSYitzhak Mandelbaum     int f() {
6942e4a628cSYitzhak Mandelbaum       int x = 5;
6952e4a628cSYitzhak Mandelbaum       int y = 3;
6962e4a628cSYitzhak Mandelbaum       return 7;
6972e4a628cSYitzhak Mandelbaum     }
6982e4a628cSYitzhak Mandelbaum   )cc";
6992e4a628cSYitzhak Mandelbaum 
7002e4a628cSYitzhak Mandelbaum   StringRef Decl = "decl";
701adcd0268SBenjamin Kramer   testRule(
702adcd0268SBenjamin Kramer       makeRule(declStmt().bind(Decl),
703adcd0268SBenjamin Kramer                insertAfter(statement(std::string(Decl)), cat("int y = 3;"))),
7042e4a628cSYitzhak Mandelbaum       Input, Expected);
7052e4a628cSYitzhak Mandelbaum }
7062e4a628cSYitzhak Mandelbaum 
7072e4a628cSYitzhak Mandelbaum TEST_F(TransformerTest, RemoveEdit) {
7082e4a628cSYitzhak Mandelbaum   std::string Input = R"cc(
7092e4a628cSYitzhak Mandelbaum     int f() {
7102e4a628cSYitzhak Mandelbaum       int x = 5;
7112e4a628cSYitzhak Mandelbaum       return 7;
7122e4a628cSYitzhak Mandelbaum     }
7132e4a628cSYitzhak Mandelbaum   )cc";
7142e4a628cSYitzhak Mandelbaum   std::string Expected = R"cc(
7152e4a628cSYitzhak Mandelbaum     int f() {
7162e4a628cSYitzhak Mandelbaum       return 7;
7172e4a628cSYitzhak Mandelbaum     }
7182e4a628cSYitzhak Mandelbaum   )cc";
7192e4a628cSYitzhak Mandelbaum 
7202e4a628cSYitzhak Mandelbaum   StringRef Decl = "decl";
721adcd0268SBenjamin Kramer   testRule(
722adcd0268SBenjamin Kramer       makeRule(declStmt().bind(Decl), remove(statement(std::string(Decl)))),
723adcd0268SBenjamin Kramer       Input, Expected);
7242e4a628cSYitzhak Mandelbaum }
7252e4a628cSYitzhak Mandelbaum 
7269945bd59SAndy Soffer TEST_F(TransformerTest, WithMetadata) {
727e5b3202bSAndy Soffer   auto makeMetadata = [](const MatchFinder::MatchResult &R) -> llvm::Any {
728e5b3202bSAndy Soffer     int N =
729e5b3202bSAndy Soffer         R.Nodes.getNodeAs<IntegerLiteral>("int")->getValue().getLimitedValue();
730e5b3202bSAndy Soffer     return N;
731e5b3202bSAndy Soffer   };
732e5b3202bSAndy Soffer 
7339945bd59SAndy Soffer   std::string Input = R"cc(
7349945bd59SAndy Soffer     int f() {
7359945bd59SAndy Soffer       int x = 5;
7369945bd59SAndy Soffer       return 7;
7379945bd59SAndy Soffer     }
7389945bd59SAndy Soffer   )cc";
7399945bd59SAndy Soffer 
7409945bd59SAndy Soffer   Transformer T(
741e5b3202bSAndy Soffer       makeRule(
742e5b3202bSAndy Soffer           declStmt(containsDeclaration(0, varDecl(hasInitializer(
743e5b3202bSAndy Soffer                                               integerLiteral().bind("int")))))
744e5b3202bSAndy Soffer               .bind("decl"),
745e5b3202bSAndy Soffer           withMetadata(remove(statement(std::string("decl"))), makeMetadata)),
7469945bd59SAndy Soffer       consumer());
7479945bd59SAndy Soffer   T.registerMatchers(&MatchFinder);
7489945bd59SAndy Soffer   auto Factory = newFrontendActionFactory(&MatchFinder);
7499945bd59SAndy Soffer   EXPECT_TRUE(runToolOnCodeWithArgs(
7509945bd59SAndy Soffer       Factory->create(), Input, std::vector<std::string>(), "input.cc",
7519945bd59SAndy Soffer       "clang-tool", std::make_shared<PCHContainerOperations>(), {}));
7529945bd59SAndy Soffer   ASSERT_EQ(Changes.size(), 1u);
7539945bd59SAndy Soffer   const llvm::Any &Metadata = Changes[0].getMetadata();
7549945bd59SAndy Soffer   ASSERT_TRUE(llvm::any_isa<int>(Metadata));
755e5b3202bSAndy Soffer   EXPECT_THAT(llvm::any_cast<int>(Metadata), 5);
7569945bd59SAndy Soffer }
7579945bd59SAndy Soffer 
758fa1552e8SYitzhak Mandelbaum TEST_F(TransformerTest, MultiChange) {
759fa1552e8SYitzhak Mandelbaum   std::string Input = R"cc(
760fa1552e8SYitzhak Mandelbaum     void foo() {
761fa1552e8SYitzhak Mandelbaum       if (10 > 1.0)
762fa1552e8SYitzhak Mandelbaum         log(1) << "oh no!";
763fa1552e8SYitzhak Mandelbaum       else
764fa1552e8SYitzhak Mandelbaum         log(0) << "ok";
765fa1552e8SYitzhak Mandelbaum     }
766fa1552e8SYitzhak Mandelbaum   )cc";
767fa1552e8SYitzhak Mandelbaum   std::string Expected = R"(
768fa1552e8SYitzhak Mandelbaum     void foo() {
769fa1552e8SYitzhak Mandelbaum       if (true) { /* then */ }
770fa1552e8SYitzhak Mandelbaum       else { /* else */ }
771fa1552e8SYitzhak Mandelbaum     }
772fa1552e8SYitzhak Mandelbaum   )";
773fa1552e8SYitzhak Mandelbaum 
774fa1552e8SYitzhak Mandelbaum   StringRef C = "C", T = "T", E = "E";
775adcd0268SBenjamin Kramer   testRule(
776adcd0268SBenjamin Kramer       makeRule(ifStmt(hasCondition(expr().bind(C)), hasThen(stmt().bind(T)),
777adcd0268SBenjamin Kramer                       hasElse(stmt().bind(E))),
778adcd0268SBenjamin Kramer                {changeTo(node(std::string(C)), cat("true")),
779adcd0268SBenjamin Kramer                 changeTo(statement(std::string(T)), cat("{ /* then */ }")),
780adcd0268SBenjamin Kramer                 changeTo(statement(std::string(E)), cat("{ /* else */ }"))}),
781fdd98782SYitzhak Mandelbaum       Input, Expected);
782fdd98782SYitzhak Mandelbaum }
783fdd98782SYitzhak Mandelbaum 
784cf428778SYitzhak Mandelbaum TEST_F(TransformerTest, EditList) {
785cf428778SYitzhak Mandelbaum   using clang::transformer::editList;
786cf428778SYitzhak Mandelbaum   std::string Input = R"cc(
787cf428778SYitzhak Mandelbaum     void foo() {
788cf428778SYitzhak Mandelbaum       if (10 > 1.0)
789cf428778SYitzhak Mandelbaum         log(1) << "oh no!";
790cf428778SYitzhak Mandelbaum       else
791cf428778SYitzhak Mandelbaum         log(0) << "ok";
792cf428778SYitzhak Mandelbaum     }
793cf428778SYitzhak Mandelbaum   )cc";
794cf428778SYitzhak Mandelbaum   std::string Expected = R"(
795cf428778SYitzhak Mandelbaum     void foo() {
796cf428778SYitzhak Mandelbaum       if (true) { /* then */ }
797cf428778SYitzhak Mandelbaum       else { /* else */ }
798cf428778SYitzhak Mandelbaum     }
799cf428778SYitzhak Mandelbaum   )";
800cf428778SYitzhak Mandelbaum 
801cf428778SYitzhak Mandelbaum   StringRef C = "C", T = "T", E = "E";
802cf428778SYitzhak Mandelbaum   testRule(makeRule(ifStmt(hasCondition(expr().bind(C)),
803cf428778SYitzhak Mandelbaum                            hasThen(stmt().bind(T)), hasElse(stmt().bind(E))),
804cf428778SYitzhak Mandelbaum                     editList({changeTo(node(std::string(C)), cat("true")),
805cf428778SYitzhak Mandelbaum                               changeTo(statement(std::string(T)),
806cf428778SYitzhak Mandelbaum                                        cat("{ /* then */ }")),
807cf428778SYitzhak Mandelbaum                               changeTo(statement(std::string(E)),
808cf428778SYitzhak Mandelbaum                                        cat("{ /* else */ }"))})),
809cf428778SYitzhak Mandelbaum            Input, Expected);
810cf428778SYitzhak Mandelbaum }
811cf428778SYitzhak Mandelbaum 
812cf428778SYitzhak Mandelbaum TEST_F(TransformerTest, Flatten) {
813cf428778SYitzhak Mandelbaum   using clang::transformer::editList;
814cf428778SYitzhak Mandelbaum   std::string Input = R"cc(
815cf428778SYitzhak Mandelbaum     void foo() {
816cf428778SYitzhak Mandelbaum       if (10 > 1.0)
817cf428778SYitzhak Mandelbaum         log(1) << "oh no!";
818cf428778SYitzhak Mandelbaum       else
819cf428778SYitzhak Mandelbaum         log(0) << "ok";
820cf428778SYitzhak Mandelbaum     }
821cf428778SYitzhak Mandelbaum   )cc";
822cf428778SYitzhak Mandelbaum   std::string Expected = R"(
823cf428778SYitzhak Mandelbaum     void foo() {
824cf428778SYitzhak Mandelbaum       if (true) { /* then */ }
825cf428778SYitzhak Mandelbaum       else { /* else */ }
826cf428778SYitzhak Mandelbaum     }
827cf428778SYitzhak Mandelbaum   )";
828cf428778SYitzhak Mandelbaum 
829cf428778SYitzhak Mandelbaum   StringRef C = "C", T = "T", E = "E";
830cf428778SYitzhak Mandelbaum   testRule(
831cf428778SYitzhak Mandelbaum       makeRule(
832cf428778SYitzhak Mandelbaum           ifStmt(hasCondition(expr().bind(C)), hasThen(stmt().bind(T)),
833cf428778SYitzhak Mandelbaum                  hasElse(stmt().bind(E))),
834cf428778SYitzhak Mandelbaum           flatten(changeTo(node(std::string(C)), cat("true")),
835cf428778SYitzhak Mandelbaum                   changeTo(statement(std::string(T)), cat("{ /* then */ }")),
836cf428778SYitzhak Mandelbaum                   changeTo(statement(std::string(E)), cat("{ /* else */ }")))),
837cf428778SYitzhak Mandelbaum       Input, Expected);
838cf428778SYitzhak Mandelbaum }
839cf428778SYitzhak Mandelbaum 
840cf428778SYitzhak Mandelbaum TEST_F(TransformerTest, FlattenWithMixedArgs) {
841cf428778SYitzhak Mandelbaum   using clang::transformer::editList;
842cf428778SYitzhak Mandelbaum   std::string Input = R"cc(
843cf428778SYitzhak Mandelbaum     void foo() {
844cf428778SYitzhak Mandelbaum       if (10 > 1.0)
845cf428778SYitzhak Mandelbaum         log(1) << "oh no!";
846cf428778SYitzhak Mandelbaum       else
847cf428778SYitzhak Mandelbaum         log(0) << "ok";
848cf428778SYitzhak Mandelbaum     }
849cf428778SYitzhak Mandelbaum   )cc";
850cf428778SYitzhak Mandelbaum   std::string Expected = R"(
851cf428778SYitzhak Mandelbaum     void foo() {
852cf428778SYitzhak Mandelbaum       if (true) { /* then */ }
853cf428778SYitzhak Mandelbaum       else { /* else */ }
854cf428778SYitzhak Mandelbaum     }
855cf428778SYitzhak Mandelbaum   )";
856cf428778SYitzhak Mandelbaum 
857cf428778SYitzhak Mandelbaum   StringRef C = "C", T = "T", E = "E";
858cf428778SYitzhak Mandelbaum   testRule(makeRule(ifStmt(hasCondition(expr().bind(C)),
859cf428778SYitzhak Mandelbaum                            hasThen(stmt().bind(T)), hasElse(stmt().bind(E))),
860cf428778SYitzhak Mandelbaum                     flatten(changeTo(node(std::string(C)), cat("true")),
861cf428778SYitzhak Mandelbaum                             edit(changeTo(statement(std::string(T)),
862cf428778SYitzhak Mandelbaum                                           cat("{ /* then */ }"))),
863cf428778SYitzhak Mandelbaum                             editList({changeTo(statement(std::string(E)),
864cf428778SYitzhak Mandelbaum                                                cat("{ /* else */ }"))}))),
865cf428778SYitzhak Mandelbaum            Input, Expected);
866cf428778SYitzhak Mandelbaum }
867cf428778SYitzhak Mandelbaum 
8688369a9beSYitzhak Mandelbaum TEST_F(TransformerTest, OrderedRuleUnrelated) {
8698369a9beSYitzhak Mandelbaum   StringRef Flag = "flag";
8708369a9beSYitzhak Mandelbaum   RewriteRule FlagRule = makeRule(
8718369a9beSYitzhak Mandelbaum       cxxMemberCallExpr(on(expr(hasType(cxxRecordDecl(
8728369a9beSYitzhak Mandelbaum                                     hasName("proto::ProtoCommandLineFlag"))))
8738369a9beSYitzhak Mandelbaum                                .bind(Flag)),
8748369a9beSYitzhak Mandelbaum                         unless(callee(cxxMethodDecl(hasName("GetProto"))))),
875adcd0268SBenjamin Kramer       changeTo(node(std::string(Flag)), cat("PROTO")));
8768369a9beSYitzhak Mandelbaum 
8778369a9beSYitzhak Mandelbaum   std::string Input = R"cc(
8788369a9beSYitzhak Mandelbaum     proto::ProtoCommandLineFlag flag;
8798369a9beSYitzhak Mandelbaum     int x = flag.foo();
8808369a9beSYitzhak Mandelbaum     int y = flag.GetProto().foo();
8818369a9beSYitzhak Mandelbaum     int f(string s) { return strlen(s.c_str()); }
8828369a9beSYitzhak Mandelbaum   )cc";
8838369a9beSYitzhak Mandelbaum   std::string Expected = R"cc(
8848369a9beSYitzhak Mandelbaum     proto::ProtoCommandLineFlag flag;
8858369a9beSYitzhak Mandelbaum     int x = PROTO.foo();
8868369a9beSYitzhak Mandelbaum     int y = flag.GetProto().foo();
8878369a9beSYitzhak Mandelbaum     int f(string s) { return REPLACED; }
8888369a9beSYitzhak Mandelbaum   )cc";
8898369a9beSYitzhak Mandelbaum 
8908369a9beSYitzhak Mandelbaum   testRule(applyFirst({ruleStrlenSize(), FlagRule}), Input, Expected);
8918369a9beSYitzhak Mandelbaum }
8928369a9beSYitzhak Mandelbaum 
8938369a9beSYitzhak Mandelbaum TEST_F(TransformerTest, OrderedRuleRelated) {
8948369a9beSYitzhak Mandelbaum   std::string Input = R"cc(
89542b957aaSYitzhak Mandelbaum     void f1();
89642b957aaSYitzhak Mandelbaum     void f2();
89742b957aaSYitzhak Mandelbaum     void call_f1() { f1(); }
89842b957aaSYitzhak Mandelbaum     void call_f2() { f2(); }
8998369a9beSYitzhak Mandelbaum   )cc";
9008369a9beSYitzhak Mandelbaum   std::string Expected = R"cc(
90142b957aaSYitzhak Mandelbaum     void f1();
90242b957aaSYitzhak Mandelbaum     void f2();
90342b957aaSYitzhak Mandelbaum     void call_f1() { REPLACE_F1; }
90442b957aaSYitzhak Mandelbaum     void call_f2() { REPLACE_F1_OR_F2; }
9058369a9beSYitzhak Mandelbaum   )cc";
9068369a9beSYitzhak Mandelbaum 
90742b957aaSYitzhak Mandelbaum   RewriteRule ReplaceF1 =
90842b957aaSYitzhak Mandelbaum       makeRule(callExpr(callee(functionDecl(hasName("f1")))),
9099f97480cSYitzhak Mandelbaum                changeTo(cat("REPLACE_F1")));
91042b957aaSYitzhak Mandelbaum   RewriteRule ReplaceF1OrF2 =
91142b957aaSYitzhak Mandelbaum       makeRule(callExpr(callee(functionDecl(hasAnyName("f1", "f2")))),
9129f97480cSYitzhak Mandelbaum                changeTo(cat("REPLACE_F1_OR_F2")));
91342b957aaSYitzhak Mandelbaum   testRule(applyFirst({ReplaceF1, ReplaceF1OrF2}), Input, Expected);
9148369a9beSYitzhak Mandelbaum }
9158369a9beSYitzhak Mandelbaum 
91642b957aaSYitzhak Mandelbaum // Change the order of the rules to get a different result. When `ReplaceF1OrF2`
91742b957aaSYitzhak Mandelbaum // comes first, it applies for both uses, so `ReplaceF1` never applies.
9188369a9beSYitzhak Mandelbaum TEST_F(TransformerTest, OrderedRuleRelatedSwapped) {
9198369a9beSYitzhak Mandelbaum   std::string Input = R"cc(
92042b957aaSYitzhak Mandelbaum     void f1();
92142b957aaSYitzhak Mandelbaum     void f2();
92242b957aaSYitzhak Mandelbaum     void call_f1() { f1(); }
92342b957aaSYitzhak Mandelbaum     void call_f2() { f2(); }
9248369a9beSYitzhak Mandelbaum   )cc";
9258369a9beSYitzhak Mandelbaum   std::string Expected = R"cc(
92642b957aaSYitzhak Mandelbaum     void f1();
92742b957aaSYitzhak Mandelbaum     void f2();
92842b957aaSYitzhak Mandelbaum     void call_f1() { REPLACE_F1_OR_F2; }
92942b957aaSYitzhak Mandelbaum     void call_f2() { REPLACE_F1_OR_F2; }
9308369a9beSYitzhak Mandelbaum   )cc";
9318369a9beSYitzhak Mandelbaum 
93242b957aaSYitzhak Mandelbaum   RewriteRule ReplaceF1 =
93342b957aaSYitzhak Mandelbaum       makeRule(callExpr(callee(functionDecl(hasName("f1")))),
9349f97480cSYitzhak Mandelbaum                changeTo(cat("REPLACE_F1")));
93542b957aaSYitzhak Mandelbaum   RewriteRule ReplaceF1OrF2 =
93642b957aaSYitzhak Mandelbaum       makeRule(callExpr(callee(functionDecl(hasAnyName("f1", "f2")))),
9379f97480cSYitzhak Mandelbaum                changeTo(cat("REPLACE_F1_OR_F2")));
93842b957aaSYitzhak Mandelbaum   testRule(applyFirst({ReplaceF1OrF2, ReplaceF1}), Input, Expected);
93942b957aaSYitzhak Mandelbaum }
94042b957aaSYitzhak Mandelbaum 
94142b957aaSYitzhak Mandelbaum // Verify that a set of rules whose matchers have different base kinds works
94242b957aaSYitzhak Mandelbaum // properly, including that `applyFirst` produces multiple matchers.  We test
94342b957aaSYitzhak Mandelbaum // two different kinds of rules: Expr and Decl. We place the Decl rule in the
94442b957aaSYitzhak Mandelbaum // middle to test that `buildMatchers` works even when the kinds aren't grouped
94542b957aaSYitzhak Mandelbaum // together.
94642b957aaSYitzhak Mandelbaum TEST_F(TransformerTest, OrderedRuleMultipleKinds) {
94742b957aaSYitzhak Mandelbaum   std::string Input = R"cc(
94842b957aaSYitzhak Mandelbaum     void f1();
94942b957aaSYitzhak Mandelbaum     void f2();
95042b957aaSYitzhak Mandelbaum     void call_f1() { f1(); }
95142b957aaSYitzhak Mandelbaum     void call_f2() { f2(); }
95242b957aaSYitzhak Mandelbaum   )cc";
95342b957aaSYitzhak Mandelbaum   std::string Expected = R"cc(
95442b957aaSYitzhak Mandelbaum     void f1();
95542b957aaSYitzhak Mandelbaum     void DECL_RULE();
95642b957aaSYitzhak Mandelbaum     void call_f1() { REPLACE_F1; }
95742b957aaSYitzhak Mandelbaum     void call_f2() { REPLACE_F1_OR_F2; }
95842b957aaSYitzhak Mandelbaum   )cc";
95942b957aaSYitzhak Mandelbaum 
96042b957aaSYitzhak Mandelbaum   RewriteRule ReplaceF1 =
96142b957aaSYitzhak Mandelbaum       makeRule(callExpr(callee(functionDecl(hasName("f1")))),
9629f97480cSYitzhak Mandelbaum                changeTo(cat("REPLACE_F1")));
96342b957aaSYitzhak Mandelbaum   RewriteRule ReplaceF1OrF2 =
96442b957aaSYitzhak Mandelbaum       makeRule(callExpr(callee(functionDecl(hasAnyName("f1", "f2")))),
9659f97480cSYitzhak Mandelbaum                changeTo(cat("REPLACE_F1_OR_F2")));
96642b957aaSYitzhak Mandelbaum   RewriteRule DeclRule = makeRule(functionDecl(hasName("f2")).bind("fun"),
9679f97480cSYitzhak Mandelbaum                                   changeTo(name("fun"), cat("DECL_RULE")));
96842b957aaSYitzhak Mandelbaum 
96942b957aaSYitzhak Mandelbaum   RewriteRule Rule = applyFirst({ReplaceF1, DeclRule, ReplaceF1OrF2});
9708bb47cd8SYitzhak Mandelbaum   EXPECT_EQ(transformer::detail::buildMatchers(Rule).size(), 2UL);
97142b957aaSYitzhak Mandelbaum   testRule(Rule, Input, Expected);
9728369a9beSYitzhak Mandelbaum }
9738369a9beSYitzhak Mandelbaum 
974ce5780b8SYitzhak Mandelbaum // Verifies that a rule with a top-level matcher for an implicit node (like
9756f0a3711SYitzhak Mandelbaum // `implicitCastExpr`) works correctly -- the implicit nodes are not skipped.
976ce5780b8SYitzhak Mandelbaum TEST_F(TransformerTest, OrderedRuleImplicitMatched) {
977ce5780b8SYitzhak Mandelbaum   std::string Input = R"cc(
978ce5780b8SYitzhak Mandelbaum     void f1();
979ce5780b8SYitzhak Mandelbaum     int f2();
980ce5780b8SYitzhak Mandelbaum     void call_f1() { f1(); }
981ce5780b8SYitzhak Mandelbaum     float call_f2() { return f2(); }
982ce5780b8SYitzhak Mandelbaum   )cc";
983ce5780b8SYitzhak Mandelbaum   std::string Expected = R"cc(
984ce5780b8SYitzhak Mandelbaum     void f1();
985ce5780b8SYitzhak Mandelbaum     int f2();
986ce5780b8SYitzhak Mandelbaum     void call_f1() { REPLACE_F1; }
987ce5780b8SYitzhak Mandelbaum     float call_f2() { return REPLACE_F2; }
988ce5780b8SYitzhak Mandelbaum   )cc";
989ce5780b8SYitzhak Mandelbaum 
9906f0a3711SYitzhak Mandelbaum   RewriteRule ReplaceF1 =
9916f0a3711SYitzhak Mandelbaum       makeRule(callExpr(callee(functionDecl(hasName("f1")))),
992ce5780b8SYitzhak Mandelbaum                changeTo(cat("REPLACE_F1")));
993ce5780b8SYitzhak Mandelbaum   RewriteRule ReplaceF2 =
9946f0a3711SYitzhak Mandelbaum       makeRule(implicitCastExpr(hasSourceExpression(callExpr())),
995ce5780b8SYitzhak Mandelbaum                changeTo(cat("REPLACE_F2")));
996ce5780b8SYitzhak Mandelbaum   testRule(applyFirst({ReplaceF1, ReplaceF2}), Input, Expected);
997ce5780b8SYitzhak Mandelbaum }
998ce5780b8SYitzhak Mandelbaum 
999fdd98782SYitzhak Mandelbaum //
1000fdd98782SYitzhak Mandelbaum // Negative tests (where we expect no transformation to occur).
1001fdd98782SYitzhak Mandelbaum //
1002fdd98782SYitzhak Mandelbaum 
1003fa1552e8SYitzhak Mandelbaum // Tests for a conflict in edits from a single match for a rule.
1004aecc59c5SYitzhak Mandelbaum TEST_F(TransformerTest, TextGeneratorFailure) {
1005aecc59c5SYitzhak Mandelbaum   std::string Input = "int conflictOneRule() { return 3 + 7; }";
1006aecc59c5SYitzhak Mandelbaum   // Try to change the whole binary-operator expression AND one its operands:
1007aecc59c5SYitzhak Mandelbaum   StringRef O = "O";
1008489449c2SYitzhak Mandelbaum   class AlwaysFail : public transformer::MatchComputation<std::string> {
1009489449c2SYitzhak Mandelbaum     llvm::Error eval(const ast_matchers::MatchFinder::MatchResult &,
1010489449c2SYitzhak Mandelbaum                      std::string *) const override {
1011aecc59c5SYitzhak Mandelbaum       return llvm::createStringError(llvm::errc::invalid_argument, "ERROR");
1012489449c2SYitzhak Mandelbaum     }
1013489449c2SYitzhak Mandelbaum     std::string toString() const override { return "AlwaysFail"; }
1014aecc59c5SYitzhak Mandelbaum   };
1015adcd0268SBenjamin Kramer   Transformer T(
1016adcd0268SBenjamin Kramer       makeRule(binaryOperator().bind(O),
1017adcd0268SBenjamin Kramer                changeTo(node(std::string(O)), std::make_shared<AlwaysFail>())),
1018aecc59c5SYitzhak Mandelbaum       consumer());
1019aecc59c5SYitzhak Mandelbaum   T.registerMatchers(&MatchFinder);
1020aecc59c5SYitzhak Mandelbaum   EXPECT_FALSE(rewrite(Input));
1021aecc59c5SYitzhak Mandelbaum   EXPECT_THAT(Changes, IsEmpty());
1022aecc59c5SYitzhak Mandelbaum   EXPECT_EQ(ErrorCount, 1);
1023aecc59c5SYitzhak Mandelbaum }
1024aecc59c5SYitzhak Mandelbaum 
1025aecc59c5SYitzhak Mandelbaum // Tests for a conflict in edits from a single match for a rule.
1026fa1552e8SYitzhak Mandelbaum TEST_F(TransformerTest, OverlappingEditsInRule) {
1027fa1552e8SYitzhak Mandelbaum   std::string Input = "int conflictOneRule() { return 3 + 7; }";
1028fa1552e8SYitzhak Mandelbaum   // Try to change the whole binary-operator expression AND one its operands:
1029fa1552e8SYitzhak Mandelbaum   StringRef O = "O", L = "L";
10303ec50e29SYitzhak Mandelbaum   Transformer T(makeRule(binaryOperator(hasLHS(expr().bind(L))).bind(O),
1031adcd0268SBenjamin Kramer                          {changeTo(node(std::string(O)), cat("DELETE_OP")),
1032adcd0268SBenjamin Kramer                           changeTo(node(std::string(L)), cat("DELETE_LHS"))}),
1033aecc59c5SYitzhak Mandelbaum                 consumer());
1034fa1552e8SYitzhak Mandelbaum   T.registerMatchers(&MatchFinder);
1035aecc59c5SYitzhak Mandelbaum   EXPECT_FALSE(rewrite(Input));
1036aecc59c5SYitzhak Mandelbaum   EXPECT_THAT(Changes, IsEmpty());
1037aecc59c5SYitzhak Mandelbaum   EXPECT_EQ(ErrorCount, 1);
1038fa1552e8SYitzhak Mandelbaum }
1039fa1552e8SYitzhak Mandelbaum 
1040fa1552e8SYitzhak Mandelbaum // Tests for a conflict in edits across multiple matches (of the same rule).
1041fa1552e8SYitzhak Mandelbaum TEST_F(TransformerTest, OverlappingEditsMultipleMatches) {
1042fa1552e8SYitzhak Mandelbaum   std::string Input = "int conflictOneRule() { return -7; }";
1043fa1552e8SYitzhak Mandelbaum   // Try to change the whole binary-operator expression AND one its operands:
1044fa1552e8SYitzhak Mandelbaum   StringRef E = "E";
1045adcd0268SBenjamin Kramer   Transformer T(makeRule(expr().bind(E),
1046adcd0268SBenjamin Kramer                          changeTo(node(std::string(E)), cat("DELETE_EXPR"))),
1047aecc59c5SYitzhak Mandelbaum                 consumer());
1048fa1552e8SYitzhak Mandelbaum   T.registerMatchers(&MatchFinder);
1049fa1552e8SYitzhak Mandelbaum   // The rewrite process fails because the changes conflict with each other...
1050fa1552e8SYitzhak Mandelbaum   EXPECT_FALSE(rewrite(Input));
1051aecc59c5SYitzhak Mandelbaum   // ... but two changes were produced.
1052aecc59c5SYitzhak Mandelbaum   EXPECT_EQ(Changes.size(), 2u);
1053aecc59c5SYitzhak Mandelbaum   EXPECT_EQ(ErrorCount, 0);
1054fa1552e8SYitzhak Mandelbaum }
1055fa1552e8SYitzhak Mandelbaum 
1056fa1552e8SYitzhak Mandelbaum TEST_F(TransformerTest, ErrorOccurredMatchSkipped) {
1057fa1552e8SYitzhak Mandelbaum   // Syntax error in the function body:
1058fa1552e8SYitzhak Mandelbaum   std::string Input = "void errorOccurred() { 3 }";
1059aecc59c5SYitzhak Mandelbaum   Transformer T(makeRule(functionDecl(hasName("errorOccurred")),
10609f97480cSYitzhak Mandelbaum                          changeTo(cat("DELETED;"))),
1061aecc59c5SYitzhak Mandelbaum                 consumer());
1062fa1552e8SYitzhak Mandelbaum   T.registerMatchers(&MatchFinder);
1063fa1552e8SYitzhak Mandelbaum   // The rewrite process itself fails...
1064fa1552e8SYitzhak Mandelbaum   EXPECT_FALSE(rewrite(Input));
1065aecc59c5SYitzhak Mandelbaum   // ... and no changes or errors are produced in the process.
1066aecc59c5SYitzhak Mandelbaum   EXPECT_THAT(Changes, IsEmpty());
1067aecc59c5SYitzhak Mandelbaum   EXPECT_EQ(ErrorCount, 0);
1068fa1552e8SYitzhak Mandelbaum }
1069fa1552e8SYitzhak Mandelbaum 
107053df3bebSStephen Kelly TEST_F(TransformerTest, TemplateInstantiation) {
107153df3bebSStephen Kelly 
107253df3bebSStephen Kelly   std::string NonTemplatesInput = R"cpp(
107353df3bebSStephen Kelly struct S {
107453df3bebSStephen Kelly   int m_i;
107553df3bebSStephen Kelly };
107653df3bebSStephen Kelly )cpp";
107753df3bebSStephen Kelly   std::string NonTemplatesExpected = R"cpp(
107853df3bebSStephen Kelly struct S {
107953df3bebSStephen Kelly   safe_int m_i;
108053df3bebSStephen Kelly };
108153df3bebSStephen Kelly )cpp";
108253df3bebSStephen Kelly 
108353df3bebSStephen Kelly   std::string TemplatesInput = R"cpp(
108453df3bebSStephen Kelly template<typename T>
108553df3bebSStephen Kelly struct TemplStruct {
108653df3bebSStephen Kelly   TemplStruct() {}
108753df3bebSStephen Kelly   ~TemplStruct() {}
108853df3bebSStephen Kelly 
108953df3bebSStephen Kelly private:
109053df3bebSStephen Kelly   T m_t;
109153df3bebSStephen Kelly };
109253df3bebSStephen Kelly 
109353df3bebSStephen Kelly void instantiate()
109453df3bebSStephen Kelly {
109553df3bebSStephen Kelly   TemplStruct<int> ti;
109653df3bebSStephen Kelly }
109753df3bebSStephen Kelly )cpp";
109853df3bebSStephen Kelly 
109953df3bebSStephen Kelly   auto MatchedField = fieldDecl(hasType(asString("int"))).bind("theField");
110053df3bebSStephen Kelly 
110153df3bebSStephen Kelly   // Changes the 'int' in 'S', but not the 'T' in 'TemplStruct':
110253df3bebSStephen Kelly   testRule(makeRule(traverse(TK_IgnoreUnlessSpelledInSource, MatchedField),
110353df3bebSStephen Kelly                     changeTo(cat("safe_int ", name("theField")))),
110453df3bebSStephen Kelly            NonTemplatesInput + TemplatesInput,
110553df3bebSStephen Kelly            NonTemplatesExpected + TemplatesInput);
110653df3bebSStephen Kelly 
110753df3bebSStephen Kelly   // In AsIs mode, template instantiations are modified, which is
110853df3bebSStephen Kelly   // often not desired:
110953df3bebSStephen Kelly 
111053df3bebSStephen Kelly   std::string IncorrectTemplatesExpected = R"cpp(
111153df3bebSStephen Kelly template<typename T>
111253df3bebSStephen Kelly struct TemplStruct {
111353df3bebSStephen Kelly   TemplStruct() {}
111453df3bebSStephen Kelly   ~TemplStruct() {}
111553df3bebSStephen Kelly 
111653df3bebSStephen Kelly private:
111753df3bebSStephen Kelly   safe_int m_t;
111853df3bebSStephen Kelly };
111953df3bebSStephen Kelly 
112053df3bebSStephen Kelly void instantiate()
112153df3bebSStephen Kelly {
112253df3bebSStephen Kelly   TemplStruct<int> ti;
112353df3bebSStephen Kelly }
112453df3bebSStephen Kelly )cpp";
112553df3bebSStephen Kelly 
112653df3bebSStephen Kelly   // Changes the 'int' in 'S', and (incorrectly) the 'T' in 'TemplStruct':
112753df3bebSStephen Kelly   testRule(makeRule(traverse(TK_AsIs, MatchedField),
112853df3bebSStephen Kelly                     changeTo(cat("safe_int ", name("theField")))),
112953df3bebSStephen Kelly 
113053df3bebSStephen Kelly            NonTemplatesInput + TemplatesInput,
113153df3bebSStephen Kelly            NonTemplatesExpected + IncorrectTemplatesExpected);
113253df3bebSStephen Kelly }
113353df3bebSStephen Kelly 
11343f1ab737SYitzhak Mandelbaum // Transformation of macro source text when the change encompasses the entirety
11353f1ab737SYitzhak Mandelbaum // of the expanded text.
11363f1ab737SYitzhak Mandelbaum TEST_F(TransformerTest, SimpleMacro) {
1137fdd98782SYitzhak Mandelbaum   std::string Input = R"cc(
11383f1ab737SYitzhak Mandelbaum #define ZERO 0
11393f1ab737SYitzhak Mandelbaum     int f(string s) { return ZERO; }
11403f1ab737SYitzhak Mandelbaum   )cc";
11413f1ab737SYitzhak Mandelbaum   std::string Expected = R"cc(
11423f1ab737SYitzhak Mandelbaum #define ZERO 0
11433f1ab737SYitzhak Mandelbaum     int f(string s) { return 999; }
11443f1ab737SYitzhak Mandelbaum   )cc";
11453f1ab737SYitzhak Mandelbaum 
11463f1ab737SYitzhak Mandelbaum   StringRef zero = "zero";
11473f1ab737SYitzhak Mandelbaum   RewriteRule R = makeRule(integerLiteral(equals(0)).bind(zero),
1148adcd0268SBenjamin Kramer                            changeTo(node(std::string(zero)), cat("999")));
11493f1ab737SYitzhak Mandelbaum   testRule(R, Input, Expected);
1150fdd98782SYitzhak Mandelbaum }
1151fdd98782SYitzhak Mandelbaum 
11523f1ab737SYitzhak Mandelbaum // Transformation of macro source text when the change encompasses the entirety
11533f1ab737SYitzhak Mandelbaum // of the expanded text, for the case of function-style macros.
11543f1ab737SYitzhak Mandelbaum TEST_F(TransformerTest, FunctionMacro) {
11553f1ab737SYitzhak Mandelbaum   std::string Input = R"cc(
11563f1ab737SYitzhak Mandelbaum #define MACRO(str) strlen((str).c_str())
11573f1ab737SYitzhak Mandelbaum     int f(string s) { return MACRO(s); }
11583f1ab737SYitzhak Mandelbaum   )cc";
11593f1ab737SYitzhak Mandelbaum   std::string Expected = R"cc(
11603f1ab737SYitzhak Mandelbaum #define MACRO(str) strlen((str).c_str())
11613f1ab737SYitzhak Mandelbaum     int f(string s) { return REPLACED; }
11623f1ab737SYitzhak Mandelbaum   )cc";
11633f1ab737SYitzhak Mandelbaum 
11643f1ab737SYitzhak Mandelbaum   testRule(ruleStrlenSize(), Input, Expected);
11653f1ab737SYitzhak Mandelbaum }
11663f1ab737SYitzhak Mandelbaum 
11673f1ab737SYitzhak Mandelbaum // Tests that expressions in macro arguments can be rewritten.
11683f1ab737SYitzhak Mandelbaum TEST_F(TransformerTest, MacroArg) {
11693f1ab737SYitzhak Mandelbaum   std::string Input = R"cc(
11703f1ab737SYitzhak Mandelbaum #define PLUS(e) e + 1
11713f1ab737SYitzhak Mandelbaum     int f(string s) { return PLUS(strlen(s.c_str())); }
11723f1ab737SYitzhak Mandelbaum   )cc";
11733f1ab737SYitzhak Mandelbaum   std::string Expected = R"cc(
11743f1ab737SYitzhak Mandelbaum #define PLUS(e) e + 1
11753f1ab737SYitzhak Mandelbaum     int f(string s) { return PLUS(REPLACED); }
11763f1ab737SYitzhak Mandelbaum   )cc";
11773f1ab737SYitzhak Mandelbaum 
11783f1ab737SYitzhak Mandelbaum   testRule(ruleStrlenSize(), Input, Expected);
11793f1ab737SYitzhak Mandelbaum }
11803f1ab737SYitzhak Mandelbaum 
11813f1ab737SYitzhak Mandelbaum // Tests that expressions in macro arguments can be rewritten, even when the
11823f1ab737SYitzhak Mandelbaum // macro call occurs inside another macro's definition.
11833f1ab737SYitzhak Mandelbaum TEST_F(TransformerTest, MacroArgInMacroDef) {
1184fdd98782SYitzhak Mandelbaum   std::string Input = R"cc(
1185fdd98782SYitzhak Mandelbaum #define NESTED(e) e
1186fdd98782SYitzhak Mandelbaum #define MACRO(str) NESTED(strlen((str).c_str()))
11873f1ab737SYitzhak Mandelbaum     int f(string s) { return MACRO(s); }
11883f1ab737SYitzhak Mandelbaum   )cc";
11893f1ab737SYitzhak Mandelbaum   std::string Expected = R"cc(
11903f1ab737SYitzhak Mandelbaum #define NESTED(e) e
11913f1ab737SYitzhak Mandelbaum #define MACRO(str) NESTED(strlen((str).c_str()))
11923f1ab737SYitzhak Mandelbaum     int f(string s) { return REPLACED; }
11933f1ab737SYitzhak Mandelbaum   )cc";
11943f1ab737SYitzhak Mandelbaum 
11953f1ab737SYitzhak Mandelbaum   testRule(ruleStrlenSize(), Input, Expected);
11963f1ab737SYitzhak Mandelbaum }
11973f1ab737SYitzhak Mandelbaum 
11983f1ab737SYitzhak Mandelbaum // Tests the corner case of the identity macro, specifically that it is
11993f1ab737SYitzhak Mandelbaum // discarded in the rewrite rather than preserved (like PLUS is preserved in the
12003f1ab737SYitzhak Mandelbaum // previous test).  This behavior is of dubious value (and marked with a FIXME
12013f1ab737SYitzhak Mandelbaum // in the code), but we test it to verify (and demonstrate) how this case is
12023f1ab737SYitzhak Mandelbaum // handled.
12033f1ab737SYitzhak Mandelbaum TEST_F(TransformerTest, IdentityMacro) {
12043f1ab737SYitzhak Mandelbaum   std::string Input = R"cc(
12053f1ab737SYitzhak Mandelbaum #define ID(e) e
12063f1ab737SYitzhak Mandelbaum     int f(string s) { return ID(strlen(s.c_str())); }
12073f1ab737SYitzhak Mandelbaum   )cc";
12083f1ab737SYitzhak Mandelbaum   std::string Expected = R"cc(
12093f1ab737SYitzhak Mandelbaum #define ID(e) e
12103f1ab737SYitzhak Mandelbaum     int f(string s) { return REPLACED; }
12113f1ab737SYitzhak Mandelbaum   )cc";
12123f1ab737SYitzhak Mandelbaum 
12133f1ab737SYitzhak Mandelbaum   testRule(ruleStrlenSize(), Input, Expected);
12143f1ab737SYitzhak Mandelbaum }
12153f1ab737SYitzhak Mandelbaum 
1216db24ef50SYitzhak Mandelbaum // Tests that two changes in a single macro expansion do not lead to conflicts
1217db24ef50SYitzhak Mandelbaum // in applying the changes.
1218db24ef50SYitzhak Mandelbaum TEST_F(TransformerTest, TwoChangesInOneMacroExpansion) {
1219db24ef50SYitzhak Mandelbaum   std::string Input = R"cc(
1220db24ef50SYitzhak Mandelbaum #define PLUS(a,b) (a) + (b)
1221db24ef50SYitzhak Mandelbaum     int f() { return PLUS(3, 4); }
1222db24ef50SYitzhak Mandelbaum   )cc";
1223db24ef50SYitzhak Mandelbaum   std::string Expected = R"cc(
1224db24ef50SYitzhak Mandelbaum #define PLUS(a,b) (a) + (b)
1225db24ef50SYitzhak Mandelbaum     int f() { return PLUS(LIT, LIT); }
1226db24ef50SYitzhak Mandelbaum   )cc";
1227db24ef50SYitzhak Mandelbaum 
12289f97480cSYitzhak Mandelbaum   testRule(makeRule(integerLiteral(), changeTo(cat("LIT"))), Input, Expected);
1229db24ef50SYitzhak Mandelbaum }
1230db24ef50SYitzhak Mandelbaum 
1231db24ef50SYitzhak Mandelbaum // Tests case where the rule's match spans both source from the macro and its
1232db24ef50SYitzhak Mandelbaum // arg, with the begin location (the "anchor") being the arg.
1233db24ef50SYitzhak Mandelbaum TEST_F(TransformerTest, MatchSpansMacroTextButChangeDoesNot) {
1234db24ef50SYitzhak Mandelbaum   std::string Input = R"cc(
1235db24ef50SYitzhak Mandelbaum #define PLUS_ONE(a) a + 1
1236db24ef50SYitzhak Mandelbaum     int f() { return PLUS_ONE(3); }
1237db24ef50SYitzhak Mandelbaum   )cc";
1238db24ef50SYitzhak Mandelbaum   std::string Expected = R"cc(
1239db24ef50SYitzhak Mandelbaum #define PLUS_ONE(a) a + 1
1240db24ef50SYitzhak Mandelbaum     int f() { return PLUS_ONE(LIT); }
1241db24ef50SYitzhak Mandelbaum   )cc";
1242db24ef50SYitzhak Mandelbaum 
1243db24ef50SYitzhak Mandelbaum   StringRef E = "expr";
1244db24ef50SYitzhak Mandelbaum   testRule(makeRule(binaryOperator(hasLHS(expr().bind(E))),
1245adcd0268SBenjamin Kramer                     changeTo(node(std::string(E)), cat("LIT"))),
1246db24ef50SYitzhak Mandelbaum            Input, Expected);
1247db24ef50SYitzhak Mandelbaum }
1248db24ef50SYitzhak Mandelbaum 
1249db24ef50SYitzhak Mandelbaum // Tests case where the rule's match spans both source from the macro and its
1250db24ef50SYitzhak Mandelbaum // arg, with the begin location (the "anchor") being inside the macro.
1251db24ef50SYitzhak Mandelbaum TEST_F(TransformerTest, MatchSpansMacroTextButChangeDoesNotAnchoredInMacro) {
1252db24ef50SYitzhak Mandelbaum   std::string Input = R"cc(
1253db24ef50SYitzhak Mandelbaum #define PLUS_ONE(a) 1 + a
1254db24ef50SYitzhak Mandelbaum     int f() { return PLUS_ONE(3); }
1255db24ef50SYitzhak Mandelbaum   )cc";
1256db24ef50SYitzhak Mandelbaum   std::string Expected = R"cc(
1257db24ef50SYitzhak Mandelbaum #define PLUS_ONE(a) 1 + a
1258db24ef50SYitzhak Mandelbaum     int f() { return PLUS_ONE(LIT); }
1259db24ef50SYitzhak Mandelbaum   )cc";
1260db24ef50SYitzhak Mandelbaum 
1261db24ef50SYitzhak Mandelbaum   StringRef E = "expr";
1262db24ef50SYitzhak Mandelbaum   testRule(makeRule(binaryOperator(hasRHS(expr().bind(E))),
1263adcd0268SBenjamin Kramer                     changeTo(node(std::string(E)), cat("LIT"))),
1264db24ef50SYitzhak Mandelbaum            Input, Expected);
1265db24ef50SYitzhak Mandelbaum }
1266db24ef50SYitzhak Mandelbaum 
12673f1ab737SYitzhak Mandelbaum // No rewrite is applied when the changed text does not encompass the entirety
12683f1ab737SYitzhak Mandelbaum // of the expanded text. That is, the edit would have to be applied to the
12693f1ab737SYitzhak Mandelbaum // macro's definition to succeed and editing the expansion point would not
12703f1ab737SYitzhak Mandelbaum // suffice.
12713f1ab737SYitzhak Mandelbaum TEST_F(TransformerTest, NoPartialRewriteOMacroExpansion) {
12723f1ab737SYitzhak Mandelbaum   std::string Input = R"cc(
12733f1ab737SYitzhak Mandelbaum #define ZERO_PLUS 0 + 3
12743f1ab737SYitzhak Mandelbaum     int f(string s) { return ZERO_PLUS; })cc";
12753f1ab737SYitzhak Mandelbaum 
12763f1ab737SYitzhak Mandelbaum   StringRef zero = "zero";
12773f1ab737SYitzhak Mandelbaum   RewriteRule R = makeRule(integerLiteral(equals(0)).bind(zero),
1278adcd0268SBenjamin Kramer                            changeTo(node(std::string(zero)), cat("0")));
12793f1ab737SYitzhak Mandelbaum   testRule(R, Input, Input);
12803f1ab737SYitzhak Mandelbaum }
12813f1ab737SYitzhak Mandelbaum 
12823f1ab737SYitzhak Mandelbaum // This test handles the corner case where a macro expands within another macro
12833f1ab737SYitzhak Mandelbaum // to matching code, but that code is an argument to the nested macro call.  A
12843f1ab737SYitzhak Mandelbaum // simple check of isMacroArgExpansion() vs. isMacroBodyExpansion() will get
12853f1ab737SYitzhak Mandelbaum // this wrong, and transform the code.
12863f1ab737SYitzhak Mandelbaum TEST_F(TransformerTest, NoPartialRewriteOfMacroExpansionForMacroArgs) {
12873f1ab737SYitzhak Mandelbaum   std::string Input = R"cc(
12883f1ab737SYitzhak Mandelbaum #define NESTED(e) e
12893f1ab737SYitzhak Mandelbaum #define MACRO(str) 1 + NESTED(strlen((str).c_str()))
12903f1ab737SYitzhak Mandelbaum     int f(string s) { return MACRO(s); }
12913f1ab737SYitzhak Mandelbaum   )cc";
12923f1ab737SYitzhak Mandelbaum 
1293fdd98782SYitzhak Mandelbaum   testRule(ruleStrlenSize(), Input, Input);
1294fdd98782SYitzhak Mandelbaum }
129542b957aaSYitzhak Mandelbaum 
129642b957aaSYitzhak Mandelbaum #if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST
129742b957aaSYitzhak Mandelbaum // Verifies that `Type` and `QualType` are not allowed as top-level matchers in
129842b957aaSYitzhak Mandelbaum // rules.
129942b957aaSYitzhak Mandelbaum TEST(TransformerDeathTest, OrderedRuleTypes) {
13009f97480cSYitzhak Mandelbaum   RewriteRule QualTypeRule = makeRule(qualType(), changeTo(cat("Q")));
13018bb47cd8SYitzhak Mandelbaum   EXPECT_DEATH(transformer::detail::buildMatchers(QualTypeRule),
130242b957aaSYitzhak Mandelbaum                "Matcher must be.*node matcher");
130342b957aaSYitzhak Mandelbaum 
13049f97480cSYitzhak Mandelbaum   RewriteRule TypeRule = makeRule(arrayType(), changeTo(cat("T")));
13058bb47cd8SYitzhak Mandelbaum   EXPECT_DEATH(transformer::detail::buildMatchers(TypeRule),
130642b957aaSYitzhak Mandelbaum                "Matcher must be.*node matcher");
130742b957aaSYitzhak Mandelbaum }
130842b957aaSYitzhak Mandelbaum #endif
1309ff2743bfSYitzhak Mandelbaum 
1310ff2743bfSYitzhak Mandelbaum // Edits are able to span multiple files; in this case, a header and an
1311ff2743bfSYitzhak Mandelbaum // implementation file.
1312ff2743bfSYitzhak Mandelbaum TEST_F(TransformerTest, MultipleFiles) {
1313ff2743bfSYitzhak Mandelbaum   std::string Header = R"cc(void RemoveThisFunction();)cc";
1314ff2743bfSYitzhak Mandelbaum   std::string Source = R"cc(#include "input.h"
1315ff2743bfSYitzhak Mandelbaum                             void RemoveThisFunction();)cc";
1316ff2743bfSYitzhak Mandelbaum   Transformer T(
1317ff2743bfSYitzhak Mandelbaum       makeRule(functionDecl(hasName("RemoveThisFunction")), changeTo(cat(""))),
1318ff2743bfSYitzhak Mandelbaum       consumer());
1319ff2743bfSYitzhak Mandelbaum   T.registerMatchers(&MatchFinder);
1320ff2743bfSYitzhak Mandelbaum   auto Factory = newFrontendActionFactory(&MatchFinder);
1321ff2743bfSYitzhak Mandelbaum   EXPECT_TRUE(runToolOnCodeWithArgs(
1322ff2743bfSYitzhak Mandelbaum       Factory->create(), Source, std::vector<std::string>(), "input.cc",
1323ff2743bfSYitzhak Mandelbaum       "clang-tool", std::make_shared<PCHContainerOperations>(),
1324ff2743bfSYitzhak Mandelbaum       {{"input.h", Header}}));
1325ff2743bfSYitzhak Mandelbaum 
1326ff2743bfSYitzhak Mandelbaum   std::sort(Changes.begin(), Changes.end(),
1327ff2743bfSYitzhak Mandelbaum             [](const AtomicChange &L, const AtomicChange &R) {
1328ff2743bfSYitzhak Mandelbaum               return L.getFilePath() < R.getFilePath();
1329ff2743bfSYitzhak Mandelbaum             });
1330ff2743bfSYitzhak Mandelbaum 
1331ff2743bfSYitzhak Mandelbaum   ASSERT_EQ(Changes[0].getFilePath(), "./input.h");
1332ff2743bfSYitzhak Mandelbaum   EXPECT_THAT(Changes[0].getInsertedHeaders(), IsEmpty());
1333ff2743bfSYitzhak Mandelbaum   EXPECT_THAT(Changes[0].getRemovedHeaders(), IsEmpty());
1334ff2743bfSYitzhak Mandelbaum   llvm::Expected<std::string> UpdatedCode =
1335ff2743bfSYitzhak Mandelbaum       clang::tooling::applyAllReplacements(Header,
1336ff2743bfSYitzhak Mandelbaum                                            Changes[0].getReplacements());
1337ff2743bfSYitzhak Mandelbaum   ASSERT_TRUE(static_cast<bool>(UpdatedCode))
1338ff2743bfSYitzhak Mandelbaum       << "Could not update code: " << llvm::toString(UpdatedCode.takeError());
1339ff2743bfSYitzhak Mandelbaum   EXPECT_EQ(format(*UpdatedCode), format(R"cc(;)cc"));
1340ff2743bfSYitzhak Mandelbaum 
1341ff2743bfSYitzhak Mandelbaum   ASSERT_EQ(Changes[1].getFilePath(), "input.cc");
1342ff2743bfSYitzhak Mandelbaum   EXPECT_THAT(Changes[1].getInsertedHeaders(), IsEmpty());
1343ff2743bfSYitzhak Mandelbaum   EXPECT_THAT(Changes[1].getRemovedHeaders(), IsEmpty());
1344ff2743bfSYitzhak Mandelbaum   UpdatedCode = clang::tooling::applyAllReplacements(
1345ff2743bfSYitzhak Mandelbaum       Source, Changes[1].getReplacements());
1346ff2743bfSYitzhak Mandelbaum   ASSERT_TRUE(static_cast<bool>(UpdatedCode))
1347ff2743bfSYitzhak Mandelbaum       << "Could not update code: " << llvm::toString(UpdatedCode.takeError());
1348ff2743bfSYitzhak Mandelbaum   EXPECT_EQ(format(*UpdatedCode), format(R"cc(#include "input.h"
1349ff2743bfSYitzhak Mandelbaum                         ;)cc"));
1350ff2743bfSYitzhak Mandelbaum }
1351d8c1f43dSYitzhak Mandelbaum 
1352d8c1f43dSYitzhak Mandelbaum TEST_F(TransformerTest, AddIncludeMultipleFiles) {
1353d8c1f43dSYitzhak Mandelbaum   std::string Header = R"cc(void RemoveThisFunction();)cc";
1354d8c1f43dSYitzhak Mandelbaum   std::string Source = R"cc(#include "input.h"
1355d8c1f43dSYitzhak Mandelbaum                             void Foo() {RemoveThisFunction();})cc";
1356d8c1f43dSYitzhak Mandelbaum   Transformer T(
1357d8c1f43dSYitzhak Mandelbaum       makeRule(callExpr(callee(
1358d8c1f43dSYitzhak Mandelbaum                    functionDecl(hasName("RemoveThisFunction")).bind("fun"))),
1359d8c1f43dSYitzhak Mandelbaum                addInclude(node("fun"), "header.h")),
1360d8c1f43dSYitzhak Mandelbaum       consumer());
1361d8c1f43dSYitzhak Mandelbaum   T.registerMatchers(&MatchFinder);
1362d8c1f43dSYitzhak Mandelbaum   auto Factory = newFrontendActionFactory(&MatchFinder);
1363d8c1f43dSYitzhak Mandelbaum   EXPECT_TRUE(runToolOnCodeWithArgs(
1364d8c1f43dSYitzhak Mandelbaum       Factory->create(), Source, std::vector<std::string>(), "input.cc",
1365d8c1f43dSYitzhak Mandelbaum       "clang-tool", std::make_shared<PCHContainerOperations>(),
1366d8c1f43dSYitzhak Mandelbaum       {{"input.h", Header}}));
1367d8c1f43dSYitzhak Mandelbaum 
1368d8c1f43dSYitzhak Mandelbaum   ASSERT_EQ(Changes.size(), 1U);
1369d8c1f43dSYitzhak Mandelbaum   ASSERT_EQ(Changes[0].getFilePath(), "./input.h");
1370d8c1f43dSYitzhak Mandelbaum   EXPECT_THAT(Changes[0].getInsertedHeaders(), ElementsAre("header.h"));
1371d8c1f43dSYitzhak Mandelbaum   EXPECT_THAT(Changes[0].getRemovedHeaders(), IsEmpty());
1372d8c1f43dSYitzhak Mandelbaum   llvm::Expected<std::string> UpdatedCode =
1373d8c1f43dSYitzhak Mandelbaum       clang::tooling::applyAllReplacements(Header,
1374d8c1f43dSYitzhak Mandelbaum                                            Changes[0].getReplacements());
1375d8c1f43dSYitzhak Mandelbaum   ASSERT_TRUE(static_cast<bool>(UpdatedCode))
1376d8c1f43dSYitzhak Mandelbaum       << "Could not update code: " << llvm::toString(UpdatedCode.takeError());
1377d8c1f43dSYitzhak Mandelbaum   EXPECT_EQ(format(*UpdatedCode), format(Header));
1378d8c1f43dSYitzhak Mandelbaum }
1379fdd98782SYitzhak Mandelbaum } // namespace
1380