1 //===- unittest/Tooling/TransformerTest.cpp -------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "clang/Tooling/Transformer/Transformer.h"
10 #include "clang/ASTMatchers/ASTMatchers.h"
11 #include "clang/Tooling/Tooling.h"
12 #include "clang/Tooling/Transformer/RangeSelector.h"
13 #include "clang/Tooling/Transformer/Stencil.h"
14 #include "llvm/Support/Errc.h"
15 #include "llvm/Support/Error.h"
16 #include "gmock/gmock.h"
17 #include "gtest/gtest.h"
18 
19 using namespace clang;
20 using namespace tooling;
21 using namespace ast_matchers;
22 namespace {
23 using ::testing::IsEmpty;
24 using transformer::cat;
25 using transformer::changeTo;
26 using transformer::RewriteRule;
27 
28 constexpr char KHeaderContents[] = R"cc(
29   struct string {
30     string(const char*);
31     char* c_str();
32     int size();
33   };
34   int strlen(const char*);
35 
36   namespace proto {
37   struct PCFProto {
38     int foo();
39   };
40   struct ProtoCommandLineFlag : PCFProto {
41     PCFProto& GetProto();
42   };
43   }  // namespace proto
44   class Logger {};
45   void operator<<(Logger& l, string msg);
46   Logger& log(int level);
47 )cc";
48 
49 static ast_matchers::internal::Matcher<clang::QualType>
isOrPointsTo(const clang::ast_matchers::DeclarationMatcher & TypeMatcher)50 isOrPointsTo(const clang::ast_matchers::DeclarationMatcher &TypeMatcher) {
51   return anyOf(hasDeclaration(TypeMatcher), pointsTo(TypeMatcher));
52 }
53 
format(StringRef Code)54 static std::string format(StringRef Code) {
55   const std::vector<Range> Ranges(1, Range(0, Code.size()));
56   auto Style = format::getLLVMStyle();
57   const auto Replacements = format::reformat(Style, Code, Ranges);
58   auto Formatted = applyAllReplacements(Code, Replacements);
59   if (!Formatted) {
60     ADD_FAILURE() << "Could not format code: "
61                   << llvm::toString(Formatted.takeError());
62     return std::string();
63   }
64   return *Formatted;
65 }
66 
compareSnippets(StringRef Expected,const llvm::Optional<std::string> & MaybeActual)67 static void compareSnippets(StringRef Expected,
68                      const llvm::Optional<std::string> &MaybeActual) {
69   ASSERT_TRUE(MaybeActual) << "Rewrite failed. Expecting: " << Expected;
70   auto Actual = *MaybeActual;
71   std::string HL = "#include \"header.h\"\n";
72   auto I = Actual.find(HL);
73   if (I != std::string::npos)
74     Actual.erase(I, HL.size());
75   EXPECT_EQ(format(Expected), format(Actual));
76 }
77 
78 // FIXME: consider separating this class into its own file(s).
79 class ClangRefactoringTestBase : public testing::Test {
80 protected:
appendToHeader(StringRef S)81   void appendToHeader(StringRef S) { FileContents[0].second += S; }
82 
addFile(StringRef Filename,StringRef Content)83   void addFile(StringRef Filename, StringRef Content) {
84     FileContents.emplace_back(std::string(Filename), std::string(Content));
85   }
86 
rewrite(StringRef Input)87   llvm::Optional<std::string> rewrite(StringRef Input) {
88     std::string Code = ("#include \"header.h\"\n" + Input).str();
89     auto Factory = newFrontendActionFactory(&MatchFinder);
90     if (!runToolOnCodeWithArgs(
91             Factory->create(), Code, std::vector<std::string>(), "input.cc",
92             "clang-tool", std::make_shared<PCHContainerOperations>(),
93             FileContents)) {
94       llvm::errs() << "Running tool failed.\n";
95       return None;
96     }
97     if (ErrorCount != 0) {
98       llvm::errs() << "Generating changes failed.\n";
99       return None;
100     }
101     auto ChangedCode =
102         applyAtomicChanges("input.cc", Code, Changes, ApplyChangesSpec());
103     if (!ChangedCode) {
104       llvm::errs() << "Applying changes failed: "
105                    << llvm::toString(ChangedCode.takeError()) << "\n";
106       return None;
107     }
108     return *ChangedCode;
109   }
110 
consumer()111   Transformer::ChangeConsumer consumer() {
112     return [this](Expected<AtomicChange> C) {
113       if (C) {
114         Changes.push_back(std::move(*C));
115       } else {
116         consumeError(C.takeError());
117         ++ErrorCount;
118       }
119     };
120   }
121 
122   template <typename R>
testRule(R Rule,StringRef Input,StringRef Expected)123   void testRule(R Rule, StringRef Input, StringRef Expected) {
124     Transformer T(std::move(Rule), consumer());
125     T.registerMatchers(&MatchFinder);
126     compareSnippets(Expected, rewrite(Input));
127   }
128 
129   clang::ast_matchers::MatchFinder MatchFinder;
130   // Records whether any errors occurred in individual changes.
131   int ErrorCount = 0;
132   AtomicChanges Changes;
133 
134 private:
135   FileContentMappings FileContents = {{"header.h", ""}};
136 };
137 
138 class TransformerTest : public ClangRefactoringTestBase {
139 protected:
TransformerTest()140   TransformerTest() { appendToHeader(KHeaderContents); }
141 };
142 
143 // Given string s, change strlen($s.c_str()) to REPLACED.
ruleStrlenSize()144 static RewriteRule ruleStrlenSize() {
145   StringRef StringExpr = "strexpr";
146   auto StringType = namedDecl(hasAnyName("::basic_string", "::string"));
147   auto R = makeRule(
148       callExpr(callee(functionDecl(hasName("strlen"))),
149                hasArgument(0, cxxMemberCallExpr(
150                                   on(expr(hasType(isOrPointsTo(StringType)))
151                                          .bind(StringExpr)),
152                                   callee(cxxMethodDecl(hasName("c_str")))))),
153       changeTo(cat("REPLACED")), cat("Use size() method directly on string."));
154   return R;
155 }
156 
TEST_F(TransformerTest,StrlenSize)157 TEST_F(TransformerTest, StrlenSize) {
158   std::string Input = "int f(string s) { return strlen(s.c_str()); }";
159   std::string Expected = "int f(string s) { return REPLACED; }";
160   testRule(ruleStrlenSize(), Input, Expected);
161 }
162 
163 // Tests that no change is applied when a match is not expected.
TEST_F(TransformerTest,NoMatch)164 TEST_F(TransformerTest, NoMatch) {
165   std::string Input = "int f(string s) { return s.size(); }";
166   testRule(ruleStrlenSize(), Input, Input);
167 }
168 
169 // Tests replacing an expression.
TEST_F(TransformerTest,Flag)170 TEST_F(TransformerTest, Flag) {
171   StringRef Flag = "flag";
172   RewriteRule Rule = makeRule(
173       cxxMemberCallExpr(on(expr(hasType(cxxRecordDecl(
174                                     hasName("proto::ProtoCommandLineFlag"))))
175                                .bind(Flag)),
176                         unless(callee(cxxMethodDecl(hasName("GetProto"))))),
177       changeTo(node(std::string(Flag)), cat("EXPR")));
178 
179   std::string Input = R"cc(
180     proto::ProtoCommandLineFlag flag;
181     int x = flag.foo();
182     int y = flag.GetProto().foo();
183   )cc";
184   std::string Expected = R"cc(
185     proto::ProtoCommandLineFlag flag;
186     int x = EXPR.foo();
187     int y = flag.GetProto().foo();
188   )cc";
189 
190   testRule(std::move(Rule), Input, Expected);
191 }
192 
TEST_F(TransformerTest,AddIncludeQuoted)193 TEST_F(TransformerTest, AddIncludeQuoted) {
194   RewriteRule Rule = makeRule(callExpr(callee(functionDecl(hasName("f")))),
195                               changeTo(cat("other()")));
196   addInclude(Rule, "clang/OtherLib.h");
197 
198   std::string Input = R"cc(
199     int f(int x);
200     int h(int x) { return f(x); }
201   )cc";
202   std::string Expected = R"cc(#include "clang/OtherLib.h"
203 
204     int f(int x);
205     int h(int x) { return other(); }
206   )cc";
207 
208   testRule(Rule, Input, Expected);
209 }
210 
TEST_F(TransformerTest,AddIncludeAngled)211 TEST_F(TransformerTest, AddIncludeAngled) {
212   RewriteRule Rule = makeRule(callExpr(callee(functionDecl(hasName("f")))),
213                               changeTo(cat("other()")));
214   addInclude(Rule, "clang/OtherLib.h", transformer::IncludeFormat::Angled);
215 
216   std::string Input = R"cc(
217     int f(int x);
218     int h(int x) { return f(x); }
219   )cc";
220   std::string Expected = R"cc(#include <clang/OtherLib.h>
221 
222     int f(int x);
223     int h(int x) { return other(); }
224   )cc";
225 
226   testRule(Rule, Input, Expected);
227 }
228 
TEST_F(TransformerTest,NodePartNameNamedDecl)229 TEST_F(TransformerTest, NodePartNameNamedDecl) {
230   StringRef Fun = "fun";
231   RewriteRule Rule = makeRule(functionDecl(hasName("bad")).bind(Fun),
232                               changeTo(name(std::string(Fun)), cat("good")));
233 
234   std::string Input = R"cc(
235     int bad(int x);
236     int bad(int x) { return x * x; }
237   )cc";
238   std::string Expected = R"cc(
239     int good(int x);
240     int good(int x) { return x * x; }
241   )cc";
242 
243   testRule(Rule, Input, Expected);
244 }
245 
TEST_F(TransformerTest,NodePartNameDeclRef)246 TEST_F(TransformerTest, NodePartNameDeclRef) {
247   std::string Input = R"cc(
248     template <typename T>
249     T bad(T x) {
250       return x;
251     }
252     int neutral(int x) { return bad<int>(x) * x; }
253   )cc";
254   std::string Expected = R"cc(
255     template <typename T>
256     T bad(T x) {
257       return x;
258     }
259     int neutral(int x) { return good<int>(x) * x; }
260   )cc";
261 
262   StringRef Ref = "ref";
263   testRule(makeRule(declRefExpr(to(functionDecl(hasName("bad")))).bind(Ref),
264                     changeTo(name(std::string(Ref)), cat("good"))),
265            Input, Expected);
266 }
267 
TEST_F(TransformerTest,NodePartNameDeclRefFailure)268 TEST_F(TransformerTest, NodePartNameDeclRefFailure) {
269   std::string Input = R"cc(
270     struct Y {
271       int operator*();
272     };
273     int neutral(int x) {
274       Y y;
275       int (Y::*ptr)() = &Y::operator*;
276       return *y + x;
277     }
278   )cc";
279 
280   StringRef Ref = "ref";
281   Transformer T(makeRule(declRefExpr(to(functionDecl())).bind(Ref),
282                          changeTo(name(std::string(Ref)), cat("good"))),
283                 consumer());
284   T.registerMatchers(&MatchFinder);
285   EXPECT_FALSE(rewrite(Input));
286 }
287 
TEST_F(TransformerTest,NodePartMember)288 TEST_F(TransformerTest, NodePartMember) {
289   StringRef E = "expr";
290   RewriteRule Rule = makeRule(memberExpr(member(hasName("bad"))).bind(E),
291                               changeTo(member(std::string(E)), cat("good")));
292 
293   std::string Input = R"cc(
294     struct S {
295       int bad;
296     };
297     int g() {
298       S s;
299       return s.bad;
300     }
301   )cc";
302   std::string Expected = R"cc(
303     struct S {
304       int bad;
305     };
306     int g() {
307       S s;
308       return s.good;
309     }
310   )cc";
311 
312   testRule(Rule, Input, Expected);
313 }
314 
TEST_F(TransformerTest,NodePartMemberQualified)315 TEST_F(TransformerTest, NodePartMemberQualified) {
316   std::string Input = R"cc(
317     struct S {
318       int bad;
319       int good;
320     };
321     struct T : public S {
322       int bad;
323     };
324     int g() {
325       T t;
326       return t.S::bad;
327     }
328   )cc";
329   std::string Expected = R"cc(
330     struct S {
331       int bad;
332       int good;
333     };
334     struct T : public S {
335       int bad;
336     };
337     int g() {
338       T t;
339       return t.S::good;
340     }
341   )cc";
342 
343   StringRef E = "expr";
344   testRule(makeRule(memberExpr().bind(E),
345                     changeTo(member(std::string(E)), cat("good"))),
346            Input, Expected);
347 }
348 
TEST_F(TransformerTest,NodePartMemberMultiToken)349 TEST_F(TransformerTest, NodePartMemberMultiToken) {
350   std::string Input = R"cc(
351     struct Y {
352       int operator*();
353       int good();
354       template <typename T> void foo(T t);
355     };
356     int neutral(int x) {
357       Y y;
358       y.template foo<int>(3);
359       return y.operator *();
360     }
361   )cc";
362   std::string Expected = R"cc(
363     struct Y {
364       int operator*();
365       int good();
366       template <typename T> void foo(T t);
367     };
368     int neutral(int x) {
369       Y y;
370       y.template good<int>(3);
371       return y.good();
372     }
373   )cc";
374 
375   StringRef MemExpr = "member";
376   testRule(makeRule(memberExpr().bind(MemExpr),
377                     changeTo(member(std::string(MemExpr)), cat("good"))),
378            Input, Expected);
379 }
380 
TEST_F(TransformerTest,InsertBeforeEdit)381 TEST_F(TransformerTest, InsertBeforeEdit) {
382   std::string Input = R"cc(
383     int f() {
384       return 7;
385     }
386   )cc";
387   std::string Expected = R"cc(
388     int f() {
389       int y = 3;
390       return 7;
391     }
392   )cc";
393 
394   StringRef Ret = "return";
395   testRule(
396       makeRule(returnStmt().bind(Ret),
397                insertBefore(statement(std::string(Ret)), cat("int y = 3;"))),
398       Input, Expected);
399 }
400 
TEST_F(TransformerTest,InsertAfterEdit)401 TEST_F(TransformerTest, InsertAfterEdit) {
402   std::string Input = R"cc(
403     int f() {
404       int x = 5;
405       return 7;
406     }
407   )cc";
408   std::string Expected = R"cc(
409     int f() {
410       int x = 5;
411       int y = 3;
412       return 7;
413     }
414   )cc";
415 
416   StringRef Decl = "decl";
417   testRule(
418       makeRule(declStmt().bind(Decl),
419                insertAfter(statement(std::string(Decl)), cat("int y = 3;"))),
420       Input, Expected);
421 }
422 
TEST_F(TransformerTest,RemoveEdit)423 TEST_F(TransformerTest, RemoveEdit) {
424   std::string Input = R"cc(
425     int f() {
426       int x = 5;
427       return 7;
428     }
429   )cc";
430   std::string Expected = R"cc(
431     int f() {
432       return 7;
433     }
434   )cc";
435 
436   StringRef Decl = "decl";
437   testRule(
438       makeRule(declStmt().bind(Decl), remove(statement(std::string(Decl)))),
439       Input, Expected);
440 }
441 
TEST_F(TransformerTest,WithMetadata)442 TEST_F(TransformerTest, WithMetadata) {
443   std::string Input = R"cc(
444     int f() {
445       int x = 5;
446       return 7;
447     }
448   )cc";
449 
450   Transformer T(
451       makeRule(declStmt().bind("decl"),
452                withMetadata(remove(statement(std::string("decl"))), 17)),
453       consumer());
454   T.registerMatchers(&MatchFinder);
455   auto Factory = newFrontendActionFactory(&MatchFinder);
456   EXPECT_TRUE(runToolOnCodeWithArgs(
457       Factory->create(), Input, std::vector<std::string>(), "input.cc",
458       "clang-tool", std::make_shared<PCHContainerOperations>(), {}));
459   ASSERT_EQ(Changes.size(), 1u);
460   const llvm::Any &Metadata = Changes[0].getMetadata();
461   ASSERT_TRUE(llvm::any_isa<int>(Metadata));
462   EXPECT_THAT(llvm::any_cast<int>(Metadata), 17);
463 }
464 
TEST_F(TransformerTest,MultiChange)465 TEST_F(TransformerTest, MultiChange) {
466   std::string Input = R"cc(
467     void foo() {
468       if (10 > 1.0)
469         log(1) << "oh no!";
470       else
471         log(0) << "ok";
472     }
473   )cc";
474   std::string Expected = R"(
475     void foo() {
476       if (true) { /* then */ }
477       else { /* else */ }
478     }
479   )";
480 
481   StringRef C = "C", T = "T", E = "E";
482   testRule(
483       makeRule(ifStmt(hasCondition(expr().bind(C)), hasThen(stmt().bind(T)),
484                       hasElse(stmt().bind(E))),
485                {changeTo(node(std::string(C)), cat("true")),
486                 changeTo(statement(std::string(T)), cat("{ /* then */ }")),
487                 changeTo(statement(std::string(E)), cat("{ /* else */ }"))}),
488       Input, Expected);
489 }
490 
TEST_F(TransformerTest,OrderedRuleUnrelated)491 TEST_F(TransformerTest, OrderedRuleUnrelated) {
492   StringRef Flag = "flag";
493   RewriteRule FlagRule = makeRule(
494       cxxMemberCallExpr(on(expr(hasType(cxxRecordDecl(
495                                     hasName("proto::ProtoCommandLineFlag"))))
496                                .bind(Flag)),
497                         unless(callee(cxxMethodDecl(hasName("GetProto"))))),
498       changeTo(node(std::string(Flag)), cat("PROTO")));
499 
500   std::string Input = R"cc(
501     proto::ProtoCommandLineFlag flag;
502     int x = flag.foo();
503     int y = flag.GetProto().foo();
504     int f(string s) { return strlen(s.c_str()); }
505   )cc";
506   std::string Expected = R"cc(
507     proto::ProtoCommandLineFlag flag;
508     int x = PROTO.foo();
509     int y = flag.GetProto().foo();
510     int f(string s) { return REPLACED; }
511   )cc";
512 
513   testRule(applyFirst({ruleStrlenSize(), FlagRule}), Input, Expected);
514 }
515 
TEST_F(TransformerTest,OrderedRuleRelated)516 TEST_F(TransformerTest, OrderedRuleRelated) {
517   std::string Input = R"cc(
518     void f1();
519     void f2();
520     void call_f1() { f1(); }
521     void call_f2() { f2(); }
522   )cc";
523   std::string Expected = R"cc(
524     void f1();
525     void f2();
526     void call_f1() { REPLACE_F1; }
527     void call_f2() { REPLACE_F1_OR_F2; }
528   )cc";
529 
530   RewriteRule ReplaceF1 =
531       makeRule(callExpr(callee(functionDecl(hasName("f1")))),
532                changeTo(cat("REPLACE_F1")));
533   RewriteRule ReplaceF1OrF2 =
534       makeRule(callExpr(callee(functionDecl(hasAnyName("f1", "f2")))),
535                changeTo(cat("REPLACE_F1_OR_F2")));
536   testRule(applyFirst({ReplaceF1, ReplaceF1OrF2}), Input, Expected);
537 }
538 
539 // Change the order of the rules to get a different result. When `ReplaceF1OrF2`
540 // comes first, it applies for both uses, so `ReplaceF1` never applies.
TEST_F(TransformerTest,OrderedRuleRelatedSwapped)541 TEST_F(TransformerTest, OrderedRuleRelatedSwapped) {
542   std::string Input = R"cc(
543     void f1();
544     void f2();
545     void call_f1() { f1(); }
546     void call_f2() { f2(); }
547   )cc";
548   std::string Expected = R"cc(
549     void f1();
550     void f2();
551     void call_f1() { REPLACE_F1_OR_F2; }
552     void call_f2() { REPLACE_F1_OR_F2; }
553   )cc";
554 
555   RewriteRule ReplaceF1 =
556       makeRule(callExpr(callee(functionDecl(hasName("f1")))),
557                changeTo(cat("REPLACE_F1")));
558   RewriteRule ReplaceF1OrF2 =
559       makeRule(callExpr(callee(functionDecl(hasAnyName("f1", "f2")))),
560                changeTo(cat("REPLACE_F1_OR_F2")));
561   testRule(applyFirst({ReplaceF1OrF2, ReplaceF1}), Input, Expected);
562 }
563 
564 // Verify that a set of rules whose matchers have different base kinds works
565 // properly, including that `applyFirst` produces multiple matchers.  We test
566 // two different kinds of rules: Expr and Decl. We place the Decl rule in the
567 // middle to test that `buildMatchers` works even when the kinds aren't grouped
568 // together.
TEST_F(TransformerTest,OrderedRuleMultipleKinds)569 TEST_F(TransformerTest, OrderedRuleMultipleKinds) {
570   std::string Input = R"cc(
571     void f1();
572     void f2();
573     void call_f1() { f1(); }
574     void call_f2() { f2(); }
575   )cc";
576   std::string Expected = R"cc(
577     void f1();
578     void DECL_RULE();
579     void call_f1() { REPLACE_F1; }
580     void call_f2() { REPLACE_F1_OR_F2; }
581   )cc";
582 
583   RewriteRule ReplaceF1 =
584       makeRule(callExpr(callee(functionDecl(hasName("f1")))),
585                changeTo(cat("REPLACE_F1")));
586   RewriteRule ReplaceF1OrF2 =
587       makeRule(callExpr(callee(functionDecl(hasAnyName("f1", "f2")))),
588                changeTo(cat("REPLACE_F1_OR_F2")));
589   RewriteRule DeclRule = makeRule(functionDecl(hasName("f2")).bind("fun"),
590                                   changeTo(name("fun"), cat("DECL_RULE")));
591 
592   RewriteRule Rule = applyFirst({ReplaceF1, DeclRule, ReplaceF1OrF2});
593   EXPECT_EQ(transformer::detail::buildMatchers(Rule).size(), 2UL);
594   testRule(Rule, Input, Expected);
595 }
596 
597 // Verifies that a rule with a top-level matcher for an implicit node (like
598 // `implicitCastExpr`) does not change the code, when the AST traversal skips
599 // implicit nodes. In this test, only the rule with the explicit-node matcher
600 // will fire.
TEST_F(TransformerTest,OrderedRuleImplicitIgnored)601 TEST_F(TransformerTest, OrderedRuleImplicitIgnored) {
602   std::string Input = R"cc(
603     void f1();
604     int f2();
605     void call_f1() { f1(); }
606     float call_f2() { return f2(); }
607   )cc";
608   std::string Expected = R"cc(
609     void f1();
610     int f2();
611     void call_f1() { REPLACE_F1; }
612     float call_f2() { return f2(); }
613   )cc";
614 
615   RewriteRule ReplaceF1 =
616       makeRule(callExpr(callee(functionDecl(hasName("f1")))),
617                changeTo(cat("REPLACE_F1")));
618   RewriteRule ReplaceF2 =
619       makeRule(implicitCastExpr(hasSourceExpression(callExpr())),
620                changeTo(cat("REPLACE_F2")));
621   testRule(applyFirst({ReplaceF1, ReplaceF2}), Input, Expected);
622 }
623 
624 // Verifies that explicitly setting the traversal kind fixes the problem in the
625 // previous test.
TEST_F(TransformerTest,OrderedRuleImplicitMatched)626 TEST_F(TransformerTest, OrderedRuleImplicitMatched) {
627   std::string Input = R"cc(
628     void f1();
629     int f2();
630     void call_f1() { f1(); }
631     float call_f2() { return f2(); }
632   )cc";
633   std::string Expected = R"cc(
634     void f1();
635     int f2();
636     void call_f1() { REPLACE_F1; }
637     float call_f2() { return REPLACE_F2; }
638   )cc";
639 
640   RewriteRule ReplaceF1 = makeRule(
641       traverse(clang::TK_AsIs, callExpr(callee(functionDecl(hasName("f1"))))),
642       changeTo(cat("REPLACE_F1")));
643   RewriteRule ReplaceF2 =
644       makeRule(traverse(clang::TK_AsIs,
645                         implicitCastExpr(hasSourceExpression(callExpr()))),
646                changeTo(cat("REPLACE_F2")));
647   testRule(applyFirst({ReplaceF1, ReplaceF2}), Input, Expected);
648 }
649 
650 //
651 // Negative tests (where we expect no transformation to occur).
652 //
653 
654 // Tests for a conflict in edits from a single match for a rule.
TEST_F(TransformerTest,TextGeneratorFailure)655 TEST_F(TransformerTest, TextGeneratorFailure) {
656   std::string Input = "int conflictOneRule() { return 3 + 7; }";
657   // Try to change the whole binary-operator expression AND one its operands:
658   StringRef O = "O";
659   class AlwaysFail : public transformer::MatchComputation<std::string> {
660     llvm::Error eval(const ast_matchers::MatchFinder::MatchResult &,
661                      std::string *) const override {
662       return llvm::createStringError(llvm::errc::invalid_argument, "ERROR");
663     }
664     std::string toString() const override { return "AlwaysFail"; }
665   };
666   Transformer T(
667       makeRule(binaryOperator().bind(O),
668                changeTo(node(std::string(O)), std::make_shared<AlwaysFail>())),
669       consumer());
670   T.registerMatchers(&MatchFinder);
671   EXPECT_FALSE(rewrite(Input));
672   EXPECT_THAT(Changes, IsEmpty());
673   EXPECT_EQ(ErrorCount, 1);
674 }
675 
676 // Tests for a conflict in edits from a single match for a rule.
TEST_F(TransformerTest,OverlappingEditsInRule)677 TEST_F(TransformerTest, OverlappingEditsInRule) {
678   std::string Input = "int conflictOneRule() { return 3 + 7; }";
679   // Try to change the whole binary-operator expression AND one its operands:
680   StringRef O = "O", L = "L";
681   Transformer T(makeRule(binaryOperator(hasLHS(expr().bind(L))).bind(O),
682                          {changeTo(node(std::string(O)), cat("DELETE_OP")),
683                           changeTo(node(std::string(L)), cat("DELETE_LHS"))}),
684                 consumer());
685   T.registerMatchers(&MatchFinder);
686   EXPECT_FALSE(rewrite(Input));
687   EXPECT_THAT(Changes, IsEmpty());
688   EXPECT_EQ(ErrorCount, 1);
689 }
690 
691 // Tests for a conflict in edits across multiple matches (of the same rule).
TEST_F(TransformerTest,OverlappingEditsMultipleMatches)692 TEST_F(TransformerTest, OverlappingEditsMultipleMatches) {
693   std::string Input = "int conflictOneRule() { return -7; }";
694   // Try to change the whole binary-operator expression AND one its operands:
695   StringRef E = "E";
696   Transformer T(makeRule(expr().bind(E),
697                          changeTo(node(std::string(E)), cat("DELETE_EXPR"))),
698                 consumer());
699   T.registerMatchers(&MatchFinder);
700   // The rewrite process fails because the changes conflict with each other...
701   EXPECT_FALSE(rewrite(Input));
702   // ... but two changes were produced.
703   EXPECT_EQ(Changes.size(), 2u);
704   EXPECT_EQ(ErrorCount, 0);
705 }
706 
TEST_F(TransformerTest,ErrorOccurredMatchSkipped)707 TEST_F(TransformerTest, ErrorOccurredMatchSkipped) {
708   // Syntax error in the function body:
709   std::string Input = "void errorOccurred() { 3 }";
710   Transformer T(makeRule(functionDecl(hasName("errorOccurred")),
711                          changeTo(cat("DELETED;"))),
712                 consumer());
713   T.registerMatchers(&MatchFinder);
714   // The rewrite process itself fails...
715   EXPECT_FALSE(rewrite(Input));
716   // ... and no changes or errors are produced in the process.
717   EXPECT_THAT(Changes, IsEmpty());
718   EXPECT_EQ(ErrorCount, 0);
719 }
720 
721 // Transformation of macro source text when the change encompasses the entirety
722 // of the expanded text.
TEST_F(TransformerTest,SimpleMacro)723 TEST_F(TransformerTest, SimpleMacro) {
724   std::string Input = R"cc(
725 #define ZERO 0
726     int f(string s) { return ZERO; }
727   )cc";
728   std::string Expected = R"cc(
729 #define ZERO 0
730     int f(string s) { return 999; }
731   )cc";
732 
733   StringRef zero = "zero";
734   RewriteRule R = makeRule(integerLiteral(equals(0)).bind(zero),
735                            changeTo(node(std::string(zero)), cat("999")));
736   testRule(R, Input, Expected);
737 }
738 
739 // Transformation of macro source text when the change encompasses the entirety
740 // of the expanded text, for the case of function-style macros.
TEST_F(TransformerTest,FunctionMacro)741 TEST_F(TransformerTest, FunctionMacro) {
742   std::string Input = R"cc(
743 #define MACRO(str) strlen((str).c_str())
744     int f(string s) { return MACRO(s); }
745   )cc";
746   std::string Expected = R"cc(
747 #define MACRO(str) strlen((str).c_str())
748     int f(string s) { return REPLACED; }
749   )cc";
750 
751   testRule(ruleStrlenSize(), Input, Expected);
752 }
753 
754 // Tests that expressions in macro arguments can be rewritten.
TEST_F(TransformerTest,MacroArg)755 TEST_F(TransformerTest, MacroArg) {
756   std::string Input = R"cc(
757 #define PLUS(e) e + 1
758     int f(string s) { return PLUS(strlen(s.c_str())); }
759   )cc";
760   std::string Expected = R"cc(
761 #define PLUS(e) e + 1
762     int f(string s) { return PLUS(REPLACED); }
763   )cc";
764 
765   testRule(ruleStrlenSize(), Input, Expected);
766 }
767 
768 // Tests that expressions in macro arguments can be rewritten, even when the
769 // macro call occurs inside another macro's definition.
TEST_F(TransformerTest,MacroArgInMacroDef)770 TEST_F(TransformerTest, MacroArgInMacroDef) {
771   std::string Input = R"cc(
772 #define NESTED(e) e
773 #define MACRO(str) NESTED(strlen((str).c_str()))
774     int f(string s) { return MACRO(s); }
775   )cc";
776   std::string Expected = R"cc(
777 #define NESTED(e) e
778 #define MACRO(str) NESTED(strlen((str).c_str()))
779     int f(string s) { return REPLACED; }
780   )cc";
781 
782   testRule(ruleStrlenSize(), Input, Expected);
783 }
784 
785 // Tests the corner case of the identity macro, specifically that it is
786 // discarded in the rewrite rather than preserved (like PLUS is preserved in the
787 // previous test).  This behavior is of dubious value (and marked with a FIXME
788 // in the code), but we test it to verify (and demonstrate) how this case is
789 // handled.
TEST_F(TransformerTest,IdentityMacro)790 TEST_F(TransformerTest, IdentityMacro) {
791   std::string Input = R"cc(
792 #define ID(e) e
793     int f(string s) { return ID(strlen(s.c_str())); }
794   )cc";
795   std::string Expected = R"cc(
796 #define ID(e) e
797     int f(string s) { return REPLACED; }
798   )cc";
799 
800   testRule(ruleStrlenSize(), Input, Expected);
801 }
802 
803 // Tests that two changes in a single macro expansion do not lead to conflicts
804 // in applying the changes.
TEST_F(TransformerTest,TwoChangesInOneMacroExpansion)805 TEST_F(TransformerTest, TwoChangesInOneMacroExpansion) {
806   std::string Input = R"cc(
807 #define PLUS(a,b) (a) + (b)
808     int f() { return PLUS(3, 4); }
809   )cc";
810   std::string Expected = R"cc(
811 #define PLUS(a,b) (a) + (b)
812     int f() { return PLUS(LIT, LIT); }
813   )cc";
814 
815   testRule(makeRule(integerLiteral(), changeTo(cat("LIT"))), Input, Expected);
816 }
817 
818 // Tests case where the rule's match spans both source from the macro and its
819 // arg, with the begin location (the "anchor") being the arg.
TEST_F(TransformerTest,MatchSpansMacroTextButChangeDoesNot)820 TEST_F(TransformerTest, MatchSpansMacroTextButChangeDoesNot) {
821   std::string Input = R"cc(
822 #define PLUS_ONE(a) a + 1
823     int f() { return PLUS_ONE(3); }
824   )cc";
825   std::string Expected = R"cc(
826 #define PLUS_ONE(a) a + 1
827     int f() { return PLUS_ONE(LIT); }
828   )cc";
829 
830   StringRef E = "expr";
831   testRule(makeRule(binaryOperator(hasLHS(expr().bind(E))),
832                     changeTo(node(std::string(E)), cat("LIT"))),
833            Input, Expected);
834 }
835 
836 // Tests case where the rule's match spans both source from the macro and its
837 // arg, with the begin location (the "anchor") being inside the macro.
TEST_F(TransformerTest,MatchSpansMacroTextButChangeDoesNotAnchoredInMacro)838 TEST_F(TransformerTest, MatchSpansMacroTextButChangeDoesNotAnchoredInMacro) {
839   std::string Input = R"cc(
840 #define PLUS_ONE(a) 1 + a
841     int f() { return PLUS_ONE(3); }
842   )cc";
843   std::string Expected = R"cc(
844 #define PLUS_ONE(a) 1 + a
845     int f() { return PLUS_ONE(LIT); }
846   )cc";
847 
848   StringRef E = "expr";
849   testRule(makeRule(binaryOperator(hasRHS(expr().bind(E))),
850                     changeTo(node(std::string(E)), cat("LIT"))),
851            Input, Expected);
852 }
853 
854 // No rewrite is applied when the changed text does not encompass the entirety
855 // of the expanded text. That is, the edit would have to be applied to the
856 // macro's definition to succeed and editing the expansion point would not
857 // suffice.
TEST_F(TransformerTest,NoPartialRewriteOMacroExpansion)858 TEST_F(TransformerTest, NoPartialRewriteOMacroExpansion) {
859   std::string Input = R"cc(
860 #define ZERO_PLUS 0 + 3
861     int f(string s) { return ZERO_PLUS; })cc";
862 
863   StringRef zero = "zero";
864   RewriteRule R = makeRule(integerLiteral(equals(0)).bind(zero),
865                            changeTo(node(std::string(zero)), cat("0")));
866   testRule(R, Input, Input);
867 }
868 
869 // This test handles the corner case where a macro expands within another macro
870 // to matching code, but that code is an argument to the nested macro call.  A
871 // simple check of isMacroArgExpansion() vs. isMacroBodyExpansion() will get
872 // this wrong, and transform the code.
TEST_F(TransformerTest,NoPartialRewriteOfMacroExpansionForMacroArgs)873 TEST_F(TransformerTest, NoPartialRewriteOfMacroExpansionForMacroArgs) {
874   std::string Input = R"cc(
875 #define NESTED(e) e
876 #define MACRO(str) 1 + NESTED(strlen((str).c_str()))
877     int f(string s) { return MACRO(s); }
878   )cc";
879 
880   testRule(ruleStrlenSize(), Input, Input);
881 }
882 
883 #if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST
884 // Verifies that `Type` and `QualType` are not allowed as top-level matchers in
885 // rules.
TEST(TransformerDeathTest,OrderedRuleTypes)886 TEST(TransformerDeathTest, OrderedRuleTypes) {
887   RewriteRule QualTypeRule = makeRule(qualType(), changeTo(cat("Q")));
888   EXPECT_DEATH(transformer::detail::buildMatchers(QualTypeRule),
889                "Matcher must be.*node matcher");
890 
891   RewriteRule TypeRule = makeRule(arrayType(), changeTo(cat("T")));
892   EXPECT_DEATH(transformer::detail::buildMatchers(TypeRule),
893                "Matcher must be.*node matcher");
894 }
895 #endif
896 
897 // Edits are able to span multiple files; in this case, a header and an
898 // implementation file.
TEST_F(TransformerTest,MultipleFiles)899 TEST_F(TransformerTest, MultipleFiles) {
900   std::string Header = R"cc(void RemoveThisFunction();)cc";
901   std::string Source = R"cc(#include "input.h"
902                             void RemoveThisFunction();)cc";
903   Transformer T(
904       makeRule(functionDecl(hasName("RemoveThisFunction")), changeTo(cat(""))),
905       consumer());
906   T.registerMatchers(&MatchFinder);
907   auto Factory = newFrontendActionFactory(&MatchFinder);
908   EXPECT_TRUE(runToolOnCodeWithArgs(
909       Factory->create(), Source, std::vector<std::string>(), "input.cc",
910       "clang-tool", std::make_shared<PCHContainerOperations>(),
911       {{"input.h", Header}}));
912 
913   std::sort(Changes.begin(), Changes.end(),
914             [](const AtomicChange &L, const AtomicChange &R) {
915               return L.getFilePath() < R.getFilePath();
916             });
917 
918   ASSERT_EQ(Changes[0].getFilePath(), "./input.h");
919   EXPECT_THAT(Changes[0].getInsertedHeaders(), IsEmpty());
920   EXPECT_THAT(Changes[0].getRemovedHeaders(), IsEmpty());
921   llvm::Expected<std::string> UpdatedCode =
922       clang::tooling::applyAllReplacements(Header,
923                                            Changes[0].getReplacements());
924   ASSERT_TRUE(static_cast<bool>(UpdatedCode))
925       << "Could not update code: " << llvm::toString(UpdatedCode.takeError());
926   EXPECT_EQ(format(*UpdatedCode), format(R"cc(;)cc"));
927 
928   ASSERT_EQ(Changes[1].getFilePath(), "input.cc");
929   EXPECT_THAT(Changes[1].getInsertedHeaders(), IsEmpty());
930   EXPECT_THAT(Changes[1].getRemovedHeaders(), IsEmpty());
931   UpdatedCode = clang::tooling::applyAllReplacements(
932       Source, Changes[1].getReplacements());
933   ASSERT_TRUE(static_cast<bool>(UpdatedCode))
934       << "Could not update code: " << llvm::toString(UpdatedCode.takeError());
935   EXPECT_EQ(format(*UpdatedCode), format(R"cc(#include "input.h"
936                         ;)cc"));
937 }
938 } // namespace
939