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