[libc++][Android] BuildKite CI: update Clang and sysroot versions (#116151)
[llvm-project.git] / clang / unittests / Tooling / TransformerTest.cpp
blobcbd84ab794a49af230df84316a2f8be63d08fbeb
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"
20 #include <optional>
22 using namespace clang;
23 using namespace tooling;
24 using namespace ast_matchers;
25 namespace {
26 using ::clang::transformer::addInclude;
27 using ::clang::transformer::applyFirst;
28 using ::clang::transformer::before;
29 using ::clang::transformer::cat;
30 using ::clang::transformer::changeTo;
31 using ::clang::transformer::editList;
32 using ::clang::transformer::makeRule;
33 using ::clang::transformer::member;
34 using ::clang::transformer::name;
35 using ::clang::transformer::node;
36 using ::clang::transformer::noEdits;
37 using ::clang::transformer::remove;
38 using ::clang::transformer::rewriteDescendants;
39 using ::clang::transformer::RewriteRule;
40 using ::clang::transformer::RewriteRuleWith;
41 using ::clang::transformer::statement;
42 using ::testing::ElementsAre;
43 using ::testing::IsEmpty;
44 using ::testing::ResultOf;
45 using ::testing::UnorderedElementsAre;
47 constexpr char KHeaderContents[] = R"cc(
48 struct string {
49 string(const char*);
50 char* c_str();
51 int size();
53 int strlen(const char*);
55 namespace proto {
56 struct PCFProto {
57 int foo();
59 struct ProtoCommandLineFlag : PCFProto {
60 PCFProto& GetProto();
62 } // namespace proto
63 class Logger {};
64 void operator<<(Logger& l, string msg);
65 Logger& log(int level);
66 )cc";
68 static ast_matchers::internal::Matcher<clang::QualType>
69 isOrPointsTo(const clang::ast_matchers::DeclarationMatcher &TypeMatcher) {
70 return anyOf(hasDeclaration(TypeMatcher), pointsTo(TypeMatcher));
73 static std::string format(StringRef Code) {
74 const std::vector<Range> Ranges(1, Range(0, Code.size()));
75 auto Style = format::getLLVMStyle();
76 const auto Replacements = format::reformat(Style, Code, Ranges);
77 auto Formatted = applyAllReplacements(Code, Replacements);
78 if (!Formatted) {
79 ADD_FAILURE() << "Could not format code: "
80 << llvm::toString(Formatted.takeError());
81 return std::string();
83 return *Formatted;
86 static void compareSnippets(StringRef Expected,
87 const std::optional<std::string> &MaybeActual) {
88 ASSERT_TRUE(MaybeActual) << "Rewrite failed. Expecting: " << Expected;
89 auto Actual = *MaybeActual;
90 std::string HL = "#include \"header.h\"\n";
91 auto I = Actual.find(HL);
92 if (I != std::string::npos)
93 Actual.erase(I, HL.size());
94 EXPECT_EQ(format(Expected), format(Actual));
97 // FIXME: consider separating this class into its own file(s).
98 class ClangRefactoringTestBase : public testing::Test {
99 protected:
100 void appendToHeader(StringRef S) { FileContents[0].second += S; }
102 void addFile(StringRef Filename, StringRef Content) {
103 FileContents.emplace_back(std::string(Filename), std::string(Content));
106 std::optional<std::string> rewrite(StringRef Input) {
107 std::string Code = ("#include \"header.h\"\n" + Input).str();
108 auto Factory = newFrontendActionFactory(&MatchFinder);
109 if (!runToolOnCodeWithArgs(
110 Factory->create(), Code, std::vector<std::string>(), "input.cc",
111 "clang-tool", std::make_shared<PCHContainerOperations>(),
112 FileContents)) {
113 llvm::errs() << "Running tool failed.\n";
114 return std::nullopt;
116 if (ErrorCount != 0) {
117 llvm::errs() << "Generating changes failed.\n";
118 return std::nullopt;
120 auto ChangedCode =
121 applyAtomicChanges("input.cc", Code, Changes, ApplyChangesSpec());
122 if (!ChangedCode) {
123 llvm::errs() << "Applying changes failed: "
124 << llvm::toString(ChangedCode.takeError()) << "\n";
125 return std::nullopt;
127 return *ChangedCode;
130 Transformer::ChangeSetConsumer consumer() {
131 return [this](Expected<MutableArrayRef<AtomicChange>> C) {
132 if (C) {
133 Changes.insert(Changes.end(), std::make_move_iterator(C->begin()),
134 std::make_move_iterator(C->end()));
135 } else {
136 // FIXME: stash this error rather than printing.
137 llvm::errs() << "Error generating changes: "
138 << llvm::toString(C.takeError()) << "\n";
139 ++ErrorCount;
144 auto consumerWithStringMetadata() {
145 return [this](Expected<TransformerResult<std::string>> C) {
146 if (C) {
147 Changes.insert(Changes.end(),
148 std::make_move_iterator(C->Changes.begin()),
149 std::make_move_iterator(C->Changes.end()));
150 StringMetadata.push_back(std::move(C->Metadata));
151 } else {
152 // FIXME: stash this error rather than printing.
153 llvm::errs() << "Error generating changes: "
154 << llvm::toString(C.takeError()) << "\n";
155 ++ErrorCount;
160 void testRule(RewriteRule Rule, StringRef Input, StringRef Expected) {
161 Transformers.push_back(
162 std::make_unique<Transformer>(std::move(Rule), consumer()));
163 Transformers.back()->registerMatchers(&MatchFinder);
164 compareSnippets(Expected, rewrite(Input));
167 void testRule(RewriteRuleWith<std::string> Rule, StringRef Input,
168 StringRef Expected) {
169 Transformers.push_back(std::make_unique<Transformer>(
170 std::move(Rule), consumerWithStringMetadata()));
171 Transformers.back()->registerMatchers(&MatchFinder);
172 compareSnippets(Expected, rewrite(Input));
175 void testRuleFailure(RewriteRule Rule, StringRef Input) {
176 Transformers.push_back(
177 std::make_unique<Transformer>(std::move(Rule), consumer()));
178 Transformers.back()->registerMatchers(&MatchFinder);
179 ASSERT_FALSE(rewrite(Input)) << "Expected failure to rewrite code";
182 void testRuleFailure(RewriteRuleWith<std::string> Rule, StringRef Input) {
183 Transformers.push_back(std::make_unique<Transformer>(
184 std::move(Rule), consumerWithStringMetadata()));
185 Transformers.back()->registerMatchers(&MatchFinder);
186 ASSERT_FALSE(rewrite(Input)) << "Expected failure to rewrite code";
189 // Transformers are referenced by MatchFinder.
190 std::vector<std::unique_ptr<Transformer>> Transformers;
191 clang::ast_matchers::MatchFinder MatchFinder;
192 // Records whether any errors occurred in individual changes.
193 int ErrorCount = 0;
194 AtomicChanges Changes;
195 std::vector<std::string> StringMetadata;
197 private:
198 FileContentMappings FileContents = {{"header.h", ""}};
201 class TransformerTest : public ClangRefactoringTestBase {
202 protected:
203 TransformerTest() { appendToHeader(KHeaderContents); }
206 // Given string s, change strlen($s.c_str()) to REPLACED.
207 static RewriteRuleWith<std::string> ruleStrlenSize() {
208 StringRef StringExpr = "strexpr";
209 auto StringType = namedDecl(hasAnyName("::basic_string", "::string"));
210 auto R = makeRule(
211 callExpr(callee(functionDecl(hasName("strlen"))),
212 hasArgument(0, cxxMemberCallExpr(
213 on(expr(hasType(isOrPointsTo(StringType)))
214 .bind(StringExpr)),
215 callee(cxxMethodDecl(hasName("c_str")))))),
216 changeTo(cat("REPLACED")), cat("Use size() method directly on string."));
217 return R;
220 TEST_F(TransformerTest, StrlenSize) {
221 std::string Input = "int f(string s) { return strlen(s.c_str()); }";
222 std::string Expected = "int f(string s) { return REPLACED; }";
223 testRule(ruleStrlenSize(), Input, Expected);
226 // Tests that no change is applied when a match is not expected.
227 TEST_F(TransformerTest, NoMatch) {
228 std::string Input = "int f(string s) { return s.size(); }";
229 testRule(ruleStrlenSize(), Input, Input);
232 // Tests replacing an expression.
233 TEST_F(TransformerTest, Flag) {
234 StringRef Flag = "flag";
235 RewriteRule Rule = makeRule(
236 cxxMemberCallExpr(on(expr(hasType(cxxRecordDecl(
237 hasName("proto::ProtoCommandLineFlag"))))
238 .bind(Flag)),
239 unless(callee(cxxMethodDecl(hasName("GetProto"))))),
240 changeTo(node(std::string(Flag)), cat("EXPR")));
242 std::string Input = R"cc(
243 proto::ProtoCommandLineFlag flag;
244 int x = flag.foo();
245 int y = flag.GetProto().foo();
246 )cc";
247 std::string Expected = R"cc(
248 proto::ProtoCommandLineFlag flag;
249 int x = EXPR.foo();
250 int y = flag.GetProto().foo();
251 )cc";
253 testRule(std::move(Rule), Input, Expected);
256 TEST_F(TransformerTest, AddIncludeQuoted) {
257 RewriteRule Rule =
258 makeRule(callExpr(callee(functionDecl(hasName("f")))),
259 {addInclude("clang/OtherLib.h"), changeTo(cat("other()"))});
261 std::string Input = R"cc(
262 int f(int x);
263 int h(int x) { return f(x); }
264 )cc";
265 std::string Expected = R"cc(#include "clang/OtherLib.h"
267 int f(int x);
268 int h(int x) { return other(); }
269 )cc";
271 testRule(Rule, Input, Expected);
274 TEST_F(TransformerTest, AddIncludeAngled) {
275 RewriteRule Rule = makeRule(
276 callExpr(callee(functionDecl(hasName("f")))),
277 {addInclude("clang/OtherLib.h", transformer::IncludeFormat::Angled),
278 changeTo(cat("other()"))});
280 std::string Input = R"cc(
281 int f(int x);
282 int h(int x) { return f(x); }
283 )cc";
284 std::string Expected = R"cc(#include <clang/OtherLib.h>
286 int f(int x);
287 int h(int x) { return other(); }
288 )cc";
290 testRule(Rule, Input, Expected);
293 TEST_F(TransformerTest, AddIncludeQuotedForRule) {
294 RewriteRule Rule = makeRule(callExpr(callee(functionDecl(hasName("f")))),
295 changeTo(cat("other()")));
296 addInclude(Rule, "clang/OtherLib.h");
298 std::string Input = R"cc(
299 int f(int x);
300 int h(int x) { return f(x); }
301 )cc";
302 std::string Expected = R"cc(#include "clang/OtherLib.h"
304 int f(int x);
305 int h(int x) { return other(); }
306 )cc";
308 testRule(Rule, Input, Expected);
311 TEST_F(TransformerTest, AddIncludeAngledForRule) {
312 RewriteRule Rule = makeRule(callExpr(callee(functionDecl(hasName("f")))),
313 changeTo(cat("other()")));
314 addInclude(Rule, "clang/OtherLib.h", transformer::IncludeFormat::Angled);
316 std::string Input = R"cc(
317 int f(int x);
318 int h(int x) { return f(x); }
319 )cc";
320 std::string Expected = R"cc(#include <clang/OtherLib.h>
322 int f(int x);
323 int h(int x) { return other(); }
324 )cc";
326 testRule(Rule, Input, Expected);
329 TEST_F(TransformerTest, NodePartNameNamedDecl) {
330 StringRef Fun = "fun";
331 RewriteRule Rule = makeRule(functionDecl(hasName("bad")).bind(Fun),
332 changeTo(name(std::string(Fun)), cat("good")));
334 std::string Input = R"cc(
335 int bad(int x);
336 int bad(int x) { return x * x; }
337 )cc";
338 std::string Expected = R"cc(
339 int good(int x);
340 int good(int x) { return x * x; }
341 )cc";
343 testRule(Rule, Input, Expected);
346 TEST_F(TransformerTest, NodePartNameDeclRef) {
347 std::string Input = R"cc(
348 template <typename T>
349 T bad(T x) {
350 return x;
352 int neutral(int x) { return bad<int>(x) * x; }
353 )cc";
354 std::string Expected = R"cc(
355 template <typename T>
356 T bad(T x) {
357 return x;
359 int neutral(int x) { return good<int>(x) * x; }
360 )cc";
362 StringRef Ref = "ref";
363 testRule(makeRule(declRefExpr(to(functionDecl(hasName("bad")))).bind(Ref),
364 changeTo(name(std::string(Ref)), cat("good"))),
365 Input, Expected);
368 TEST_F(TransformerTest, NodePartNameDeclRefFailure) {
369 std::string Input = R"cc(
370 struct Y {
371 int operator*();
373 int neutral(int x) {
374 Y y;
375 int (Y::*ptr)() = &Y::operator*;
376 return *y + x;
378 )cc";
380 StringRef Ref = "ref";
381 Transformer T(makeRule(declRefExpr(to(functionDecl())).bind(Ref),
382 changeTo(name(std::string(Ref)), cat("good"))),
383 consumer());
384 T.registerMatchers(&MatchFinder);
385 EXPECT_FALSE(rewrite(Input));
388 TEST_F(TransformerTest, NodePartMember) {
389 StringRef E = "expr";
390 RewriteRule Rule =
391 makeRule(memberExpr(clang::ast_matchers::member(hasName("bad"))).bind(E),
392 changeTo(member(std::string(E)), cat("good")));
394 std::string Input = R"cc(
395 struct S {
396 int bad;
398 int g() {
399 S s;
400 return s.bad;
402 )cc";
403 std::string Expected = R"cc(
404 struct S {
405 int bad;
407 int g() {
408 S s;
409 return s.good;
411 )cc";
413 testRule(Rule, Input, Expected);
416 TEST_F(TransformerTest, NodePartMemberQualified) {
417 std::string Input = R"cc(
418 struct S {
419 int bad;
420 int good;
422 struct T : public S {
423 int bad;
425 int g() {
426 T t;
427 return t.S::bad;
429 )cc";
430 std::string Expected = R"cc(
431 struct S {
432 int bad;
433 int good;
435 struct T : public S {
436 int bad;
438 int g() {
439 T t;
440 return t.S::good;
442 )cc";
444 StringRef E = "expr";
445 testRule(makeRule(memberExpr().bind(E),
446 changeTo(member(std::string(E)), cat("good"))),
447 Input, Expected);
450 TEST_F(TransformerTest, NodePartMemberMultiToken) {
451 std::string Input = R"cc(
452 struct Y {
453 int operator*();
454 int good();
455 template <typename T> void foo(T t);
457 int neutral(int x) {
458 Y y;
459 y.template foo<int>(3);
460 return y.operator *();
462 )cc";
463 std::string Expected = R"cc(
464 struct Y {
465 int operator*();
466 int good();
467 template <typename T> void foo(T t);
469 int neutral(int x) {
470 Y y;
471 y.template good<int>(3);
472 return y.good();
474 )cc";
476 StringRef MemExpr = "member";
477 testRule(makeRule(memberExpr().bind(MemExpr),
478 changeTo(member(std::string(MemExpr)), cat("good"))),
479 Input, Expected);
482 TEST_F(TransformerTest, NoEdits) {
483 using transformer::noEdits;
484 std::string Input = "int f(int x) { return x; }";
485 testRule(makeRule(returnStmt().bind("return"), noEdits()), Input, Input);
488 TEST_F(TransformerTest, NoopEdit) {
489 using transformer::node;
490 using transformer::noopEdit;
491 std::string Input = "int f(int x) { return x; }";
492 testRule(makeRule(returnStmt().bind("return"), noopEdit(node("return"))),
493 Input, Input);
496 TEST_F(TransformerTest, IfBound2Args) {
497 using transformer::ifBound;
498 std::string Input = "int f(int x) { return x; }";
499 std::string Expected = "int f(int x) { CHANGE; }";
500 testRule(makeRule(returnStmt().bind("return"),
501 ifBound("return", changeTo(cat("CHANGE;")))),
502 Input, Expected);
505 TEST_F(TransformerTest, IfBound3Args) {
506 using transformer::ifBound;
507 std::string Input = "int f(int x) { return x; }";
508 std::string Expected = "int f(int x) { CHANGE; }";
509 testRule(makeRule(returnStmt().bind("return"),
510 ifBound("nothing", changeTo(cat("ERROR")),
511 changeTo(cat("CHANGE;")))),
512 Input, Expected);
515 TEST_F(TransformerTest, ShrinkTo) {
516 using transformer::shrinkTo;
517 std::string Input = "int f(int x) { return x; }";
518 std::string Expected = "return x;";
519 testRule(makeRule(functionDecl(hasDescendant(returnStmt().bind("return")))
520 .bind("function"),
521 shrinkTo(node("function"), node("return"))),
522 Input, Expected);
525 // Rewrite various Stmts inside a Decl.
526 TEST_F(TransformerTest, RewriteDescendantsDeclChangeStmt) {
527 std::string Input =
528 "int f(int x) { int y = x; { int z = x * x; } return x; }";
529 std::string Expected =
530 "int f(int x) { int y = 3; { int z = 3 * 3; } return 3; }";
531 auto InlineX =
532 makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
533 testRule(makeRule(functionDecl(hasName("f")).bind("fun"),
534 rewriteDescendants("fun", InlineX)),
535 Input, Expected);
538 // Rewrite various TypeLocs inside a Decl.
539 TEST_F(TransformerTest, RewriteDescendantsDeclChangeTypeLoc) {
540 std::string Input = "int f(int *x) { return *x; }";
541 std::string Expected = "char f(char *x) { return *x; }";
542 auto IntToChar = makeRule(typeLoc(loc(qualType(isInteger(), builtinType()))),
543 changeTo(cat("char")));
544 testRule(makeRule(functionDecl(hasName("f")).bind("fun"),
545 rewriteDescendants("fun", IntToChar)),
546 Input, Expected);
549 TEST_F(TransformerTest, RewriteDescendantsStmt) {
550 // Add an unrelated definition to the header that also has a variable named
551 // "x", to test that the rewrite is limited to the scope we intend.
552 appendToHeader(R"cc(int g(int x) { return x; })cc");
553 std::string Input =
554 "int f(int x) { int y = x; { int z = x * x; } return x; }";
555 std::string Expected =
556 "int f(int x) { int y = 3; { int z = 3 * 3; } return 3; }";
557 auto InlineX =
558 makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
559 testRule(makeRule(functionDecl(hasName("f"), hasBody(stmt().bind("body"))),
560 rewriteDescendants("body", InlineX)),
561 Input, Expected);
564 TEST_F(TransformerTest, RewriteDescendantsStmtWithAdditionalChange) {
565 std::string Input =
566 "int f(int x) { int y = x; { int z = x * x; } return x; }";
567 std::string Expected =
568 "int newName(int x) { int y = 3; { int z = 3 * 3; } return 3; }";
569 auto InlineX =
570 makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
571 testRule(
572 makeRule(
573 functionDecl(hasName("f"), hasBody(stmt().bind("body"))).bind("f"),
574 flatten(changeTo(name("f"), cat("newName")),
575 rewriteDescendants("body", InlineX))),
576 Input, Expected);
579 TEST_F(TransformerTest, RewriteDescendantsTypeLoc) {
580 std::string Input = "int f(int *x) { return *x; }";
581 std::string Expected = "int f(char *x) { return *x; }";
582 auto IntToChar =
583 makeRule(typeLoc(loc(qualType(isInteger(), builtinType()))).bind("loc"),
584 changeTo(cat("char")));
585 testRule(
586 makeRule(functionDecl(hasName("f"),
587 hasParameter(0, varDecl(hasTypeLoc(
588 typeLoc().bind("parmType"))))),
589 rewriteDescendants("parmType", IntToChar)),
590 Input, Expected);
593 TEST_F(TransformerTest, RewriteDescendantsReferToParentBinding) {
594 std::string Input =
595 "int f(int p) { int y = p; { int z = p * p; } return p; }";
596 std::string Expected =
597 "int f(int p) { int y = 3; { int z = 3 * 3; } return 3; }";
598 std::string VarId = "var";
599 auto InlineVar = makeRule(declRefExpr(to(varDecl(equalsBoundNode(VarId)))),
600 changeTo(cat("3")));
601 testRule(makeRule(functionDecl(hasName("f"),
602 hasParameter(0, varDecl().bind(VarId)))
603 .bind("fun"),
604 rewriteDescendants("fun", InlineVar)),
605 Input, Expected);
608 TEST_F(TransformerTest, RewriteDescendantsUnboundNode) {
609 std::string Input =
610 "int f(int x) { int y = x; { int z = x * x; } return x; }";
611 auto InlineX =
612 makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
613 Transformer T(makeRule(functionDecl(hasName("f")),
614 rewriteDescendants("UNBOUND", InlineX)),
615 consumer());
616 T.registerMatchers(&MatchFinder);
617 EXPECT_FALSE(rewrite(Input));
618 EXPECT_THAT(Changes, IsEmpty());
619 EXPECT_EQ(ErrorCount, 1);
622 TEST_F(TransformerTest, RewriteDescendantsInvalidNodeType) {
623 std::string Input =
624 "int f(int x) { int y = x; { int z = x * x; } return x; }";
625 auto IntToChar =
626 makeRule(qualType(isInteger(), builtinType()), changeTo(cat("char")));
627 Transformer T(
628 makeRule(functionDecl(
629 hasName("f"),
630 hasParameter(0, varDecl(hasType(qualType().bind("type"))))),
631 rewriteDescendants("type", IntToChar)),
632 consumer());
633 T.registerMatchers(&MatchFinder);
634 EXPECT_FALSE(rewrite(Input));
635 EXPECT_THAT(Changes, IsEmpty());
636 EXPECT_EQ(ErrorCount, 1);
640 // We include one test per typed overload. We don't test extensively since that
641 // is already covered by the tests above.
644 TEST_F(TransformerTest, RewriteDescendantsTypedStmt) {
645 // Add an unrelated definition to the header that also has a variable named
646 // "x", to test that the rewrite is limited to the scope we intend.
647 appendToHeader(R"cc(int g(int x) { return x; })cc");
648 std::string Input =
649 "int f(int x) { int y = x; { int z = x * x; } return x; }";
650 std::string Expected =
651 "int f(int x) { int y = 3; { int z = 3 * 3; } return 3; }";
652 auto InlineX =
653 makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
654 testRule(makeRule(functionDecl(hasName("f"), hasBody(stmt().bind("body"))),
655 [&InlineX](const MatchFinder::MatchResult &R) {
656 const auto *Node = R.Nodes.getNodeAs<Stmt>("body");
657 assert(Node != nullptr && "body must be bound");
658 return transformer::detail::rewriteDescendants(
659 *Node, InlineX, R);
661 Input, Expected);
664 TEST_F(TransformerTest, RewriteDescendantsTypedDecl) {
665 std::string Input =
666 "int f(int x) { int y = x; { int z = x * x; } return x; }";
667 std::string Expected =
668 "int f(int x) { int y = 3; { int z = 3 * 3; } return 3; }";
669 auto InlineX =
670 makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
671 testRule(makeRule(functionDecl(hasName("f")).bind("fun"),
672 [&InlineX](const MatchFinder::MatchResult &R) {
673 const auto *Node = R.Nodes.getNodeAs<Decl>("fun");
674 assert(Node != nullptr && "fun must be bound");
675 return transformer::detail::rewriteDescendants(
676 *Node, InlineX, R);
678 Input, Expected);
681 TEST_F(TransformerTest, RewriteDescendantsTypedTypeLoc) {
682 std::string Input = "int f(int *x) { return *x; }";
683 std::string Expected = "int f(char *x) { return *x; }";
684 auto IntToChar =
685 makeRule(typeLoc(loc(qualType(isInteger(), builtinType()))).bind("loc"),
686 changeTo(cat("char")));
687 testRule(
688 makeRule(
689 functionDecl(
690 hasName("f"),
691 hasParameter(0, varDecl(hasTypeLoc(typeLoc().bind("parmType"))))),
692 [&IntToChar](const MatchFinder::MatchResult &R) {
693 const auto *Node = R.Nodes.getNodeAs<TypeLoc>("parmType");
694 assert(Node != nullptr && "parmType must be bound");
695 return transformer::detail::rewriteDescendants(*Node, IntToChar, R);
697 Input, Expected);
700 TEST_F(TransformerTest, RewriteDescendantsTypedDynTyped) {
701 // Add an unrelated definition to the header that also has a variable named
702 // "x", to test that the rewrite is limited to the scope we intend.
703 appendToHeader(R"cc(int g(int x) { return x; })cc");
704 std::string Input =
705 "int f(int x) { int y = x; { int z = x * x; } return x; }";
706 std::string Expected =
707 "int f(int x) { int y = 3; { int z = 3 * 3; } return 3; }";
708 auto InlineX =
709 makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
710 testRule(
711 makeRule(functionDecl(hasName("f"), hasBody(stmt().bind("body"))),
712 [&InlineX](const MatchFinder::MatchResult &R) {
713 auto It = R.Nodes.getMap().find("body");
714 assert(It != R.Nodes.getMap().end() && "body must be bound");
715 return transformer::detail::rewriteDescendants(It->second,
716 InlineX, R);
718 Input, Expected);
721 TEST_F(TransformerTest, InsertBeforeEdit) {
722 std::string Input = R"cc(
723 int f() {
724 return 7;
726 )cc";
727 std::string Expected = R"cc(
728 int f() {
729 int y = 3;
730 return 7;
732 )cc";
734 StringRef Ret = "return";
735 testRule(
736 makeRule(returnStmt().bind(Ret),
737 insertBefore(statement(std::string(Ret)), cat("int y = 3;"))),
738 Input, Expected);
741 TEST_F(TransformerTest, InsertAfterEdit) {
742 std::string Input = R"cc(
743 int f() {
744 int x = 5;
745 return 7;
747 )cc";
748 std::string Expected = R"cc(
749 int f() {
750 int x = 5;
751 int y = 3;
752 return 7;
754 )cc";
756 StringRef Decl = "decl";
757 testRule(
758 makeRule(declStmt().bind(Decl),
759 insertAfter(statement(std::string(Decl)), cat("int y = 3;"))),
760 Input, Expected);
763 TEST_F(TransformerTest, RemoveEdit) {
764 std::string Input = R"cc(
765 int f() {
766 int x = 5;
767 return 7;
769 )cc";
770 std::string Expected = R"cc(
771 int f() {
772 return 7;
774 )cc";
776 StringRef Decl = "decl";
777 testRule(
778 makeRule(declStmt().bind(Decl), remove(statement(std::string(Decl)))),
779 Input, Expected);
782 TEST_F(TransformerTest, WithMetadata) {
783 auto makeMetadata = [](const MatchFinder::MatchResult &R) -> llvm::Any {
784 int N =
785 R.Nodes.getNodeAs<IntegerLiteral>("int")->getValue().getLimitedValue();
786 return N;
789 std::string Input = R"cc(
790 int f() {
791 int x = 5;
792 return 7;
794 )cc";
796 Transformer T(
797 makeRule(
798 declStmt(containsDeclaration(0, varDecl(hasInitializer(
799 integerLiteral().bind("int")))))
800 .bind("decl"),
801 withMetadata(remove(statement(std::string("decl"))), makeMetadata)),
802 consumer());
803 T.registerMatchers(&MatchFinder);
804 auto Factory = newFrontendActionFactory(&MatchFinder);
805 EXPECT_TRUE(runToolOnCodeWithArgs(
806 Factory->create(), Input, std::vector<std::string>(), "input.cc",
807 "clang-tool", std::make_shared<PCHContainerOperations>(), {}));
808 ASSERT_EQ(Changes.size(), 1u);
809 const llvm::Any &Metadata = Changes[0].getMetadata();
810 ASSERT_TRUE(llvm::any_cast<int>(&Metadata));
811 EXPECT_THAT(llvm::any_cast<int>(Metadata), 5);
814 TEST_F(TransformerTest, MultiChange) {
815 std::string Input = R"cc(
816 void foo() {
817 if (10 > 1.0)
818 log(1) << "oh no!";
819 else
820 log(0) << "ok";
822 )cc";
823 std::string Expected = R"(
824 void foo() {
825 if (true) { /* then */ }
826 else { /* else */ }
830 StringRef C = "C", T = "T", E = "E";
831 testRule(
832 makeRule(ifStmt(hasCondition(expr().bind(C)), hasThen(stmt().bind(T)),
833 hasElse(stmt().bind(E))),
834 {changeTo(node(std::string(C)), cat("true")),
835 changeTo(statement(std::string(T)), cat("{ /* then */ }")),
836 changeTo(statement(std::string(E)), cat("{ /* else */ }"))}),
837 Input, Expected);
840 TEST_F(TransformerTest, EditList) {
841 std::string Input = R"cc(
842 void foo() {
843 if (10 > 1.0)
844 log(1) << "oh no!";
845 else
846 log(0) << "ok";
848 )cc";
849 std::string Expected = R"(
850 void foo() {
851 if (true) { /* then */ }
852 else { /* else */ }
856 StringRef C = "C", T = "T", E = "E";
857 testRule(makeRule(ifStmt(hasCondition(expr().bind(C)),
858 hasThen(stmt().bind(T)), hasElse(stmt().bind(E))),
859 editList({changeTo(node(std::string(C)), cat("true")),
860 changeTo(statement(std::string(T)),
861 cat("{ /* then */ }")),
862 changeTo(statement(std::string(E)),
863 cat("{ /* else */ }"))})),
864 Input, Expected);
867 TEST_F(TransformerTest, Flatten) {
868 std::string Input = R"cc(
869 void foo() {
870 if (10 > 1.0)
871 log(1) << "oh no!";
872 else
873 log(0) << "ok";
875 )cc";
876 std::string Expected = R"(
877 void foo() {
878 if (true) { /* then */ }
879 else { /* else */ }
883 StringRef C = "C", T = "T", E = "E";
884 testRule(
885 makeRule(
886 ifStmt(hasCondition(expr().bind(C)), hasThen(stmt().bind(T)),
887 hasElse(stmt().bind(E))),
888 flatten(changeTo(node(std::string(C)), cat("true")),
889 changeTo(statement(std::string(T)), cat("{ /* then */ }")),
890 changeTo(statement(std::string(E)), cat("{ /* else */ }")))),
891 Input, Expected);
894 TEST_F(TransformerTest, FlattenWithMixedArgs) {
895 using clang::transformer::editList;
896 std::string Input = R"cc(
897 void foo() {
898 if (10 > 1.0)
899 log(1) << "oh no!";
900 else
901 log(0) << "ok";
903 )cc";
904 std::string Expected = R"(
905 void foo() {
906 if (true) { /* then */ }
907 else { /* else */ }
911 StringRef C = "C", T = "T", E = "E";
912 testRule(makeRule(ifStmt(hasCondition(expr().bind(C)),
913 hasThen(stmt().bind(T)), hasElse(stmt().bind(E))),
914 flatten(changeTo(node(std::string(C)), cat("true")),
915 edit(changeTo(statement(std::string(T)),
916 cat("{ /* then */ }"))),
917 editList({changeTo(statement(std::string(E)),
918 cat("{ /* else */ }"))}))),
919 Input, Expected);
922 TEST_F(TransformerTest, OrderedRuleUnrelated) {
923 StringRef Flag = "flag";
924 RewriteRuleWith<std::string> FlagRule = makeRule(
925 cxxMemberCallExpr(on(expr(hasType(cxxRecordDecl(
926 hasName("proto::ProtoCommandLineFlag"))))
927 .bind(Flag)),
928 unless(callee(cxxMethodDecl(hasName("GetProto"))))),
929 changeTo(node(std::string(Flag)), cat("PROTO")), cat(""));
931 std::string Input = R"cc(
932 proto::ProtoCommandLineFlag flag;
933 int x = flag.foo();
934 int y = flag.GetProto().foo();
935 int f(string s) { return strlen(s.c_str()); }
936 )cc";
937 std::string Expected = R"cc(
938 proto::ProtoCommandLineFlag flag;
939 int x = PROTO.foo();
940 int y = flag.GetProto().foo();
941 int f(string s) { return REPLACED; }
942 )cc";
944 testRule(applyFirst({ruleStrlenSize(), FlagRule}), Input, Expected);
947 TEST_F(TransformerTest, OrderedRuleRelated) {
948 std::string Input = R"cc(
949 void f1();
950 void f2();
951 void call_f1() { f1(); }
952 void call_f2() { f2(); }
953 )cc";
954 std::string Expected = R"cc(
955 void f1();
956 void f2();
957 void call_f1() { REPLACE_F1; }
958 void call_f2() { REPLACE_F1_OR_F2; }
959 )cc";
961 RewriteRule ReplaceF1 =
962 makeRule(callExpr(callee(functionDecl(hasName("f1")))),
963 changeTo(cat("REPLACE_F1")));
964 RewriteRule ReplaceF1OrF2 =
965 makeRule(callExpr(callee(functionDecl(hasAnyName("f1", "f2")))),
966 changeTo(cat("REPLACE_F1_OR_F2")));
967 testRule(applyFirst({ReplaceF1, ReplaceF1OrF2}), Input, Expected);
970 // Change the order of the rules to get a different result. When `ReplaceF1OrF2`
971 // comes first, it applies for both uses, so `ReplaceF1` never applies.
972 TEST_F(TransformerTest, OrderedRuleRelatedSwapped) {
973 std::string Input = R"cc(
974 void f1();
975 void f2();
976 void call_f1() { f1(); }
977 void call_f2() { f2(); }
978 )cc";
979 std::string Expected = R"cc(
980 void f1();
981 void f2();
982 void call_f1() { REPLACE_F1_OR_F2; }
983 void call_f2() { REPLACE_F1_OR_F2; }
984 )cc";
986 RewriteRule ReplaceF1 =
987 makeRule(callExpr(callee(functionDecl(hasName("f1")))),
988 changeTo(cat("REPLACE_F1")));
989 RewriteRule ReplaceF1OrF2 =
990 makeRule(callExpr(callee(functionDecl(hasAnyName("f1", "f2")))),
991 changeTo(cat("REPLACE_F1_OR_F2")));
992 testRule(applyFirst({ReplaceF1OrF2, ReplaceF1}), Input, Expected);
995 // Verify that a set of rules whose matchers have different base kinds works
996 // properly, including that `applyFirst` produces multiple matchers. We test
997 // two different kinds of rules: Expr and Decl. We place the Decl rule in the
998 // middle to test that `buildMatchers` works even when the kinds aren't grouped
999 // together.
1000 TEST_F(TransformerTest, OrderedRuleMultipleKinds) {
1001 std::string Input = R"cc(
1002 void f1();
1003 void f2();
1004 void call_f1() { f1(); }
1005 void call_f2() { f2(); }
1006 )cc";
1007 std::string Expected = R"cc(
1008 void f1();
1009 void DECL_RULE();
1010 void call_f1() { REPLACE_F1; }
1011 void call_f2() { REPLACE_F1_OR_F2; }
1012 )cc";
1014 RewriteRule ReplaceF1 =
1015 makeRule(callExpr(callee(functionDecl(hasName("f1")))),
1016 changeTo(cat("REPLACE_F1")));
1017 RewriteRule ReplaceF1OrF2 =
1018 makeRule(callExpr(callee(functionDecl(hasAnyName("f1", "f2")))),
1019 changeTo(cat("REPLACE_F1_OR_F2")));
1020 RewriteRule DeclRule = makeRule(functionDecl(hasName("f2")).bind("fun"),
1021 changeTo(name("fun"), cat("DECL_RULE")));
1023 RewriteRule Rule = applyFirst({ReplaceF1, DeclRule, ReplaceF1OrF2});
1024 EXPECT_EQ(transformer::detail::buildMatchers(Rule).size(), 2UL);
1025 testRule(Rule, Input, Expected);
1028 // Verifies that a rule with a top-level matcher for an implicit node (like
1029 // `implicitCastExpr`) works correctly -- the implicit nodes are not skipped.
1030 TEST_F(TransformerTest, OrderedRuleImplicitMatched) {
1031 std::string Input = R"cc(
1032 void f1();
1033 int f2();
1034 void call_f1() { f1(); }
1035 float call_f2() { return f2(); }
1036 )cc";
1037 std::string Expected = R"cc(
1038 void f1();
1039 int f2();
1040 void call_f1() { REPLACE_F1; }
1041 float call_f2() { return REPLACE_F2; }
1042 )cc";
1044 RewriteRule ReplaceF1 =
1045 makeRule(callExpr(callee(functionDecl(hasName("f1")))),
1046 changeTo(cat("REPLACE_F1")));
1047 RewriteRule ReplaceF2 =
1048 makeRule(implicitCastExpr(hasSourceExpression(callExpr())),
1049 changeTo(cat("REPLACE_F2")));
1050 testRule(applyFirst({ReplaceF1, ReplaceF2}), Input, Expected);
1054 // Negative tests (where we expect no transformation to occur).
1057 // Tests for a conflict in edits from a single match for a rule.
1058 TEST_F(TransformerTest, TextGeneratorFailure) {
1059 std::string Input = "int conflictOneRule() { return 3 + 7; }";
1060 // Try to change the whole binary-operator expression AND one its operands:
1061 StringRef O = "O";
1062 class AlwaysFail : public transformer::MatchComputation<std::string> {
1063 llvm::Error eval(const ast_matchers::MatchFinder::MatchResult &,
1064 std::string *) const override {
1065 return llvm::createStringError(llvm::errc::invalid_argument, "ERROR");
1067 std::string toString() const override { return "AlwaysFail"; }
1069 Transformer T(
1070 makeRule(binaryOperator().bind(O),
1071 changeTo(node(std::string(O)), std::make_shared<AlwaysFail>())),
1072 consumer());
1073 T.registerMatchers(&MatchFinder);
1074 EXPECT_FALSE(rewrite(Input));
1075 EXPECT_THAT(Changes, IsEmpty());
1076 EXPECT_EQ(ErrorCount, 1);
1079 // Tests for a conflict in edits from a single match for a rule.
1080 TEST_F(TransformerTest, OverlappingEditsInRule) {
1081 std::string Input = "int conflictOneRule() { return 3 + 7; }";
1082 // Try to change the whole binary-operator expression AND one its operands:
1083 StringRef O = "O", L = "L";
1084 Transformer T(makeRule(binaryOperator(hasLHS(expr().bind(L))).bind(O),
1085 {changeTo(node(std::string(O)), cat("DELETE_OP")),
1086 changeTo(node(std::string(L)), cat("DELETE_LHS"))}),
1087 consumer());
1088 T.registerMatchers(&MatchFinder);
1089 EXPECT_FALSE(rewrite(Input));
1090 EXPECT_THAT(Changes, IsEmpty());
1091 EXPECT_EQ(ErrorCount, 1);
1094 // Tests for a conflict in edits across multiple matches (of the same rule).
1095 TEST_F(TransformerTest, OverlappingEditsMultipleMatches) {
1096 std::string Input = "int conflictOneRule() { return -7; }";
1097 // Try to change the whole binary-operator expression AND one its operands:
1098 StringRef E = "E";
1099 Transformer T(makeRule(expr().bind(E),
1100 changeTo(node(std::string(E)), cat("DELETE_EXPR"))),
1101 consumer());
1102 T.registerMatchers(&MatchFinder);
1103 // The rewrite process fails because the changes conflict with each other...
1104 EXPECT_FALSE(rewrite(Input));
1105 // ... but two changes were produced.
1106 EXPECT_EQ(Changes.size(), 2u);
1107 EXPECT_EQ(ErrorCount, 0);
1110 TEST_F(TransformerTest, ErrorOccurredMatchSkipped) {
1111 // Syntax error in the function body:
1112 std::string Input = "void errorOccurred() { 3 }";
1113 Transformer T(makeRule(functionDecl(hasName("errorOccurred")),
1114 changeTo(cat("DELETED;"))),
1115 consumer());
1116 T.registerMatchers(&MatchFinder);
1117 // The rewrite process itself fails...
1118 EXPECT_FALSE(rewrite(Input));
1119 // ... and no changes or errors are produced in the process.
1120 EXPECT_THAT(Changes, IsEmpty());
1121 EXPECT_EQ(ErrorCount, 0);
1124 TEST_F(TransformerTest, ImplicitNodes_ConstructorDecl) {
1126 std::string OtherStructPrefix = R"cpp(
1127 struct Other {
1128 )cpp";
1129 std::string OtherStructSuffix = "};";
1131 std::string CopyableStructName = "struct Copyable";
1132 std::string BrokenStructName = "struct explicit Copyable";
1134 std::string CodeSuffix = R"cpp(
1136 Other m_i;
1137 Copyable();
1139 )cpp";
1141 std::string CopyCtor = "Other(const Other&) = default;";
1142 std::string ExplicitCopyCtor = "explicit Other(const Other&) = default;";
1143 std::string BrokenExplicitCopyCtor =
1144 "explicit explicit explicit Other(const Other&) = default;";
1146 std::string RewriteInput = OtherStructPrefix + CopyCtor + OtherStructSuffix +
1147 CopyableStructName + CodeSuffix;
1148 std::string ExpectedRewriteOutput = OtherStructPrefix + ExplicitCopyCtor +
1149 OtherStructSuffix + CopyableStructName +
1150 CodeSuffix;
1151 std::string BrokenRewriteOutput = OtherStructPrefix + BrokenExplicitCopyCtor +
1152 OtherStructSuffix + BrokenStructName +
1153 CodeSuffix;
1155 auto MatchedRecord =
1156 cxxConstructorDecl(isCopyConstructor()).bind("copyConstructor");
1158 auto RewriteRule =
1159 changeTo(before(node("copyConstructor")), cat("explicit "));
1161 testRule(makeRule(traverse(TK_IgnoreUnlessSpelledInSource, MatchedRecord),
1162 RewriteRule),
1163 RewriteInput, ExpectedRewriteOutput);
1165 testRule(makeRule(traverse(TK_AsIs, MatchedRecord), RewriteRule),
1166 RewriteInput, BrokenRewriteOutput);
1169 TEST_F(TransformerTest, ImplicitNodes_RangeFor) {
1171 std::string CodePrefix = R"cpp(
1172 struct Container
1174 int* begin() const;
1175 int* end() const;
1176 int* cbegin() const;
1177 int* cend() const;
1180 void foo()
1182 const Container c;
1183 )cpp";
1185 std::string BeginCallBefore = " c.begin();";
1186 std::string BeginCallAfter = " c.cbegin();";
1188 std::string ForLoop = "for (auto i : c)";
1189 std::string BrokenForLoop = "for (auto i :.cbegin() c)";
1191 std::string CodeSuffix = R"cpp(
1195 )cpp";
1197 std::string RewriteInput =
1198 CodePrefix + BeginCallBefore + ForLoop + CodeSuffix;
1199 std::string ExpectedRewriteOutput =
1200 CodePrefix + BeginCallAfter + ForLoop + CodeSuffix;
1201 std::string BrokenRewriteOutput =
1202 CodePrefix + BeginCallAfter + BrokenForLoop + CodeSuffix;
1204 auto MatchedRecord =
1205 cxxMemberCallExpr(on(expr(hasType(qualType(isConstQualified(),
1206 hasDeclaration(cxxRecordDecl(
1207 hasName("Container"))))))
1208 .bind("callTarget")),
1209 callee(cxxMethodDecl(hasName("begin"))))
1210 .bind("constBeginCall");
1212 auto RewriteRule =
1213 changeTo(node("constBeginCall"), cat(name("callTarget"), ".cbegin()"));
1215 testRule(makeRule(traverse(TK_IgnoreUnlessSpelledInSource, MatchedRecord),
1216 RewriteRule),
1217 RewriteInput, ExpectedRewriteOutput);
1219 testRule(makeRule(traverse(TK_AsIs, MatchedRecord), RewriteRule),
1220 RewriteInput, BrokenRewriteOutput);
1223 TEST_F(TransformerTest, ImplicitNodes_ForStmt) {
1225 std::string CodePrefix = R"cpp(
1226 struct NonTrivial {
1227 NonTrivial() {}
1228 NonTrivial(NonTrivial&) {}
1229 NonTrivial& operator=(NonTrivial const&) { return *this; }
1231 ~NonTrivial() {}
1234 struct ContainsArray {
1235 NonTrivial arr[2];
1236 ContainsArray& operator=(ContainsArray const&) = default;
1239 void testIt()
1241 ContainsArray ca1;
1242 ContainsArray ca2;
1243 ca2 = ca1;
1244 )cpp";
1246 auto CodeSuffix = "}";
1248 auto LoopBody = R"cpp(
1252 )cpp";
1254 auto RawLoop = "for (auto i = 0; i != 5; ++i)";
1256 auto RangeLoop = "for (auto i : boost::irange(5))";
1258 // Expect to rewrite the raw loop to the ranged loop.
1259 // This works in TK_IgnoreUnlessSpelledInSource mode, but TK_AsIs
1260 // mode also matches the hidden for loop generated in the copy assignment
1261 // operator of ContainsArray. Transformer then fails to transform the code at
1262 // all.
1264 auto RewriteInput =
1265 CodePrefix + RawLoop + LoopBody + RawLoop + LoopBody + CodeSuffix;
1267 auto RewriteOutput =
1268 CodePrefix + RangeLoop + LoopBody + RangeLoop + LoopBody + CodeSuffix;
1270 auto MatchedLoop = forStmt(
1271 has(declStmt(hasSingleDecl(
1272 varDecl(hasInitializer(integerLiteral(equals(0)))).bind("loopVar")))),
1273 has(binaryOperator(hasOperatorName("!="),
1274 hasLHS(ignoringImplicit(declRefExpr(
1275 to(varDecl(equalsBoundNode("loopVar")))))),
1276 hasRHS(expr().bind("upperBoundExpr")))),
1277 has(unaryOperator(hasOperatorName("++"),
1278 hasUnaryOperand(declRefExpr(
1279 to(varDecl(equalsBoundNode("loopVar"))))))
1280 .bind("incrementOp")));
1282 auto RewriteRule =
1283 changeTo(transformer::enclose(node("loopVar"), node("incrementOp")),
1284 cat("auto ", name("loopVar"), " : boost::irange(",
1285 node("upperBoundExpr"), ")"));
1287 testRule(makeRule(traverse(TK_IgnoreUnlessSpelledInSource, MatchedLoop),
1288 RewriteRule),
1289 RewriteInput, RewriteOutput);
1291 testRuleFailure(makeRule(traverse(TK_AsIs, MatchedLoop), RewriteRule),
1292 RewriteInput);
1295 TEST_F(TransformerTest, ImplicitNodes_ForStmt2) {
1297 std::string CodePrefix = R"cpp(
1298 struct NonTrivial {
1299 NonTrivial() {}
1300 NonTrivial(NonTrivial&) {}
1301 NonTrivial& operator=(NonTrivial const&) { return *this; }
1303 ~NonTrivial() {}
1306 struct ContainsArray {
1307 NonTrivial arr[2];
1308 ContainsArray& operator=(ContainsArray const&) = default;
1311 void testIt()
1313 ContainsArray ca1;
1314 ContainsArray ca2;
1315 ca2 = ca1;
1316 )cpp";
1318 auto CodeSuffix = "}";
1320 auto LoopBody = R"cpp(
1324 )cpp";
1326 auto RawLoop = "for (auto i = 0; i != 5; ++i)";
1328 auto RangeLoop = "for (auto i : boost::irange(5))";
1330 // Expect to rewrite the raw loop to the ranged loop.
1331 // This works in TK_IgnoreUnlessSpelledInSource mode, but TK_AsIs
1332 // mode also matches the hidden for loop generated in the copy assignment
1333 // operator of ContainsArray. Transformer then fails to transform the code at
1334 // all.
1336 auto RewriteInput =
1337 CodePrefix + RawLoop + LoopBody + RawLoop + LoopBody + CodeSuffix;
1339 auto RewriteOutput =
1340 CodePrefix + RangeLoop + LoopBody + RangeLoop + LoopBody + CodeSuffix;
1341 auto MatchedLoop = forStmt(
1342 hasLoopInit(declStmt(hasSingleDecl(
1343 varDecl(hasInitializer(integerLiteral(equals(0)))).bind("loopVar")))),
1344 hasCondition(binaryOperator(hasOperatorName("!="),
1345 hasLHS(ignoringImplicit(declRefExpr(to(
1346 varDecl(equalsBoundNode("loopVar")))))),
1347 hasRHS(expr().bind("upperBoundExpr")))),
1348 hasIncrement(unaryOperator(hasOperatorName("++"),
1349 hasUnaryOperand(declRefExpr(
1350 to(varDecl(equalsBoundNode("loopVar"))))))
1351 .bind("incrementOp")));
1353 auto RewriteRule =
1354 changeTo(transformer::enclose(node("loopVar"), node("incrementOp")),
1355 cat("auto ", name("loopVar"), " : boost::irange(",
1356 node("upperBoundExpr"), ")"));
1358 testRule(makeRule(traverse(TK_IgnoreUnlessSpelledInSource, MatchedLoop),
1359 RewriteRule),
1360 RewriteInput, RewriteOutput);
1362 testRuleFailure(makeRule(traverse(TK_AsIs, MatchedLoop), RewriteRule),
1363 RewriteInput);
1366 TEST_F(TransformerTest, TemplateInstantiation) {
1368 std::string NonTemplatesInput = R"cpp(
1369 struct S {
1370 int m_i;
1372 )cpp";
1373 std::string NonTemplatesExpected = R"cpp(
1374 struct S {
1375 safe_int m_i;
1377 )cpp";
1379 std::string TemplatesInput = R"cpp(
1380 template<typename T>
1381 struct TemplStruct {
1382 TemplStruct() {}
1383 ~TemplStruct() {}
1385 private:
1386 T m_t;
1389 void instantiate()
1391 TemplStruct<int> ti;
1393 )cpp";
1395 auto MatchedField = fieldDecl(hasType(asString("int"))).bind("theField");
1397 // Changes the 'int' in 'S', but not the 'T' in 'TemplStruct':
1398 testRule(makeRule(traverse(TK_IgnoreUnlessSpelledInSource, MatchedField),
1399 changeTo(cat("safe_int ", name("theField"), ";"))),
1400 NonTemplatesInput + TemplatesInput,
1401 NonTemplatesExpected + TemplatesInput);
1403 // In AsIs mode, template instantiations are modified, which is
1404 // often not desired:
1406 std::string IncorrectTemplatesExpected = R"cpp(
1407 template<typename T>
1408 struct TemplStruct {
1409 TemplStruct() {}
1410 ~TemplStruct() {}
1412 private:
1413 safe_int m_t;
1416 void instantiate()
1418 TemplStruct<int> ti;
1420 )cpp";
1422 // Changes the 'int' in 'S', and (incorrectly) the 'T' in 'TemplStruct':
1423 testRule(makeRule(traverse(TK_AsIs, MatchedField),
1424 changeTo(cat("safe_int ", name("theField"), ";"))),
1426 NonTemplatesInput + TemplatesInput,
1427 NonTemplatesExpected + IncorrectTemplatesExpected);
1430 // Transformation of macro source text when the change encompasses the entirety
1431 // of the expanded text.
1432 TEST_F(TransformerTest, SimpleMacro) {
1433 std::string Input = R"cc(
1434 #define ZERO 0
1435 int f(string s) { return ZERO; }
1436 )cc";
1437 std::string Expected = R"cc(
1438 #define ZERO 0
1439 int f(string s) { return 999; }
1440 )cc";
1442 StringRef zero = "zero";
1443 RewriteRule R = makeRule(integerLiteral(equals(0)).bind(zero),
1444 changeTo(node(std::string(zero)), cat("999")));
1445 testRule(R, Input, Expected);
1448 // Transformation of macro source text when the change encompasses the entirety
1449 // of the expanded text, for the case of function-style macros.
1450 TEST_F(TransformerTest, FunctionMacro) {
1451 std::string Input = R"cc(
1452 #define MACRO(str) strlen((str).c_str())
1453 int f(string s) { return MACRO(s); }
1454 )cc";
1455 std::string Expected = R"cc(
1456 #define MACRO(str) strlen((str).c_str())
1457 int f(string s) { return REPLACED; }
1458 )cc";
1460 testRule(ruleStrlenSize(), Input, Expected);
1463 // Tests that expressions in macro arguments can be rewritten.
1464 TEST_F(TransformerTest, MacroArg) {
1465 std::string Input = R"cc(
1466 #define PLUS(e) e + 1
1467 int f(string s) { return PLUS(strlen(s.c_str())); }
1468 )cc";
1469 std::string Expected = R"cc(
1470 #define PLUS(e) e + 1
1471 int f(string s) { return PLUS(REPLACED); }
1472 )cc";
1474 testRule(ruleStrlenSize(), Input, Expected);
1477 // Tests that expressions in macro arguments can be rewritten, even when the
1478 // macro call occurs inside another macro's definition.
1479 TEST_F(TransformerTest, MacroArgInMacroDef) {
1480 std::string Input = R"cc(
1481 #define NESTED(e) e
1482 #define MACRO(str) NESTED(strlen((str).c_str()))
1483 int f(string s) { return MACRO(s); }
1484 )cc";
1485 std::string Expected = R"cc(
1486 #define NESTED(e) e
1487 #define MACRO(str) NESTED(strlen((str).c_str()))
1488 int f(string s) { return REPLACED; }
1489 )cc";
1491 testRule(ruleStrlenSize(), Input, Expected);
1494 // Tests the corner case of the identity macro, specifically that it is
1495 // discarded in the rewrite rather than preserved (like PLUS is preserved in the
1496 // previous test). This behavior is of dubious value (and marked with a FIXME
1497 // in the code), but we test it to verify (and demonstrate) how this case is
1498 // handled.
1499 TEST_F(TransformerTest, IdentityMacro) {
1500 std::string Input = R"cc(
1501 #define ID(e) e
1502 int f(string s) { return ID(strlen(s.c_str())); }
1503 )cc";
1504 std::string Expected = R"cc(
1505 #define ID(e) e
1506 int f(string s) { return REPLACED; }
1507 )cc";
1509 testRule(ruleStrlenSize(), Input, Expected);
1512 // Tests that two changes in a single macro expansion do not lead to conflicts
1513 // in applying the changes.
1514 TEST_F(TransformerTest, TwoChangesInOneMacroExpansion) {
1515 std::string Input = R"cc(
1516 #define PLUS(a,b) (a) + (b)
1517 int f() { return PLUS(3, 4); }
1518 )cc";
1519 std::string Expected = R"cc(
1520 #define PLUS(a,b) (a) + (b)
1521 int f() { return PLUS(LIT, LIT); }
1522 )cc";
1524 testRule(makeRule(integerLiteral(), changeTo(cat("LIT"))), Input, Expected);
1527 // Tests case where the rule's match spans both source from the macro and its
1528 // arg, with the begin location (the "anchor") being the arg.
1529 TEST_F(TransformerTest, MatchSpansMacroTextButChangeDoesNot) {
1530 std::string Input = R"cc(
1531 #define PLUS_ONE(a) a + 1
1532 int f() { return PLUS_ONE(3); }
1533 )cc";
1534 std::string Expected = R"cc(
1535 #define PLUS_ONE(a) a + 1
1536 int f() { return PLUS_ONE(LIT); }
1537 )cc";
1539 StringRef E = "expr";
1540 testRule(makeRule(binaryOperator(hasLHS(expr().bind(E))),
1541 changeTo(node(std::string(E)), cat("LIT"))),
1542 Input, Expected);
1545 // Tests case where the rule's match spans both source from the macro and its
1546 // arg, with the begin location (the "anchor") being inside the macro.
1547 TEST_F(TransformerTest, MatchSpansMacroTextButChangeDoesNotAnchoredInMacro) {
1548 std::string Input = R"cc(
1549 #define PLUS_ONE(a) 1 + a
1550 int f() { return PLUS_ONE(3); }
1551 )cc";
1552 std::string Expected = R"cc(
1553 #define PLUS_ONE(a) 1 + a
1554 int f() { return PLUS_ONE(LIT); }
1555 )cc";
1557 StringRef E = "expr";
1558 testRule(makeRule(binaryOperator(hasRHS(expr().bind(E))),
1559 changeTo(node(std::string(E)), cat("LIT"))),
1560 Input, Expected);
1563 // No rewrite is applied when the changed text does not encompass the entirety
1564 // of the expanded text. That is, the edit would have to be applied to the
1565 // macro's definition to succeed and editing the expansion point would not
1566 // suffice.
1567 TEST_F(TransformerTest, NoPartialRewriteOMacroExpansion) {
1568 std::string Input = R"cc(
1569 #define ZERO_PLUS 0 + 3
1570 int f(string s) { return ZERO_PLUS; })cc";
1572 StringRef zero = "zero";
1573 RewriteRule R = makeRule(integerLiteral(equals(0)).bind(zero),
1574 changeTo(node(std::string(zero)), cat("0")));
1575 testRule(R, Input, Input);
1578 // This test handles the corner case where a macro expands within another macro
1579 // to matching code, but that code is an argument to the nested macro call. A
1580 // simple check of isMacroArgExpansion() vs. isMacroBodyExpansion() will get
1581 // this wrong, and transform the code.
1582 TEST_F(TransformerTest, NoPartialRewriteOfMacroExpansionForMacroArgs) {
1583 std::string Input = R"cc(
1584 #define NESTED(e) e
1585 #define MACRO(str) 1 + NESTED(strlen((str).c_str()))
1586 int f(string s) { return MACRO(s); }
1587 )cc";
1589 testRule(ruleStrlenSize(), Input, Input);
1592 #if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST
1593 // Verifies that `Type` and `QualType` are not allowed as top-level matchers in
1594 // rules.
1595 TEST(TransformerDeathTest, OrderedRuleTypes) {
1596 RewriteRule QualTypeRule = makeRule(qualType(), changeTo(cat("Q")));
1597 EXPECT_DEATH(transformer::detail::buildMatchers(QualTypeRule),
1598 "Matcher must be.*node matcher");
1600 RewriteRule TypeRule = makeRule(arrayType(), changeTo(cat("T")));
1601 EXPECT_DEATH(transformer::detail::buildMatchers(TypeRule),
1602 "Matcher must be.*node matcher");
1604 #endif
1606 // Edits are able to span multiple files; in this case, a header and an
1607 // implementation file.
1608 TEST_F(TransformerTest, MultipleFiles) {
1609 std::string Header = R"cc(void RemoveThisFunction();)cc";
1610 std::string Source = R"cc(#include "input.h"
1611 void RemoveThisFunction();)cc";
1612 Transformer T(
1613 makeRule(functionDecl(hasName("RemoveThisFunction")), changeTo(cat(""))),
1614 consumer());
1615 T.registerMatchers(&MatchFinder);
1616 auto Factory = newFrontendActionFactory(&MatchFinder);
1617 EXPECT_TRUE(runToolOnCodeWithArgs(
1618 Factory->create(), Source, std::vector<std::string>(), "input.cc",
1619 "clang-tool", std::make_shared<PCHContainerOperations>(),
1620 {{"input.h", Header}}));
1622 llvm::sort(Changes, [](const AtomicChange &L, const AtomicChange &R) {
1623 return L.getFilePath() < R.getFilePath();
1626 ASSERT_EQ(llvm::sys::path::convert_to_slash(Changes[0].getFilePath()),
1627 "./input.h");
1628 EXPECT_THAT(Changes[0].getInsertedHeaders(), IsEmpty());
1629 EXPECT_THAT(Changes[0].getRemovedHeaders(), IsEmpty());
1630 llvm::Expected<std::string> UpdatedCode =
1631 clang::tooling::applyAllReplacements(Header,
1632 Changes[0].getReplacements());
1633 ASSERT_TRUE(static_cast<bool>(UpdatedCode))
1634 << "Could not update code: " << llvm::toString(UpdatedCode.takeError());
1635 EXPECT_EQ(format(*UpdatedCode), "");
1637 ASSERT_EQ(Changes[1].getFilePath(), "input.cc");
1638 EXPECT_THAT(Changes[1].getInsertedHeaders(), IsEmpty());
1639 EXPECT_THAT(Changes[1].getRemovedHeaders(), IsEmpty());
1640 UpdatedCode = clang::tooling::applyAllReplacements(
1641 Source, Changes[1].getReplacements());
1642 ASSERT_TRUE(static_cast<bool>(UpdatedCode))
1643 << "Could not update code: " << llvm::toString(UpdatedCode.takeError());
1644 EXPECT_EQ(format(*UpdatedCode), format("#include \"input.h\"\n"));
1647 TEST_F(TransformerTest, AddIncludeMultipleFiles) {
1648 std::string Header = R"cc(void RemoveThisFunction();)cc";
1649 std::string Source = R"cc(#include "input.h"
1650 void Foo() {RemoveThisFunction();})cc";
1651 Transformer T(
1652 makeRule(callExpr(callee(
1653 functionDecl(hasName("RemoveThisFunction")).bind("fun"))),
1654 addInclude(node("fun"), "header.h")),
1655 consumer());
1656 T.registerMatchers(&MatchFinder);
1657 auto Factory = newFrontendActionFactory(&MatchFinder);
1658 EXPECT_TRUE(runToolOnCodeWithArgs(
1659 Factory->create(), Source, std::vector<std::string>(), "input.cc",
1660 "clang-tool", std::make_shared<PCHContainerOperations>(),
1661 {{"input.h", Header}}));
1663 ASSERT_EQ(Changes.size(), 1U);
1664 ASSERT_EQ(llvm::sys::path::convert_to_slash(Changes[0].getFilePath()),
1665 "./input.h");
1666 EXPECT_THAT(Changes[0].getInsertedHeaders(), ElementsAre("header.h"));
1667 EXPECT_THAT(Changes[0].getRemovedHeaders(), IsEmpty());
1668 llvm::Expected<std::string> UpdatedCode =
1669 clang::tooling::applyAllReplacements(Header,
1670 Changes[0].getReplacements());
1671 ASSERT_TRUE(static_cast<bool>(UpdatedCode))
1672 << "Could not update code: " << llvm::toString(UpdatedCode.takeError());
1673 EXPECT_EQ(format(*UpdatedCode), format(Header));
1676 // A single change set can span multiple files.
1677 TEST_F(TransformerTest, MultiFileEdit) {
1678 // NB: The fixture is unused for this test, but kept for the test suite name.
1679 std::string Header = R"cc(void Func(int id);)cc";
1680 std::string Source = R"cc(#include "input.h"
1681 void Caller() {
1682 int id = 0;
1683 Func(id);
1684 })cc";
1685 int ErrorCount = 0;
1686 std::vector<AtomicChanges> ChangeSets;
1687 clang::ast_matchers::MatchFinder MatchFinder;
1688 Transformer T(
1689 makeRule(callExpr(callee(functionDecl(hasName("Func"))),
1690 forEachArgumentWithParam(expr().bind("arg"),
1691 parmVarDecl().bind("param"))),
1692 {changeTo(node("arg"), cat("ARG")),
1693 changeTo(node("param"), cat("PARAM"))}),
1694 [&](Expected<MutableArrayRef<AtomicChange>> Changes) {
1695 if (Changes)
1696 ChangeSets.push_back(AtomicChanges(Changes->begin(), Changes->end()));
1697 else
1698 ++ErrorCount;
1700 T.registerMatchers(&MatchFinder);
1701 auto Factory = newFrontendActionFactory(&MatchFinder);
1702 EXPECT_TRUE(runToolOnCodeWithArgs(
1703 Factory->create(), Source, std::vector<std::string>(), "input.cc",
1704 "clang-tool", std::make_shared<PCHContainerOperations>(),
1705 {{"input.h", Header}}));
1707 auto GetPathWithSlashes = [](const AtomicChange &C) {
1708 return llvm::sys::path::convert_to_slash(C.getFilePath());
1711 EXPECT_EQ(ErrorCount, 0);
1712 EXPECT_THAT(ChangeSets, UnorderedElementsAre(UnorderedElementsAre(
1713 ResultOf(GetPathWithSlashes, "input.cc"),
1714 ResultOf(GetPathWithSlashes, "./input.h"))));
1717 TEST_F(TransformerTest, GeneratesMetadata) {
1718 std::string Input = R"cc(int target = 0;)cc";
1719 std::string Expected = R"cc(REPLACE)cc";
1720 RewriteRuleWith<std::string> Rule = makeRule(
1721 varDecl(hasName("target")), changeTo(cat("REPLACE")), cat("METADATA"));
1722 testRule(std::move(Rule), Input, Expected);
1723 EXPECT_EQ(ErrorCount, 0);
1724 EXPECT_THAT(StringMetadata, UnorderedElementsAre("METADATA"));
1727 TEST_F(TransformerTest, GeneratesMetadataWithNoEdits) {
1728 std::string Input = R"cc(int target = 0;)cc";
1729 RewriteRuleWith<std::string> Rule = makeRule(
1730 varDecl(hasName("target")).bind("var"), noEdits(), cat("METADATA"));
1731 testRule(std::move(Rule), Input, Input);
1732 EXPECT_EQ(ErrorCount, 0);
1733 EXPECT_THAT(StringMetadata, UnorderedElementsAre("METADATA"));
1736 TEST_F(TransformerTest, PropagateMetadataErrors) {
1737 class AlwaysFail : public transformer::MatchComputation<std::string> {
1738 llvm::Error eval(const ast_matchers::MatchFinder::MatchResult &,
1739 std::string *) const override {
1740 return llvm::createStringError(llvm::errc::invalid_argument, "ERROR");
1742 std::string toString() const override { return "AlwaysFail"; }
1744 std::string Input = R"cc(int target = 0;)cc";
1745 RewriteRuleWith<std::string> Rule = makeRule<std::string>(
1746 varDecl(hasName("target")).bind("var"), changeTo(cat("REPLACE")),
1747 std::make_shared<AlwaysFail>());
1748 testRuleFailure(std::move(Rule), Input);
1749 EXPECT_EQ(ErrorCount, 1);
1752 } // namespace