[DebugInfo] Limit the number of values that may be referenced by a dbg.value
[llvm-project.git] / clang / unittests / Tooling / TransformerTest.cpp
blob9ef1c08a7cfa393ebd872ed635c9ace18a90e281
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/Support/Errc.h"
16 #include "llvm/Support/Error.h"
17 #include "gmock/gmock.h"
18 #include "gtest/gtest.h"
20 using namespace clang;
21 using namespace tooling;
22 using namespace ast_matchers;
23 namespace {
24 using ::clang::transformer::addInclude;
25 using ::clang::transformer::applyFirst;
26 using ::clang::transformer::before;
27 using ::clang::transformer::cat;
28 using ::clang::transformer::changeTo;
29 using ::clang::transformer::makeRule;
30 using ::clang::transformer::member;
31 using ::clang::transformer::name;
32 using ::clang::transformer::node;
33 using ::clang::transformer::remove;
34 using ::clang::transformer::rewriteDescendants;
35 using ::clang::transformer::RewriteRule;
36 using ::clang::transformer::statement;
37 using ::testing::ElementsAre;
38 using ::testing::IsEmpty;
40 constexpr char KHeaderContents[] = R"cc(
41 struct string {
42 string(const char*);
43 char* c_str();
44 int size();
46 int strlen(const char*);
48 namespace proto {
49 struct PCFProto {
50 int foo();
52 struct ProtoCommandLineFlag : PCFProto {
53 PCFProto& GetProto();
55 } // namespace proto
56 class Logger {};
57 void operator<<(Logger& l, string msg);
58 Logger& log(int level);
59 )cc";
61 static ast_matchers::internal::Matcher<clang::QualType>
62 isOrPointsTo(const clang::ast_matchers::DeclarationMatcher &TypeMatcher) {
63 return anyOf(hasDeclaration(TypeMatcher), pointsTo(TypeMatcher));
66 static std::string format(StringRef Code) {
67 const std::vector<Range> Ranges(1, Range(0, Code.size()));
68 auto Style = format::getLLVMStyle();
69 const auto Replacements = format::reformat(Style, Code, Ranges);
70 auto Formatted = applyAllReplacements(Code, Replacements);
71 if (!Formatted) {
72 ADD_FAILURE() << "Could not format code: "
73 << llvm::toString(Formatted.takeError());
74 return std::string();
76 return *Formatted;
79 static void compareSnippets(StringRef Expected,
80 const llvm::Optional<std::string> &MaybeActual) {
81 ASSERT_TRUE(MaybeActual) << "Rewrite failed. Expecting: " << Expected;
82 auto Actual = *MaybeActual;
83 std::string HL = "#include \"header.h\"\n";
84 auto I = Actual.find(HL);
85 if (I != std::string::npos)
86 Actual.erase(I, HL.size());
87 EXPECT_EQ(format(Expected), format(Actual));
90 // FIXME: consider separating this class into its own file(s).
91 class ClangRefactoringTestBase : public testing::Test {
92 protected:
93 void appendToHeader(StringRef S) { FileContents[0].second += S; }
95 void addFile(StringRef Filename, StringRef Content) {
96 FileContents.emplace_back(std::string(Filename), std::string(Content));
99 llvm::Optional<std::string> rewrite(StringRef Input) {
100 std::string Code = ("#include \"header.h\"\n" + Input).str();
101 auto Factory = newFrontendActionFactory(&MatchFinder);
102 if (!runToolOnCodeWithArgs(
103 Factory->create(), Code, std::vector<std::string>(), "input.cc",
104 "clang-tool", std::make_shared<PCHContainerOperations>(),
105 FileContents)) {
106 llvm::errs() << "Running tool failed.\n";
107 return None;
109 if (ErrorCount != 0) {
110 llvm::errs() << "Generating changes failed.\n";
111 return None;
113 auto ChangedCode =
114 applyAtomicChanges("input.cc", Code, Changes, ApplyChangesSpec());
115 if (!ChangedCode) {
116 llvm::errs() << "Applying changes failed: "
117 << llvm::toString(ChangedCode.takeError()) << "\n";
118 return None;
120 return *ChangedCode;
123 Transformer::ChangeConsumer consumer() {
124 return [this](Expected<AtomicChange> C) {
125 if (C) {
126 Changes.push_back(std::move(*C));
127 } else {
128 // FIXME: stash this error rather then printing.
129 llvm::errs() << "Error generating changes: "
130 << llvm::toString(C.takeError()) << "\n";
131 ++ErrorCount;
136 template <typename R>
137 void testRule(R Rule, StringRef Input, StringRef Expected) {
138 Transformers.push_back(
139 std::make_unique<Transformer>(std::move(Rule), consumer()));
140 Transformers.back()->registerMatchers(&MatchFinder);
141 compareSnippets(Expected, rewrite(Input));
144 template <typename R> void testRuleFailure(R Rule, StringRef Input) {
145 Transformers.push_back(
146 std::make_unique<Transformer>(std::move(Rule), consumer()));
147 Transformers.back()->registerMatchers(&MatchFinder);
148 ASSERT_FALSE(rewrite(Input)) << "Expected failure to rewrite code";
151 // Transformers are referenced by MatchFinder.
152 std::vector<std::unique_ptr<Transformer>> Transformers;
153 clang::ast_matchers::MatchFinder MatchFinder;
154 // Records whether any errors occurred in individual changes.
155 int ErrorCount = 0;
156 AtomicChanges Changes;
158 private:
159 FileContentMappings FileContents = {{"header.h", ""}};
162 class TransformerTest : public ClangRefactoringTestBase {
163 protected:
164 TransformerTest() { appendToHeader(KHeaderContents); }
167 // Given string s, change strlen($s.c_str()) to REPLACED.
168 static RewriteRule ruleStrlenSize() {
169 StringRef StringExpr = "strexpr";
170 auto StringType = namedDecl(hasAnyName("::basic_string", "::string"));
171 auto R = makeRule(
172 callExpr(callee(functionDecl(hasName("strlen"))),
173 hasArgument(0, cxxMemberCallExpr(
174 on(expr(hasType(isOrPointsTo(StringType)))
175 .bind(StringExpr)),
176 callee(cxxMethodDecl(hasName("c_str")))))),
177 changeTo(cat("REPLACED")), cat("Use size() method directly on string."));
178 return R;
181 TEST_F(TransformerTest, StrlenSize) {
182 std::string Input = "int f(string s) { return strlen(s.c_str()); }";
183 std::string Expected = "int f(string s) { return REPLACED; }";
184 testRule(ruleStrlenSize(), Input, Expected);
187 // Tests that no change is applied when a match is not expected.
188 TEST_F(TransformerTest, NoMatch) {
189 std::string Input = "int f(string s) { return s.size(); }";
190 testRule(ruleStrlenSize(), Input, Input);
193 // Tests replacing an expression.
194 TEST_F(TransformerTest, Flag) {
195 StringRef Flag = "flag";
196 RewriteRule Rule = makeRule(
197 cxxMemberCallExpr(on(expr(hasType(cxxRecordDecl(
198 hasName("proto::ProtoCommandLineFlag"))))
199 .bind(Flag)),
200 unless(callee(cxxMethodDecl(hasName("GetProto"))))),
201 changeTo(node(std::string(Flag)), cat("EXPR")));
203 std::string Input = R"cc(
204 proto::ProtoCommandLineFlag flag;
205 int x = flag.foo();
206 int y = flag.GetProto().foo();
207 )cc";
208 std::string Expected = R"cc(
209 proto::ProtoCommandLineFlag flag;
210 int x = EXPR.foo();
211 int y = flag.GetProto().foo();
212 )cc";
214 testRule(std::move(Rule), Input, Expected);
217 TEST_F(TransformerTest, AddIncludeQuoted) {
218 RewriteRule Rule =
219 makeRule(callExpr(callee(functionDecl(hasName("f")))),
220 {addInclude("clang/OtherLib.h"), changeTo(cat("other()"))});
222 std::string Input = R"cc(
223 int f(int x);
224 int h(int x) { return f(x); }
225 )cc";
226 std::string Expected = R"cc(#include "clang/OtherLib.h"
228 int f(int x);
229 int h(int x) { return other(); }
230 )cc";
232 testRule(Rule, Input, Expected);
235 TEST_F(TransformerTest, AddIncludeAngled) {
236 RewriteRule Rule = makeRule(
237 callExpr(callee(functionDecl(hasName("f")))),
238 {addInclude("clang/OtherLib.h", transformer::IncludeFormat::Angled),
239 changeTo(cat("other()"))});
241 std::string Input = R"cc(
242 int f(int x);
243 int h(int x) { return f(x); }
244 )cc";
245 std::string Expected = R"cc(#include <clang/OtherLib.h>
247 int f(int x);
248 int h(int x) { return other(); }
249 )cc";
251 testRule(Rule, Input, Expected);
254 TEST_F(TransformerTest, AddIncludeQuotedForRule) {
255 RewriteRule Rule = makeRule(callExpr(callee(functionDecl(hasName("f")))),
256 changeTo(cat("other()")));
257 addInclude(Rule, "clang/OtherLib.h");
259 std::string Input = R"cc(
260 int f(int x);
261 int h(int x) { return f(x); }
262 )cc";
263 std::string Expected = R"cc(#include "clang/OtherLib.h"
265 int f(int x);
266 int h(int x) { return other(); }
267 )cc";
269 testRule(Rule, Input, Expected);
272 TEST_F(TransformerTest, AddIncludeAngledForRule) {
273 RewriteRule Rule = makeRule(callExpr(callee(functionDecl(hasName("f")))),
274 changeTo(cat("other()")));
275 addInclude(Rule, "clang/OtherLib.h", transformer::IncludeFormat::Angled);
277 std::string Input = R"cc(
278 int f(int x);
279 int h(int x) { return f(x); }
280 )cc";
281 std::string Expected = R"cc(#include <clang/OtherLib.h>
283 int f(int x);
284 int h(int x) { return other(); }
285 )cc";
287 testRule(Rule, Input, Expected);
290 TEST_F(TransformerTest, NodePartNameNamedDecl) {
291 StringRef Fun = "fun";
292 RewriteRule Rule = makeRule(functionDecl(hasName("bad")).bind(Fun),
293 changeTo(name(std::string(Fun)), cat("good")));
295 std::string Input = R"cc(
296 int bad(int x);
297 int bad(int x) { return x * x; }
298 )cc";
299 std::string Expected = R"cc(
300 int good(int x);
301 int good(int x) { return x * x; }
302 )cc";
304 testRule(Rule, Input, Expected);
307 TEST_F(TransformerTest, NodePartNameDeclRef) {
308 std::string Input = R"cc(
309 template <typename T>
310 T bad(T x) {
311 return x;
313 int neutral(int x) { return bad<int>(x) * x; }
314 )cc";
315 std::string Expected = R"cc(
316 template <typename T>
317 T bad(T x) {
318 return x;
320 int neutral(int x) { return good<int>(x) * x; }
321 )cc";
323 StringRef Ref = "ref";
324 testRule(makeRule(declRefExpr(to(functionDecl(hasName("bad")))).bind(Ref),
325 changeTo(name(std::string(Ref)), cat("good"))),
326 Input, Expected);
329 TEST_F(TransformerTest, NodePartNameDeclRefFailure) {
330 std::string Input = R"cc(
331 struct Y {
332 int operator*();
334 int neutral(int x) {
335 Y y;
336 int (Y::*ptr)() = &Y::operator*;
337 return *y + x;
339 )cc";
341 StringRef Ref = "ref";
342 Transformer T(makeRule(declRefExpr(to(functionDecl())).bind(Ref),
343 changeTo(name(std::string(Ref)), cat("good"))),
344 consumer());
345 T.registerMatchers(&MatchFinder);
346 EXPECT_FALSE(rewrite(Input));
349 TEST_F(TransformerTest, NodePartMember) {
350 StringRef E = "expr";
351 RewriteRule Rule =
352 makeRule(memberExpr(clang::ast_matchers::member(hasName("bad"))).bind(E),
353 changeTo(member(std::string(E)), cat("good")));
355 std::string Input = R"cc(
356 struct S {
357 int bad;
359 int g() {
360 S s;
361 return s.bad;
363 )cc";
364 std::string Expected = R"cc(
365 struct S {
366 int bad;
368 int g() {
369 S s;
370 return s.good;
372 )cc";
374 testRule(Rule, Input, Expected);
377 TEST_F(TransformerTest, NodePartMemberQualified) {
378 std::string Input = R"cc(
379 struct S {
380 int bad;
381 int good;
383 struct T : public S {
384 int bad;
386 int g() {
387 T t;
388 return t.S::bad;
390 )cc";
391 std::string Expected = R"cc(
392 struct S {
393 int bad;
394 int good;
396 struct T : public S {
397 int bad;
399 int g() {
400 T t;
401 return t.S::good;
403 )cc";
405 StringRef E = "expr";
406 testRule(makeRule(memberExpr().bind(E),
407 changeTo(member(std::string(E)), cat("good"))),
408 Input, Expected);
411 TEST_F(TransformerTest, NodePartMemberMultiToken) {
412 std::string Input = R"cc(
413 struct Y {
414 int operator*();
415 int good();
416 template <typename T> void foo(T t);
418 int neutral(int x) {
419 Y y;
420 y.template foo<int>(3);
421 return y.operator *();
423 )cc";
424 std::string Expected = R"cc(
425 struct Y {
426 int operator*();
427 int good();
428 template <typename T> void foo(T t);
430 int neutral(int x) {
431 Y y;
432 y.template good<int>(3);
433 return y.good();
435 )cc";
437 StringRef MemExpr = "member";
438 testRule(makeRule(memberExpr().bind(MemExpr),
439 changeTo(member(std::string(MemExpr)), cat("good"))),
440 Input, Expected);
443 TEST_F(TransformerTest, NoEdits) {
444 using transformer::noEdits;
445 std::string Input = "int f(int x) { return x; }";
446 testRule(makeRule(returnStmt().bind("return"), noEdits()), Input, Input);
449 TEST_F(TransformerTest, NoopEdit) {
450 using transformer::node;
451 using transformer::noopEdit;
452 std::string Input = "int f(int x) { return x; }";
453 testRule(makeRule(returnStmt().bind("return"), noopEdit(node("return"))),
454 Input, Input);
457 TEST_F(TransformerTest, IfBound2Args) {
458 using transformer::ifBound;
459 std::string Input = "int f(int x) { return x; }";
460 std::string Expected = "int f(int x) { CHANGE; }";
461 testRule(makeRule(returnStmt().bind("return"),
462 ifBound("return", changeTo(cat("CHANGE;")))),
463 Input, Expected);
466 TEST_F(TransformerTest, IfBound3Args) {
467 using transformer::ifBound;
468 std::string Input = "int f(int x) { return x; }";
469 std::string Expected = "int f(int x) { CHANGE; }";
470 testRule(makeRule(returnStmt().bind("return"),
471 ifBound("nothing", changeTo(cat("ERROR")),
472 changeTo(cat("CHANGE;")))),
473 Input, Expected);
476 TEST_F(TransformerTest, ShrinkTo) {
477 using transformer::shrinkTo;
478 std::string Input = "int f(int x) { return x; }";
479 std::string Expected = "return x;";
480 testRule(makeRule(functionDecl(hasDescendant(returnStmt().bind("return")))
481 .bind("function"),
482 shrinkTo(node("function"), node("return"))),
483 Input, Expected);
486 // Rewrite various Stmts inside a Decl.
487 TEST_F(TransformerTest, RewriteDescendantsDeclChangeStmt) {
488 std::string Input =
489 "int f(int x) { int y = x; { int z = x * x; } return x; }";
490 std::string Expected =
491 "int f(int x) { int y = 3; { int z = 3 * 3; } return 3; }";
492 auto InlineX =
493 makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
494 testRule(makeRule(functionDecl(hasName("f")).bind("fun"),
495 rewriteDescendants("fun", InlineX)),
496 Input, Expected);
499 // Rewrite various TypeLocs inside a Decl.
500 TEST_F(TransformerTest, RewriteDescendantsDeclChangeTypeLoc) {
501 std::string Input = "int f(int *x) { return *x; }";
502 std::string Expected = "char f(char *x) { return *x; }";
503 auto IntToChar = makeRule(typeLoc(loc(qualType(isInteger(), builtinType()))),
504 changeTo(cat("char")));
505 testRule(makeRule(functionDecl(hasName("f")).bind("fun"),
506 rewriteDescendants("fun", IntToChar)),
507 Input, Expected);
510 TEST_F(TransformerTest, RewriteDescendantsStmt) {
511 // Add an unrelated definition to the header that also has a variable named
512 // "x", to test that the rewrite is limited to the scope we intend.
513 appendToHeader(R"cc(int g(int x) { return x; })cc");
514 std::string Input =
515 "int f(int x) { int y = x; { int z = x * x; } return x; }";
516 std::string Expected =
517 "int f(int x) { int y = 3; { int z = 3 * 3; } return 3; }";
518 auto InlineX =
519 makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
520 testRule(makeRule(functionDecl(hasName("f"), hasBody(stmt().bind("body"))),
521 rewriteDescendants("body", InlineX)),
522 Input, Expected);
525 TEST_F(TransformerTest, RewriteDescendantsStmtWithAdditionalChange) {
526 std::string Input =
527 "int f(int x) { int y = x; { int z = x * x; } return x; }";
528 std::string Expected =
529 "int newName(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(
533 makeRule(
534 functionDecl(hasName("f"), hasBody(stmt().bind("body"))).bind("f"),
535 flatten(changeTo(name("f"), cat("newName")),
536 rewriteDescendants("body", InlineX))),
537 Input, Expected);
540 TEST_F(TransformerTest, RewriteDescendantsTypeLoc) {
541 std::string Input = "int f(int *x) { return *x; }";
542 std::string Expected = "int f(char *x) { return *x; }";
543 auto IntToChar =
544 makeRule(typeLoc(loc(qualType(isInteger(), builtinType()))).bind("loc"),
545 changeTo(cat("char")));
546 testRule(
547 makeRule(functionDecl(hasName("f"),
548 hasParameter(0, varDecl(hasTypeLoc(
549 typeLoc().bind("parmType"))))),
550 rewriteDescendants("parmType", IntToChar)),
551 Input, Expected);
554 TEST_F(TransformerTest, RewriteDescendantsReferToParentBinding) {
555 std::string Input =
556 "int f(int p) { int y = p; { int z = p * p; } return p; }";
557 std::string Expected =
558 "int f(int p) { int y = 3; { int z = 3 * 3; } return 3; }";
559 std::string VarId = "var";
560 auto InlineVar = makeRule(declRefExpr(to(varDecl(equalsBoundNode(VarId)))),
561 changeTo(cat("3")));
562 testRule(makeRule(functionDecl(hasName("f"),
563 hasParameter(0, varDecl().bind(VarId)))
564 .bind("fun"),
565 rewriteDescendants("fun", InlineVar)),
566 Input, Expected);
569 TEST_F(TransformerTest, RewriteDescendantsUnboundNode) {
570 std::string Input =
571 "int f(int x) { int y = x; { int z = x * x; } return x; }";
572 auto InlineX =
573 makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
574 Transformer T(makeRule(functionDecl(hasName("f")),
575 rewriteDescendants("UNBOUND", InlineX)),
576 consumer());
577 T.registerMatchers(&MatchFinder);
578 EXPECT_FALSE(rewrite(Input));
579 EXPECT_THAT(Changes, IsEmpty());
580 EXPECT_EQ(ErrorCount, 1);
583 TEST_F(TransformerTest, RewriteDescendantsInvalidNodeType) {
584 std::string Input =
585 "int f(int x) { int y = x; { int z = x * x; } return x; }";
586 auto IntToChar =
587 makeRule(qualType(isInteger(), builtinType()), changeTo(cat("char")));
588 Transformer T(
589 makeRule(functionDecl(
590 hasName("f"),
591 hasParameter(0, varDecl(hasType(qualType().bind("type"))))),
592 rewriteDescendants("type", IntToChar)),
593 consumer());
594 T.registerMatchers(&MatchFinder);
595 EXPECT_FALSE(rewrite(Input));
596 EXPECT_THAT(Changes, IsEmpty());
597 EXPECT_EQ(ErrorCount, 1);
601 // We include one test per typed overload. We don't test extensively since that
602 // is already covered by the tests above.
605 TEST_F(TransformerTest, RewriteDescendantsTypedStmt) {
606 // Add an unrelated definition to the header that also has a variable named
607 // "x", to test that the rewrite is limited to the scope we intend.
608 appendToHeader(R"cc(int g(int x) { return x; })cc");
609 std::string Input =
610 "int f(int x) { int y = x; { int z = x * x; } return x; }";
611 std::string Expected =
612 "int f(int x) { int y = 3; { int z = 3 * 3; } return 3; }";
613 auto InlineX =
614 makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
615 testRule(makeRule(functionDecl(hasName("f"), hasBody(stmt().bind("body"))),
616 [&InlineX](const MatchFinder::MatchResult &R) {
617 const auto *Node = R.Nodes.getNodeAs<Stmt>("body");
618 assert(Node != nullptr && "body must be bound");
619 return transformer::detail::rewriteDescendants(
620 *Node, InlineX, R);
622 Input, Expected);
625 TEST_F(TransformerTest, RewriteDescendantsTypedDecl) {
626 std::string Input =
627 "int f(int x) { int y = x; { int z = x * x; } return x; }";
628 std::string Expected =
629 "int f(int x) { int y = 3; { int z = 3 * 3; } return 3; }";
630 auto InlineX =
631 makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
632 testRule(makeRule(functionDecl(hasName("f")).bind("fun"),
633 [&InlineX](const MatchFinder::MatchResult &R) {
634 const auto *Node = R.Nodes.getNodeAs<Decl>("fun");
635 assert(Node != nullptr && "fun must be bound");
636 return transformer::detail::rewriteDescendants(
637 *Node, InlineX, R);
639 Input, Expected);
642 TEST_F(TransformerTest, RewriteDescendantsTypedTypeLoc) {
643 std::string Input = "int f(int *x) { return *x; }";
644 std::string Expected = "int f(char *x) { return *x; }";
645 auto IntToChar =
646 makeRule(typeLoc(loc(qualType(isInteger(), builtinType()))).bind("loc"),
647 changeTo(cat("char")));
648 testRule(
649 makeRule(
650 functionDecl(
651 hasName("f"),
652 hasParameter(0, varDecl(hasTypeLoc(typeLoc().bind("parmType"))))),
653 [&IntToChar](const MatchFinder::MatchResult &R) {
654 const auto *Node = R.Nodes.getNodeAs<TypeLoc>("parmType");
655 assert(Node != nullptr && "parmType must be bound");
656 return transformer::detail::rewriteDescendants(*Node, IntToChar, R);
658 Input, Expected);
661 TEST_F(TransformerTest, RewriteDescendantsTypedDynTyped) {
662 // Add an unrelated definition to the header that also has a variable named
663 // "x", to test that the rewrite is limited to the scope we intend.
664 appendToHeader(R"cc(int g(int x) { return x; })cc");
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(
672 makeRule(functionDecl(hasName("f"), hasBody(stmt().bind("body"))),
673 [&InlineX](const MatchFinder::MatchResult &R) {
674 auto It = R.Nodes.getMap().find("body");
675 assert(It != R.Nodes.getMap().end() && "body must be bound");
676 return transformer::detail::rewriteDescendants(It->second,
677 InlineX, R);
679 Input, Expected);
682 TEST_F(TransformerTest, InsertBeforeEdit) {
683 std::string Input = R"cc(
684 int f() {
685 return 7;
687 )cc";
688 std::string Expected = R"cc(
689 int f() {
690 int y = 3;
691 return 7;
693 )cc";
695 StringRef Ret = "return";
696 testRule(
697 makeRule(returnStmt().bind(Ret),
698 insertBefore(statement(std::string(Ret)), cat("int y = 3;"))),
699 Input, Expected);
702 TEST_F(TransformerTest, InsertAfterEdit) {
703 std::string Input = R"cc(
704 int f() {
705 int x = 5;
706 return 7;
708 )cc";
709 std::string Expected = R"cc(
710 int f() {
711 int x = 5;
712 int y = 3;
713 return 7;
715 )cc";
717 StringRef Decl = "decl";
718 testRule(
719 makeRule(declStmt().bind(Decl),
720 insertAfter(statement(std::string(Decl)), cat("int y = 3;"))),
721 Input, Expected);
724 TEST_F(TransformerTest, RemoveEdit) {
725 std::string Input = R"cc(
726 int f() {
727 int x = 5;
728 return 7;
730 )cc";
731 std::string Expected = R"cc(
732 int f() {
733 return 7;
735 )cc";
737 StringRef Decl = "decl";
738 testRule(
739 makeRule(declStmt().bind(Decl), remove(statement(std::string(Decl)))),
740 Input, Expected);
743 TEST_F(TransformerTest, WithMetadata) {
744 auto makeMetadata = [](const MatchFinder::MatchResult &R) -> llvm::Any {
745 int N =
746 R.Nodes.getNodeAs<IntegerLiteral>("int")->getValue().getLimitedValue();
747 return N;
750 std::string Input = R"cc(
751 int f() {
752 int x = 5;
753 return 7;
755 )cc";
757 Transformer T(
758 makeRule(
759 declStmt(containsDeclaration(0, varDecl(hasInitializer(
760 integerLiteral().bind("int")))))
761 .bind("decl"),
762 withMetadata(remove(statement(std::string("decl"))), makeMetadata)),
763 consumer());
764 T.registerMatchers(&MatchFinder);
765 auto Factory = newFrontendActionFactory(&MatchFinder);
766 EXPECT_TRUE(runToolOnCodeWithArgs(
767 Factory->create(), Input, std::vector<std::string>(), "input.cc",
768 "clang-tool", std::make_shared<PCHContainerOperations>(), {}));
769 ASSERT_EQ(Changes.size(), 1u);
770 const llvm::Any &Metadata = Changes[0].getMetadata();
771 ASSERT_TRUE(llvm::any_isa<int>(Metadata));
772 EXPECT_THAT(llvm::any_cast<int>(Metadata), 5);
775 TEST_F(TransformerTest, MultiChange) {
776 std::string Input = R"cc(
777 void foo() {
778 if (10 > 1.0)
779 log(1) << "oh no!";
780 else
781 log(0) << "ok";
783 )cc";
784 std::string Expected = R"(
785 void foo() {
786 if (true) { /* then */ }
787 else { /* else */ }
791 StringRef C = "C", T = "T", E = "E";
792 testRule(
793 makeRule(ifStmt(hasCondition(expr().bind(C)), hasThen(stmt().bind(T)),
794 hasElse(stmt().bind(E))),
795 {changeTo(node(std::string(C)), cat("true")),
796 changeTo(statement(std::string(T)), cat("{ /* then */ }")),
797 changeTo(statement(std::string(E)), cat("{ /* else */ }"))}),
798 Input, Expected);
801 TEST_F(TransformerTest, EditList) {
802 using clang::transformer::editList;
803 std::string Input = R"cc(
804 void foo() {
805 if (10 > 1.0)
806 log(1) << "oh no!";
807 else
808 log(0) << "ok";
810 )cc";
811 std::string Expected = R"(
812 void foo() {
813 if (true) { /* then */ }
814 else { /* else */ }
818 StringRef C = "C", T = "T", E = "E";
819 testRule(makeRule(ifStmt(hasCondition(expr().bind(C)),
820 hasThen(stmt().bind(T)), hasElse(stmt().bind(E))),
821 editList({changeTo(node(std::string(C)), cat("true")),
822 changeTo(statement(std::string(T)),
823 cat("{ /* then */ }")),
824 changeTo(statement(std::string(E)),
825 cat("{ /* else */ }"))})),
826 Input, Expected);
829 TEST_F(TransformerTest, Flatten) {
830 using clang::transformer::editList;
831 std::string Input = R"cc(
832 void foo() {
833 if (10 > 1.0)
834 log(1) << "oh no!";
835 else
836 log(0) << "ok";
838 )cc";
839 std::string Expected = R"(
840 void foo() {
841 if (true) { /* then */ }
842 else { /* else */ }
846 StringRef C = "C", T = "T", E = "E";
847 testRule(
848 makeRule(
849 ifStmt(hasCondition(expr().bind(C)), hasThen(stmt().bind(T)),
850 hasElse(stmt().bind(E))),
851 flatten(changeTo(node(std::string(C)), cat("true")),
852 changeTo(statement(std::string(T)), cat("{ /* then */ }")),
853 changeTo(statement(std::string(E)), cat("{ /* else */ }")))),
854 Input, Expected);
857 TEST_F(TransformerTest, FlattenWithMixedArgs) {
858 using clang::transformer::editList;
859 std::string Input = R"cc(
860 void foo() {
861 if (10 > 1.0)
862 log(1) << "oh no!";
863 else
864 log(0) << "ok";
866 )cc";
867 std::string Expected = R"(
868 void foo() {
869 if (true) { /* then */ }
870 else { /* else */ }
874 StringRef C = "C", T = "T", E = "E";
875 testRule(makeRule(ifStmt(hasCondition(expr().bind(C)),
876 hasThen(stmt().bind(T)), hasElse(stmt().bind(E))),
877 flatten(changeTo(node(std::string(C)), cat("true")),
878 edit(changeTo(statement(std::string(T)),
879 cat("{ /* then */ }"))),
880 editList({changeTo(statement(std::string(E)),
881 cat("{ /* else */ }"))}))),
882 Input, Expected);
885 TEST_F(TransformerTest, OrderedRuleUnrelated) {
886 StringRef Flag = "flag";
887 RewriteRule FlagRule = makeRule(
888 cxxMemberCallExpr(on(expr(hasType(cxxRecordDecl(
889 hasName("proto::ProtoCommandLineFlag"))))
890 .bind(Flag)),
891 unless(callee(cxxMethodDecl(hasName("GetProto"))))),
892 changeTo(node(std::string(Flag)), cat("PROTO")));
894 std::string Input = R"cc(
895 proto::ProtoCommandLineFlag flag;
896 int x = flag.foo();
897 int y = flag.GetProto().foo();
898 int f(string s) { return strlen(s.c_str()); }
899 )cc";
900 std::string Expected = R"cc(
901 proto::ProtoCommandLineFlag flag;
902 int x = PROTO.foo();
903 int y = flag.GetProto().foo();
904 int f(string s) { return REPLACED; }
905 )cc";
907 testRule(applyFirst({ruleStrlenSize(), FlagRule}), Input, Expected);
910 TEST_F(TransformerTest, OrderedRuleRelated) {
911 std::string Input = R"cc(
912 void f1();
913 void f2();
914 void call_f1() { f1(); }
915 void call_f2() { f2(); }
916 )cc";
917 std::string Expected = R"cc(
918 void f1();
919 void f2();
920 void call_f1() { REPLACE_F1; }
921 void call_f2() { REPLACE_F1_OR_F2; }
922 )cc";
924 RewriteRule ReplaceF1 =
925 makeRule(callExpr(callee(functionDecl(hasName("f1")))),
926 changeTo(cat("REPLACE_F1")));
927 RewriteRule ReplaceF1OrF2 =
928 makeRule(callExpr(callee(functionDecl(hasAnyName("f1", "f2")))),
929 changeTo(cat("REPLACE_F1_OR_F2")));
930 testRule(applyFirst({ReplaceF1, ReplaceF1OrF2}), Input, Expected);
933 // Change the order of the rules to get a different result. When `ReplaceF1OrF2`
934 // comes first, it applies for both uses, so `ReplaceF1` never applies.
935 TEST_F(TransformerTest, OrderedRuleRelatedSwapped) {
936 std::string Input = R"cc(
937 void f1();
938 void f2();
939 void call_f1() { f1(); }
940 void call_f2() { f2(); }
941 )cc";
942 std::string Expected = R"cc(
943 void f1();
944 void f2();
945 void call_f1() { REPLACE_F1_OR_F2; }
946 void call_f2() { REPLACE_F1_OR_F2; }
947 )cc";
949 RewriteRule ReplaceF1 =
950 makeRule(callExpr(callee(functionDecl(hasName("f1")))),
951 changeTo(cat("REPLACE_F1")));
952 RewriteRule ReplaceF1OrF2 =
953 makeRule(callExpr(callee(functionDecl(hasAnyName("f1", "f2")))),
954 changeTo(cat("REPLACE_F1_OR_F2")));
955 testRule(applyFirst({ReplaceF1OrF2, ReplaceF1}), Input, Expected);
958 // Verify that a set of rules whose matchers have different base kinds works
959 // properly, including that `applyFirst` produces multiple matchers. We test
960 // two different kinds of rules: Expr and Decl. We place the Decl rule in the
961 // middle to test that `buildMatchers` works even when the kinds aren't grouped
962 // together.
963 TEST_F(TransformerTest, OrderedRuleMultipleKinds) {
964 std::string Input = R"cc(
965 void f1();
966 void f2();
967 void call_f1() { f1(); }
968 void call_f2() { f2(); }
969 )cc";
970 std::string Expected = R"cc(
971 void f1();
972 void DECL_RULE();
973 void call_f1() { REPLACE_F1; }
974 void call_f2() { REPLACE_F1_OR_F2; }
975 )cc";
977 RewriteRule ReplaceF1 =
978 makeRule(callExpr(callee(functionDecl(hasName("f1")))),
979 changeTo(cat("REPLACE_F1")));
980 RewriteRule ReplaceF1OrF2 =
981 makeRule(callExpr(callee(functionDecl(hasAnyName("f1", "f2")))),
982 changeTo(cat("REPLACE_F1_OR_F2")));
983 RewriteRule DeclRule = makeRule(functionDecl(hasName("f2")).bind("fun"),
984 changeTo(name("fun"), cat("DECL_RULE")));
986 RewriteRule Rule = applyFirst({ReplaceF1, DeclRule, ReplaceF1OrF2});
987 EXPECT_EQ(transformer::detail::buildMatchers(Rule).size(), 2UL);
988 testRule(Rule, Input, Expected);
991 // Verifies that a rule with a top-level matcher for an implicit node (like
992 // `implicitCastExpr`) works correctly -- the implicit nodes are not skipped.
993 TEST_F(TransformerTest, OrderedRuleImplicitMatched) {
994 std::string Input = R"cc(
995 void f1();
996 int f2();
997 void call_f1() { f1(); }
998 float call_f2() { return f2(); }
999 )cc";
1000 std::string Expected = R"cc(
1001 void f1();
1002 int f2();
1003 void call_f1() { REPLACE_F1; }
1004 float call_f2() { return REPLACE_F2; }
1005 )cc";
1007 RewriteRule ReplaceF1 =
1008 makeRule(callExpr(callee(functionDecl(hasName("f1")))),
1009 changeTo(cat("REPLACE_F1")));
1010 RewriteRule ReplaceF2 =
1011 makeRule(implicitCastExpr(hasSourceExpression(callExpr())),
1012 changeTo(cat("REPLACE_F2")));
1013 testRule(applyFirst({ReplaceF1, ReplaceF2}), Input, Expected);
1017 // Negative tests (where we expect no transformation to occur).
1020 // Tests for a conflict in edits from a single match for a rule.
1021 TEST_F(TransformerTest, TextGeneratorFailure) {
1022 std::string Input = "int conflictOneRule() { return 3 + 7; }";
1023 // Try to change the whole binary-operator expression AND one its operands:
1024 StringRef O = "O";
1025 class AlwaysFail : public transformer::MatchComputation<std::string> {
1026 llvm::Error eval(const ast_matchers::MatchFinder::MatchResult &,
1027 std::string *) const override {
1028 return llvm::createStringError(llvm::errc::invalid_argument, "ERROR");
1030 std::string toString() const override { return "AlwaysFail"; }
1032 Transformer T(
1033 makeRule(binaryOperator().bind(O),
1034 changeTo(node(std::string(O)), std::make_shared<AlwaysFail>())),
1035 consumer());
1036 T.registerMatchers(&MatchFinder);
1037 EXPECT_FALSE(rewrite(Input));
1038 EXPECT_THAT(Changes, IsEmpty());
1039 EXPECT_EQ(ErrorCount, 1);
1042 // Tests for a conflict in edits from a single match for a rule.
1043 TEST_F(TransformerTest, OverlappingEditsInRule) {
1044 std::string Input = "int conflictOneRule() { return 3 + 7; }";
1045 // Try to change the whole binary-operator expression AND one its operands:
1046 StringRef O = "O", L = "L";
1047 Transformer T(makeRule(binaryOperator(hasLHS(expr().bind(L))).bind(O),
1048 {changeTo(node(std::string(O)), cat("DELETE_OP")),
1049 changeTo(node(std::string(L)), cat("DELETE_LHS"))}),
1050 consumer());
1051 T.registerMatchers(&MatchFinder);
1052 EXPECT_FALSE(rewrite(Input));
1053 EXPECT_THAT(Changes, IsEmpty());
1054 EXPECT_EQ(ErrorCount, 1);
1057 // Tests for a conflict in edits across multiple matches (of the same rule).
1058 TEST_F(TransformerTest, OverlappingEditsMultipleMatches) {
1059 std::string Input = "int conflictOneRule() { return -7; }";
1060 // Try to change the whole binary-operator expression AND one its operands:
1061 StringRef E = "E";
1062 Transformer T(makeRule(expr().bind(E),
1063 changeTo(node(std::string(E)), cat("DELETE_EXPR"))),
1064 consumer());
1065 T.registerMatchers(&MatchFinder);
1066 // The rewrite process fails because the changes conflict with each other...
1067 EXPECT_FALSE(rewrite(Input));
1068 // ... but two changes were produced.
1069 EXPECT_EQ(Changes.size(), 2u);
1070 EXPECT_EQ(ErrorCount, 0);
1073 TEST_F(TransformerTest, ErrorOccurredMatchSkipped) {
1074 // Syntax error in the function body:
1075 std::string Input = "void errorOccurred() { 3 }";
1076 Transformer T(makeRule(functionDecl(hasName("errorOccurred")),
1077 changeTo(cat("DELETED;"))),
1078 consumer());
1079 T.registerMatchers(&MatchFinder);
1080 // The rewrite process itself fails...
1081 EXPECT_FALSE(rewrite(Input));
1082 // ... and no changes or errors are produced in the process.
1083 EXPECT_THAT(Changes, IsEmpty());
1084 EXPECT_EQ(ErrorCount, 0);
1087 TEST_F(TransformerTest, ImplicitNodes_ConstructorDecl) {
1089 std::string OtherStructPrefix = R"cpp(
1090 struct Other {
1091 )cpp";
1092 std::string OtherStructSuffix = "};";
1094 std::string CopyableStructName = "struct Copyable";
1095 std::string BrokenStructName = "struct explicit Copyable";
1097 std::string CodeSuffix = R"cpp(
1099 Other m_i;
1100 Copyable();
1102 )cpp";
1104 std::string CopyCtor = "Other(const Other&) = default;";
1105 std::string ExplicitCopyCtor = "explicit Other(const Other&) = default;";
1106 std::string BrokenExplicitCopyCtor =
1107 "explicit explicit explicit Other(const Other&) = default;";
1109 std::string RewriteInput = OtherStructPrefix + CopyCtor + OtherStructSuffix +
1110 CopyableStructName + CodeSuffix;
1111 std::string ExpectedRewriteOutput = OtherStructPrefix + ExplicitCopyCtor +
1112 OtherStructSuffix + CopyableStructName +
1113 CodeSuffix;
1114 std::string BrokenRewriteOutput = OtherStructPrefix + BrokenExplicitCopyCtor +
1115 OtherStructSuffix + BrokenStructName +
1116 CodeSuffix;
1118 auto MatchedRecord =
1119 cxxConstructorDecl(isCopyConstructor()).bind("copyConstructor");
1121 auto RewriteRule =
1122 changeTo(before(node("copyConstructor")), cat("explicit "));
1124 testRule(makeRule(traverse(TK_IgnoreUnlessSpelledInSource, MatchedRecord),
1125 RewriteRule),
1126 RewriteInput, ExpectedRewriteOutput);
1128 testRule(makeRule(traverse(TK_AsIs, MatchedRecord), RewriteRule),
1129 RewriteInput, BrokenRewriteOutput);
1132 TEST_F(TransformerTest, ImplicitNodes_RangeFor) {
1134 std::string CodePrefix = R"cpp(
1135 struct Container
1137 int* begin() const;
1138 int* end() const;
1139 int* cbegin() const;
1140 int* cend() const;
1143 void foo()
1145 const Container c;
1146 )cpp";
1148 std::string BeginCallBefore = " c.begin();";
1149 std::string BeginCallAfter = " c.cbegin();";
1151 std::string ForLoop = "for (auto i : c)";
1152 std::string BrokenForLoop = "for (auto i :.cbegin() c)";
1154 std::string CodeSuffix = R"cpp(
1158 )cpp";
1160 std::string RewriteInput =
1161 CodePrefix + BeginCallBefore + ForLoop + CodeSuffix;
1162 std::string ExpectedRewriteOutput =
1163 CodePrefix + BeginCallAfter + ForLoop + CodeSuffix;
1164 std::string BrokenRewriteOutput =
1165 CodePrefix + BeginCallAfter + BrokenForLoop + CodeSuffix;
1167 auto MatchedRecord =
1168 cxxMemberCallExpr(on(expr(hasType(qualType(isConstQualified(),
1169 hasDeclaration(cxxRecordDecl(
1170 hasName("Container"))))))
1171 .bind("callTarget")),
1172 callee(cxxMethodDecl(hasName("begin"))))
1173 .bind("constBeginCall");
1175 auto RewriteRule =
1176 changeTo(node("constBeginCall"), cat(name("callTarget"), ".cbegin()"));
1178 testRule(makeRule(traverse(TK_IgnoreUnlessSpelledInSource, MatchedRecord),
1179 RewriteRule),
1180 RewriteInput, ExpectedRewriteOutput);
1182 testRule(makeRule(traverse(TK_AsIs, MatchedRecord), RewriteRule),
1183 RewriteInput, BrokenRewriteOutput);
1186 TEST_F(TransformerTest, ImplicitNodes_ForStmt) {
1188 std::string CodePrefix = R"cpp(
1189 struct NonTrivial {
1190 NonTrivial() {}
1191 NonTrivial(NonTrivial&) {}
1192 NonTrivial& operator=(NonTrivial const&) { return *this; }
1194 ~NonTrivial() {}
1197 struct ContainsArray {
1198 NonTrivial arr[2];
1199 ContainsArray& operator=(ContainsArray const&) = default;
1202 void testIt()
1204 ContainsArray ca1;
1205 ContainsArray ca2;
1206 ca2 = ca1;
1207 )cpp";
1209 auto CodeSuffix = "}";
1211 auto LoopBody = R"cpp(
1215 )cpp";
1217 auto RawLoop = "for (auto i = 0; i != 5; ++i)";
1219 auto RangeLoop = "for (auto i : boost::irange(5))";
1221 // Expect to rewrite the raw loop to the ranged loop.
1222 // This works in TK_IgnoreUnlessSpelledInSource mode, but TK_AsIs
1223 // mode also matches the hidden for loop generated in the copy assignment
1224 // operator of ContainsArray. Transformer then fails to transform the code at
1225 // all.
1227 auto RewriteInput =
1228 CodePrefix + RawLoop + LoopBody + RawLoop + LoopBody + CodeSuffix;
1230 auto RewriteOutput =
1231 CodePrefix + RangeLoop + LoopBody + RangeLoop + LoopBody + CodeSuffix;
1233 auto MatchedLoop = forStmt(
1234 has(declStmt(
1235 hasSingleDecl(varDecl(hasInitializer(integerLiteral(equals(0))))
1236 .bind("loopVar")))),
1237 has(binaryOperator(hasOperatorName("!="),
1238 hasLHS(ignoringImplicit(declRefExpr(
1239 to(varDecl(equalsBoundNode("loopVar")))))),
1240 hasRHS(expr().bind("upperBoundExpr")))),
1241 has(unaryOperator(hasOperatorName("++"),
1242 hasUnaryOperand(declRefExpr(
1243 to(varDecl(equalsBoundNode("loopVar"))))))
1244 .bind("incrementOp")));
1246 auto RewriteRule =
1247 changeTo(transformer::enclose(node("loopVar"), node("incrementOp")),
1248 cat("auto ", name("loopVar"), " : boost::irange(",
1249 node("upperBoundExpr"), ")"));
1251 testRule(makeRule(traverse(TK_IgnoreUnlessSpelledInSource, MatchedLoop),
1252 RewriteRule),
1253 RewriteInput, RewriteOutput);
1255 testRuleFailure(makeRule(traverse(TK_AsIs, MatchedLoop), RewriteRule),
1256 RewriteInput);
1260 TEST_F(TransformerTest, ImplicitNodes_ForStmt2) {
1262 std::string CodePrefix = R"cpp(
1263 struct NonTrivial {
1264 NonTrivial() {}
1265 NonTrivial(NonTrivial&) {}
1266 NonTrivial& operator=(NonTrivial const&) { return *this; }
1268 ~NonTrivial() {}
1271 struct ContainsArray {
1272 NonTrivial arr[2];
1273 ContainsArray& operator=(ContainsArray const&) = default;
1276 void testIt()
1278 ContainsArray ca1;
1279 ContainsArray ca2;
1280 ca2 = ca1;
1281 )cpp";
1283 auto CodeSuffix = "}";
1285 auto LoopBody = R"cpp(
1289 )cpp";
1291 auto RawLoop = "for (auto i = 0; i != 5; ++i)";
1293 auto RangeLoop = "for (auto i : boost::irange(5))";
1295 // Expect to rewrite the raw loop to the ranged loop.
1296 // This works in TK_IgnoreUnlessSpelledInSource mode, but TK_AsIs
1297 // mode also matches the hidden for loop generated in the copy assignment
1298 // operator of ContainsArray. Transformer then fails to transform the code at
1299 // all.
1301 auto RewriteInput =
1302 CodePrefix + RawLoop + LoopBody + RawLoop + LoopBody + CodeSuffix;
1304 auto RewriteOutput =
1305 CodePrefix + RangeLoop + LoopBody + RangeLoop + LoopBody + CodeSuffix;
1306 auto MatchedLoop = forStmt(
1307 hasLoopInit(declStmt(
1308 hasSingleDecl(varDecl(hasInitializer(integerLiteral(equals(0))))
1309 .bind("loopVar")))),
1310 hasCondition(binaryOperator(hasOperatorName("!="),
1311 hasLHS(ignoringImplicit(declRefExpr(to(
1312 varDecl(equalsBoundNode("loopVar")))))),
1313 hasRHS(expr().bind("upperBoundExpr")))),
1314 hasIncrement(unaryOperator(hasOperatorName("++"),
1315 hasUnaryOperand(declRefExpr(to(
1316 varDecl(equalsBoundNode("loopVar"))))))
1317 .bind("incrementOp")));
1319 auto RewriteRule =
1320 changeTo(transformer::enclose(node("loopVar"), node("incrementOp")),
1321 cat("auto ", name("loopVar"), " : boost::irange(",
1322 node("upperBoundExpr"), ")"));
1324 testRule(makeRule(traverse(TK_IgnoreUnlessSpelledInSource, MatchedLoop),
1325 RewriteRule),
1326 RewriteInput, RewriteOutput);
1328 testRuleFailure(makeRule(traverse(TK_AsIs, MatchedLoop), RewriteRule),
1329 RewriteInput);
1333 TEST_F(TransformerTest, TemplateInstantiation) {
1335 std::string NonTemplatesInput = R"cpp(
1336 struct S {
1337 int m_i;
1339 )cpp";
1340 std::string NonTemplatesExpected = R"cpp(
1341 struct S {
1342 safe_int m_i;
1344 )cpp";
1346 std::string TemplatesInput = R"cpp(
1347 template<typename T>
1348 struct TemplStruct {
1349 TemplStruct() {}
1350 ~TemplStruct() {}
1352 private:
1353 T m_t;
1356 void instantiate()
1358 TemplStruct<int> ti;
1360 )cpp";
1362 auto MatchedField = fieldDecl(hasType(asString("int"))).bind("theField");
1364 // Changes the 'int' in 'S', but not the 'T' in 'TemplStruct':
1365 testRule(makeRule(traverse(TK_IgnoreUnlessSpelledInSource, MatchedField),
1366 changeTo(cat("safe_int ", name("theField"), ";"))),
1367 NonTemplatesInput + TemplatesInput,
1368 NonTemplatesExpected + TemplatesInput);
1370 // In AsIs mode, template instantiations are modified, which is
1371 // often not desired:
1373 std::string IncorrectTemplatesExpected = R"cpp(
1374 template<typename T>
1375 struct TemplStruct {
1376 TemplStruct() {}
1377 ~TemplStruct() {}
1379 private:
1380 safe_int m_t;
1383 void instantiate()
1385 TemplStruct<int> ti;
1387 )cpp";
1389 // Changes the 'int' in 'S', and (incorrectly) the 'T' in 'TemplStruct':
1390 testRule(makeRule(traverse(TK_AsIs, MatchedField),
1391 changeTo(cat("safe_int ", name("theField"), ";"))),
1393 NonTemplatesInput + TemplatesInput,
1394 NonTemplatesExpected + IncorrectTemplatesExpected);
1397 // Transformation of macro source text when the change encompasses the entirety
1398 // of the expanded text.
1399 TEST_F(TransformerTest, SimpleMacro) {
1400 std::string Input = R"cc(
1401 #define ZERO 0
1402 int f(string s) { return ZERO; }
1403 )cc";
1404 std::string Expected = R"cc(
1405 #define ZERO 0
1406 int f(string s) { return 999; }
1407 )cc";
1409 StringRef zero = "zero";
1410 RewriteRule R = makeRule(integerLiteral(equals(0)).bind(zero),
1411 changeTo(node(std::string(zero)), cat("999")));
1412 testRule(R, Input, Expected);
1415 // Transformation of macro source text when the change encompasses the entirety
1416 // of the expanded text, for the case of function-style macros.
1417 TEST_F(TransformerTest, FunctionMacro) {
1418 std::string Input = R"cc(
1419 #define MACRO(str) strlen((str).c_str())
1420 int f(string s) { return MACRO(s); }
1421 )cc";
1422 std::string Expected = R"cc(
1423 #define MACRO(str) strlen((str).c_str())
1424 int f(string s) { return REPLACED; }
1425 )cc";
1427 testRule(ruleStrlenSize(), Input, Expected);
1430 // Tests that expressions in macro arguments can be rewritten.
1431 TEST_F(TransformerTest, MacroArg) {
1432 std::string Input = R"cc(
1433 #define PLUS(e) e + 1
1434 int f(string s) { return PLUS(strlen(s.c_str())); }
1435 )cc";
1436 std::string Expected = R"cc(
1437 #define PLUS(e) e + 1
1438 int f(string s) { return PLUS(REPLACED); }
1439 )cc";
1441 testRule(ruleStrlenSize(), Input, Expected);
1444 // Tests that expressions in macro arguments can be rewritten, even when the
1445 // macro call occurs inside another macro's definition.
1446 TEST_F(TransformerTest, MacroArgInMacroDef) {
1447 std::string Input = R"cc(
1448 #define NESTED(e) e
1449 #define MACRO(str) NESTED(strlen((str).c_str()))
1450 int f(string s) { return MACRO(s); }
1451 )cc";
1452 std::string Expected = R"cc(
1453 #define NESTED(e) e
1454 #define MACRO(str) NESTED(strlen((str).c_str()))
1455 int f(string s) { return REPLACED; }
1456 )cc";
1458 testRule(ruleStrlenSize(), Input, Expected);
1461 // Tests the corner case of the identity macro, specifically that it is
1462 // discarded in the rewrite rather than preserved (like PLUS is preserved in the
1463 // previous test). This behavior is of dubious value (and marked with a FIXME
1464 // in the code), but we test it to verify (and demonstrate) how this case is
1465 // handled.
1466 TEST_F(TransformerTest, IdentityMacro) {
1467 std::string Input = R"cc(
1468 #define ID(e) e
1469 int f(string s) { return ID(strlen(s.c_str())); }
1470 )cc";
1471 std::string Expected = R"cc(
1472 #define ID(e) e
1473 int f(string s) { return REPLACED; }
1474 )cc";
1476 testRule(ruleStrlenSize(), Input, Expected);
1479 // Tests that two changes in a single macro expansion do not lead to conflicts
1480 // in applying the changes.
1481 TEST_F(TransformerTest, TwoChangesInOneMacroExpansion) {
1482 std::string Input = R"cc(
1483 #define PLUS(a,b) (a) + (b)
1484 int f() { return PLUS(3, 4); }
1485 )cc";
1486 std::string Expected = R"cc(
1487 #define PLUS(a,b) (a) + (b)
1488 int f() { return PLUS(LIT, LIT); }
1489 )cc";
1491 testRule(makeRule(integerLiteral(), changeTo(cat("LIT"))), Input, Expected);
1494 // Tests case where the rule's match spans both source from the macro and its
1495 // arg, with the begin location (the "anchor") being the arg.
1496 TEST_F(TransformerTest, MatchSpansMacroTextButChangeDoesNot) {
1497 std::string Input = R"cc(
1498 #define PLUS_ONE(a) a + 1
1499 int f() { return PLUS_ONE(3); }
1500 )cc";
1501 std::string Expected = R"cc(
1502 #define PLUS_ONE(a) a + 1
1503 int f() { return PLUS_ONE(LIT); }
1504 )cc";
1506 StringRef E = "expr";
1507 testRule(makeRule(binaryOperator(hasLHS(expr().bind(E))),
1508 changeTo(node(std::string(E)), cat("LIT"))),
1509 Input, Expected);
1512 // Tests case where the rule's match spans both source from the macro and its
1513 // arg, with the begin location (the "anchor") being inside the macro.
1514 TEST_F(TransformerTest, MatchSpansMacroTextButChangeDoesNotAnchoredInMacro) {
1515 std::string Input = R"cc(
1516 #define PLUS_ONE(a) 1 + a
1517 int f() { return PLUS_ONE(3); }
1518 )cc";
1519 std::string Expected = R"cc(
1520 #define PLUS_ONE(a) 1 + a
1521 int f() { return PLUS_ONE(LIT); }
1522 )cc";
1524 StringRef E = "expr";
1525 testRule(makeRule(binaryOperator(hasRHS(expr().bind(E))),
1526 changeTo(node(std::string(E)), cat("LIT"))),
1527 Input, Expected);
1530 // No rewrite is applied when the changed text does not encompass the entirety
1531 // of the expanded text. That is, the edit would have to be applied to the
1532 // macro's definition to succeed and editing the expansion point would not
1533 // suffice.
1534 TEST_F(TransformerTest, NoPartialRewriteOMacroExpansion) {
1535 std::string Input = R"cc(
1536 #define ZERO_PLUS 0 + 3
1537 int f(string s) { return ZERO_PLUS; })cc";
1539 StringRef zero = "zero";
1540 RewriteRule R = makeRule(integerLiteral(equals(0)).bind(zero),
1541 changeTo(node(std::string(zero)), cat("0")));
1542 testRule(R, Input, Input);
1545 // This test handles the corner case where a macro expands within another macro
1546 // to matching code, but that code is an argument to the nested macro call. A
1547 // simple check of isMacroArgExpansion() vs. isMacroBodyExpansion() will get
1548 // this wrong, and transform the code.
1549 TEST_F(TransformerTest, NoPartialRewriteOfMacroExpansionForMacroArgs) {
1550 std::string Input = R"cc(
1551 #define NESTED(e) e
1552 #define MACRO(str) 1 + NESTED(strlen((str).c_str()))
1553 int f(string s) { return MACRO(s); }
1554 )cc";
1556 testRule(ruleStrlenSize(), Input, Input);
1559 #if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST
1560 // Verifies that `Type` and `QualType` are not allowed as top-level matchers in
1561 // rules.
1562 TEST(TransformerDeathTest, OrderedRuleTypes) {
1563 RewriteRule QualTypeRule = makeRule(qualType(), changeTo(cat("Q")));
1564 EXPECT_DEATH(transformer::detail::buildMatchers(QualTypeRule),
1565 "Matcher must be.*node matcher");
1567 RewriteRule TypeRule = makeRule(arrayType(), changeTo(cat("T")));
1568 EXPECT_DEATH(transformer::detail::buildMatchers(TypeRule),
1569 "Matcher must be.*node matcher");
1571 #endif
1573 // Edits are able to span multiple files; in this case, a header and an
1574 // implementation file.
1575 TEST_F(TransformerTest, MultipleFiles) {
1576 std::string Header = R"cc(void RemoveThisFunction();)cc";
1577 std::string Source = R"cc(#include "input.h"
1578 void RemoveThisFunction();)cc";
1579 Transformer T(
1580 makeRule(functionDecl(hasName("RemoveThisFunction")), changeTo(cat(""))),
1581 consumer());
1582 T.registerMatchers(&MatchFinder);
1583 auto Factory = newFrontendActionFactory(&MatchFinder);
1584 EXPECT_TRUE(runToolOnCodeWithArgs(
1585 Factory->create(), Source, std::vector<std::string>(), "input.cc",
1586 "clang-tool", std::make_shared<PCHContainerOperations>(),
1587 {{"input.h", Header}}));
1589 std::sort(Changes.begin(), Changes.end(),
1590 [](const AtomicChange &L, const AtomicChange &R) {
1591 return L.getFilePath() < R.getFilePath();
1594 ASSERT_EQ(Changes[0].getFilePath(), "./input.h");
1595 EXPECT_THAT(Changes[0].getInsertedHeaders(), IsEmpty());
1596 EXPECT_THAT(Changes[0].getRemovedHeaders(), IsEmpty());
1597 llvm::Expected<std::string> UpdatedCode =
1598 clang::tooling::applyAllReplacements(Header,
1599 Changes[0].getReplacements());
1600 ASSERT_TRUE(static_cast<bool>(UpdatedCode))
1601 << "Could not update code: " << llvm::toString(UpdatedCode.takeError());
1602 EXPECT_EQ(format(*UpdatedCode), "");
1604 ASSERT_EQ(Changes[1].getFilePath(), "input.cc");
1605 EXPECT_THAT(Changes[1].getInsertedHeaders(), IsEmpty());
1606 EXPECT_THAT(Changes[1].getRemovedHeaders(), IsEmpty());
1607 UpdatedCode = clang::tooling::applyAllReplacements(
1608 Source, Changes[1].getReplacements());
1609 ASSERT_TRUE(static_cast<bool>(UpdatedCode))
1610 << "Could not update code: " << llvm::toString(UpdatedCode.takeError());
1611 EXPECT_EQ(format(*UpdatedCode), format("#include \"input.h\"\n"));
1614 TEST_F(TransformerTest, AddIncludeMultipleFiles) {
1615 std::string Header = R"cc(void RemoveThisFunction();)cc";
1616 std::string Source = R"cc(#include "input.h"
1617 void Foo() {RemoveThisFunction();})cc";
1618 Transformer T(
1619 makeRule(callExpr(callee(
1620 functionDecl(hasName("RemoveThisFunction")).bind("fun"))),
1621 addInclude(node("fun"), "header.h")),
1622 consumer());
1623 T.registerMatchers(&MatchFinder);
1624 auto Factory = newFrontendActionFactory(&MatchFinder);
1625 EXPECT_TRUE(runToolOnCodeWithArgs(
1626 Factory->create(), Source, std::vector<std::string>(), "input.cc",
1627 "clang-tool", std::make_shared<PCHContainerOperations>(),
1628 {{"input.h", Header}}));
1630 ASSERT_EQ(Changes.size(), 1U);
1631 ASSERT_EQ(Changes[0].getFilePath(), "./input.h");
1632 EXPECT_THAT(Changes[0].getInsertedHeaders(), ElementsAre("header.h"));
1633 EXPECT_THAT(Changes[0].getRemovedHeaders(), IsEmpty());
1634 llvm::Expected<std::string> UpdatedCode =
1635 clang::tooling::applyAllReplacements(Header,
1636 Changes[0].getReplacements());
1637 ASSERT_TRUE(static_cast<bool>(UpdatedCode))
1638 << "Could not update code: " << llvm::toString(UpdatedCode.takeError());
1639 EXPECT_EQ(format(*UpdatedCode), format(Header));
1641 } // namespace