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/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
;
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(
46 int strlen(const char*);
52 struct ProtoCommandLineFlag : PCFProto {
57 void operator<<(Logger& l, string msg);
58 Logger& log(int level);
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
);
72 ADD_FAILURE() << "Could not format code: "
73 << llvm::toString(Formatted
.takeError());
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
{
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
>(),
106 llvm::errs() << "Running tool failed.\n";
109 if (ErrorCount
!= 0) {
110 llvm::errs() << "Generating changes failed.\n";
114 applyAtomicChanges("input.cc", Code
, Changes
, ApplyChangesSpec());
116 llvm::errs() << "Applying changes failed: "
117 << llvm::toString(ChangedCode
.takeError()) << "\n";
123 Transformer::ChangeConsumer
consumer() {
124 return [this](Expected
<AtomicChange
> C
) {
126 Changes
.push_back(std::move(*C
));
128 // FIXME: stash this error rather then printing.
129 llvm::errs() << "Error generating changes: "
130 << llvm::toString(C
.takeError()) << "\n";
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.
156 AtomicChanges Changes
;
159 FileContentMappings FileContents
= {{"header.h", ""}};
162 class TransformerTest
: public ClangRefactoringTestBase
{
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"));
172 callExpr(callee(functionDecl(hasName("strlen"))),
173 hasArgument(0, cxxMemberCallExpr(
174 on(expr(hasType(isOrPointsTo(StringType
)))
176 callee(cxxMethodDecl(hasName("c_str")))))),
177 changeTo(cat("REPLACED")), cat("Use size() method directly on string."));
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"))))
200 unless(callee(cxxMethodDecl(hasName("GetProto"))))),
201 changeTo(node(std::string(Flag
)), cat("EXPR")));
203 std::string Input
= R
"cc(
204 proto::ProtoCommandLineFlag flag;
206 int y = flag.GetProto().foo();
208 std::string Expected
= R
"cc(
209 proto::ProtoCommandLineFlag flag;
211 int y = flag.GetProto().foo();
214 testRule(std::move(Rule
), Input
, Expected
);
217 TEST_F(TransformerTest
, AddIncludeQuoted
) {
219 makeRule(callExpr(callee(functionDecl(hasName("f")))),
220 {addInclude("clang/OtherLib.h"), changeTo(cat("other()"))});
222 std::string Input
= R
"cc(
224 int h(int x) { return f(x); }
226 std::string Expected
= R
"cc(#include "clang
/OtherLib
.h
"
229 int h(int x) { return other(); }
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(
243 int h(int x) { return f(x); }
245 std::string Expected
= R
"cc(#include <clang/OtherLib.h>
248 int h(int x) { return other(); }
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(
261 int h(int x) { return f(x); }
263 std::string Expected
= R
"cc(#include "clang
/OtherLib
.h
"
266 int h(int x) { return other(); }
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(
279 int h(int x) { return f(x); }
281 std::string Expected
= R
"cc(#include <clang/OtherLib.h>
284 int h(int x) { return other(); }
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(
297 int bad(int x) { return x * x; }
299 std::string Expected
= R
"cc(
301 int good(int x) { return x * x; }
304 testRule(Rule
, Input
, Expected
);
307 TEST_F(TransformerTest
, NodePartNameDeclRef
) {
308 std::string Input
= R
"cc(
309 template <typename T>
313 int neutral(int x) { return bad<int>(x) * x; }
315 std::string Expected
= R
"cc(
316 template <typename T>
320 int neutral(int x) { return good<int>(x) * x; }
323 StringRef Ref
= "ref";
324 testRule(makeRule(declRefExpr(to(functionDecl(hasName("bad")))).bind(Ref
),
325 changeTo(name(std::string(Ref
)), cat("good"))),
329 TEST_F(TransformerTest
, NodePartNameDeclRefFailure
) {
330 std::string Input
= R
"cc(
336 int (Y::*ptr)() = &Y::operator*;
341 StringRef Ref
= "ref";
342 Transformer
T(makeRule(declRefExpr(to(functionDecl())).bind(Ref
),
343 changeTo(name(std::string(Ref
)), cat("good"))),
345 T
.registerMatchers(&MatchFinder
);
346 EXPECT_FALSE(rewrite(Input
));
349 TEST_F(TransformerTest
, NodePartMember
) {
350 StringRef E
= "expr";
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(
364 std::string Expected
= R
"cc(
374 testRule(Rule
, Input
, Expected
);
377 TEST_F(TransformerTest
, NodePartMemberQualified
) {
378 std::string Input
= R
"cc(
383 struct T : public S {
391 std::string Expected
= R
"cc(
396 struct T : public S {
405 StringRef E
= "expr";
406 testRule(makeRule(memberExpr().bind(E
),
407 changeTo(member(std::string(E
)), cat("good"))),
411 TEST_F(TransformerTest
, NodePartMemberMultiToken
) {
412 std::string Input
= R
"cc(
416 template <typename T> void foo(T t);
420 y.template foo<int>(3);
421 return y.operator *();
424 std::string Expected
= R
"cc(
428 template <typename T> void foo(T t);
432 y.template good<int>(3);
437 StringRef MemExpr
= "member";
438 testRule(makeRule(memberExpr().bind(MemExpr
),
439 changeTo(member(std::string(MemExpr
)), cat("good"))),
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"))),
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;")))),
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;")))),
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")))
482 shrinkTo(node("function"), node("return"))),
486 // Rewrite various Stmts inside a Decl.
487 TEST_F(TransformerTest
, RewriteDescendantsDeclChangeStmt
) {
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; }";
493 makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
494 testRule(makeRule(functionDecl(hasName("f")).bind("fun"),
495 rewriteDescendants("fun", InlineX
)),
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
)),
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");
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; }";
519 makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
520 testRule(makeRule(functionDecl(hasName("f"), hasBody(stmt().bind("body"))),
521 rewriteDescendants("body", InlineX
)),
525 TEST_F(TransformerTest
, RewriteDescendantsStmtWithAdditionalChange
) {
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; }";
531 makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
534 functionDecl(hasName("f"), hasBody(stmt().bind("body"))).bind("f"),
535 flatten(changeTo(name("f"), cat("newName")),
536 rewriteDescendants("body", InlineX
))),
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; }";
544 makeRule(typeLoc(loc(qualType(isInteger(), builtinType()))).bind("loc"),
545 changeTo(cat("char")));
547 makeRule(functionDecl(hasName("f"),
548 hasParameter(0, varDecl(hasTypeLoc(
549 typeLoc().bind("parmType"))))),
550 rewriteDescendants("parmType", IntToChar
)),
554 TEST_F(TransformerTest
, RewriteDescendantsReferToParentBinding
) {
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
)))),
562 testRule(makeRule(functionDecl(hasName("f"),
563 hasParameter(0, varDecl().bind(VarId
)))
565 rewriteDescendants("fun", InlineVar
)),
569 TEST_F(TransformerTest
, RewriteDescendantsUnboundNode
) {
571 "int f(int x) { int y = x; { int z = x * x; } return x; }";
573 makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
574 Transformer
T(makeRule(functionDecl(hasName("f")),
575 rewriteDescendants("UNBOUND", InlineX
)),
577 T
.registerMatchers(&MatchFinder
);
578 EXPECT_FALSE(rewrite(Input
));
579 EXPECT_THAT(Changes
, IsEmpty());
580 EXPECT_EQ(ErrorCount
, 1);
583 TEST_F(TransformerTest
, RewriteDescendantsInvalidNodeType
) {
585 "int f(int x) { int y = x; { int z = x * x; } return x; }";
587 makeRule(qualType(isInteger(), builtinType()), changeTo(cat("char")));
589 makeRule(functionDecl(
591 hasParameter(0, varDecl(hasType(qualType().bind("type"))))),
592 rewriteDescendants("type", IntToChar
)),
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");
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; }";
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(
625 TEST_F(TransformerTest
, RewriteDescendantsTypedDecl
) {
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; }";
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(
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; }";
646 makeRule(typeLoc(loc(qualType(isInteger(), builtinType()))).bind("loc"),
647 changeTo(cat("char")));
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
);
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");
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; }";
670 makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
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
,
682 TEST_F(TransformerTest
, InsertBeforeEdit
) {
683 std::string Input
= R
"cc(
688 std::string Expected
= R
"cc(
695 StringRef Ret
= "return";
697 makeRule(returnStmt().bind(Ret
),
698 insertBefore(statement(std::string(Ret
)), cat("int y = 3;"))),
702 TEST_F(TransformerTest
, InsertAfterEdit
) {
703 std::string Input
= R
"cc(
709 std::string Expected
= R
"cc(
717 StringRef Decl
= "decl";
719 makeRule(declStmt().bind(Decl
),
720 insertAfter(statement(std::string(Decl
)), cat("int y = 3;"))),
724 TEST_F(TransformerTest
, RemoveEdit
) {
725 std::string Input
= R
"cc(
731 std::string Expected
= R
"cc(
737 StringRef Decl
= "decl";
739 makeRule(declStmt().bind(Decl
), remove(statement(std::string(Decl
)))),
743 TEST_F(TransformerTest
, WithMetadata
) {
744 auto makeMetadata
= [](const MatchFinder::MatchResult
&R
) -> llvm::Any
{
746 R
.Nodes
.getNodeAs
<IntegerLiteral
>("int")->getValue().getLimitedValue();
750 std::string Input
= R
"cc(
759 declStmt(containsDeclaration(0, varDecl(hasInitializer(
760 integerLiteral().bind("int")))))
762 withMetadata(remove(statement(std::string("decl"))), makeMetadata
)),
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(
784 std::string Expected
= R
"(
786 if (true) { /* then */ }
791 StringRef C
= "C", T
= "T", E
= "E";
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 */ }"))}),
801 TEST_F(TransformerTest
, EditList
) {
802 using clang::transformer::editList
;
803 std::string Input
= R
"cc(
811 std::string Expected
= R
"(
813 if (true) { /* then */ }
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 */ }"))})),
829 TEST_F(TransformerTest
, Flatten
) {
830 using clang::transformer::editList
;
831 std::string Input
= R
"cc(
839 std::string Expected
= R
"(
841 if (true) { /* then */ }
846 StringRef C
= "C", T
= "T", E
= "E";
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 */ }")))),
857 TEST_F(TransformerTest
, FlattenWithMixedArgs
) {
858 using clang::transformer::editList
;
859 std::string Input
= R
"cc(
867 std::string Expected
= R
"(
869 if (true) { /* then */ }
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 */ }"))}))),
885 TEST_F(TransformerTest
, OrderedRuleUnrelated
) {
886 StringRef Flag
= "flag";
887 RewriteRule FlagRule
= makeRule(
888 cxxMemberCallExpr(on(expr(hasType(cxxRecordDecl(
889 hasName("proto::ProtoCommandLineFlag"))))
891 unless(callee(cxxMethodDecl(hasName("GetProto"))))),
892 changeTo(node(std::string(Flag
)), cat("PROTO")));
894 std::string Input
= R
"cc(
895 proto::ProtoCommandLineFlag flag;
897 int y = flag.GetProto().foo();
898 int f(string s) { return strlen(s.c_str()); }
900 std::string Expected
= R
"cc(
901 proto::ProtoCommandLineFlag flag;
903 int y = flag.GetProto().foo();
904 int f(string s) { return REPLACED; }
907 testRule(applyFirst({ruleStrlenSize(), FlagRule
}), Input
, Expected
);
910 TEST_F(TransformerTest
, OrderedRuleRelated
) {
911 std::string Input
= R
"cc(
914 void call_f1() { f1(); }
915 void call_f2() { f2(); }
917 std::string Expected
= R
"cc(
920 void call_f1() { REPLACE_F1; }
921 void call_f2() { REPLACE_F1_OR_F2; }
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(
939 void call_f1() { f1(); }
940 void call_f2() { f2(); }
942 std::string Expected
= R
"cc(
945 void call_f1() { REPLACE_F1_OR_F2; }
946 void call_f2() { REPLACE_F1_OR_F2; }
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
963 TEST_F(TransformerTest
, OrderedRuleMultipleKinds
) {
964 std::string Input
= R
"cc(
967 void call_f1() { f1(); }
968 void call_f2() { f2(); }
970 std::string Expected
= R
"cc(
973 void call_f1() { REPLACE_F1; }
974 void call_f2() { REPLACE_F1_OR_F2; }
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(
997 void call_f1() { f1(); }
998 float call_f2() { return f2(); }
1000 std::string Expected
= R
"cc(
1003 void call_f1() { REPLACE_F1; }
1004 float call_f2() { return REPLACE_F2; }
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:
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"; }
1033 makeRule(binaryOperator().bind(O
),
1034 changeTo(node(std::string(O
)), std::make_shared
<AlwaysFail
>())),
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"))}),
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:
1062 Transformer
T(makeRule(expr().bind(E
),
1063 changeTo(node(std::string(E
)), cat("DELETE_EXPR"))),
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;"))),
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(
1092 std::string OtherStructSuffix
= "};";
1094 std::string CopyableStructName
= "struct Copyable";
1095 std::string BrokenStructName
= "struct explicit Copyable";
1097 std::string CodeSuffix
= R
"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
+
1114 std::string BrokenRewriteOutput
= OtherStructPrefix
+ BrokenExplicitCopyCtor
+
1115 OtherStructSuffix
+ BrokenStructName
+
1118 auto MatchedRecord
=
1119 cxxConstructorDecl(isCopyConstructor()).bind("copyConstructor");
1122 changeTo(before(node("copyConstructor")), cat("explicit "));
1124 testRule(makeRule(traverse(TK_IgnoreUnlessSpelledInSource
, MatchedRecord
),
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(
1139 int* cbegin() const;
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(
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");
1176 changeTo(node("constBeginCall"), cat(name("callTarget"), ".cbegin()"));
1178 testRule(makeRule(traverse(TK_IgnoreUnlessSpelledInSource
, MatchedRecord
),
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(
1191 NonTrivial(NonTrivial&) {}
1192 NonTrivial& operator=(NonTrivial const&) { return *this; }
1197 struct ContainsArray {
1199 ContainsArray& operator=(ContainsArray const&) = default;
1209 auto CodeSuffix
= "}";
1211 auto LoopBody
= R
"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
1228 CodePrefix
+ RawLoop
+ LoopBody
+ RawLoop
+ LoopBody
+ CodeSuffix
;
1230 auto RewriteOutput
=
1231 CodePrefix
+ RangeLoop
+ LoopBody
+ RangeLoop
+ LoopBody
+ CodeSuffix
;
1233 auto MatchedLoop
= forStmt(
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")));
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
),
1253 RewriteInput
, RewriteOutput
);
1255 testRuleFailure(makeRule(traverse(TK_AsIs
, MatchedLoop
), RewriteRule
),
1260 TEST_F(TransformerTest
, ImplicitNodes_ForStmt2
) {
1262 std::string CodePrefix
= R
"cpp(
1265 NonTrivial(NonTrivial&) {}
1266 NonTrivial& operator=(NonTrivial const&) { return *this; }
1271 struct ContainsArray {
1273 ContainsArray& operator=(ContainsArray const&) = default;
1283 auto CodeSuffix
= "}";
1285 auto LoopBody
= R
"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
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")));
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
),
1326 RewriteInput
, RewriteOutput
);
1328 testRuleFailure(makeRule(traverse(TK_AsIs
, MatchedLoop
), RewriteRule
),
1333 TEST_F(TransformerTest
, TemplateInstantiation
) {
1335 std::string NonTemplatesInput
= R
"cpp(
1340 std::string NonTemplatesExpected
= R
"cpp(
1346 std::string TemplatesInput
= R
"cpp(
1347 template<typename T>
1348 struct TemplStruct {
1358 TemplStruct<int> ti;
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 {
1385 TemplStruct<int> ti;
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(
1402 int f(string s) { return ZERO; }
1404 std::string Expected
= R
"cc(
1406 int f(string s) { return 999; }
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); }
1422 std::string Expected
= R
"cc(
1423 #define MACRO(str) strlen((str).c_str())
1424 int f(string s) { return REPLACED; }
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())); }
1436 std::string Expected
= R
"cc(
1437 #define PLUS(e) e + 1
1438 int f(string s) { return PLUS(REPLACED); }
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(
1449 #define MACRO(str) NESTED(strlen((str).c_str()))
1450 int f(string s) { return MACRO(s); }
1452 std::string Expected
= R
"cc(
1454 #define MACRO(str) NESTED(strlen((str).c_str()))
1455 int f(string s) { return REPLACED; }
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
1466 TEST_F(TransformerTest
, IdentityMacro
) {
1467 std::string Input
= R
"cc(
1469 int f(string s) { return ID(strlen(s.c_str())); }
1471 std::string Expected
= R
"cc(
1473 int f(string s) { return REPLACED; }
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); }
1486 std::string Expected
= R
"cc(
1487 #define PLUS(a,b) (a) + (b)
1488 int f() { return PLUS(LIT, LIT); }
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); }
1501 std::string Expected
= R
"cc(
1502 #define PLUS_ONE(a) a + 1
1503 int f() { return PLUS_ONE(LIT); }
1506 StringRef E
= "expr";
1507 testRule(makeRule(binaryOperator(hasLHS(expr().bind(E
))),
1508 changeTo(node(std::string(E
)), cat("LIT"))),
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); }
1519 std::string Expected
= R
"cc(
1520 #define PLUS_ONE(a) 1 + a
1521 int f() { return PLUS_ONE(LIT); }
1524 StringRef E
= "expr";
1525 testRule(makeRule(binaryOperator(hasRHS(expr().bind(E
))),
1526 changeTo(node(std::string(E
)), cat("LIT"))),
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
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(
1552 #define MACRO(str) 1 + NESTED(strlen((str).c_str()))
1553 int f(string s) { return MACRO(s); }
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
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");
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";
1580 makeRule(functionDecl(hasName("RemoveThisFunction")), changeTo(cat(""))),
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";
1619 makeRule(callExpr(callee(
1620 functionDecl(hasName("RemoveThisFunction")).bind("fun"))),
1621 addInclude(node("fun"), "header.h")),
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
));