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