1 //===- unittest/Tooling/TransformerTest.cpp -------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
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"
19
20 using namespace clang;
21 using namespace tooling;
22 using namespace ast_matchers;
23 namespace {
24 using ::clang::transformer::addInclude;
25 using ::clang::transformer::applyFirst;
26 using ::clang::transformer::before;
27 using ::clang::transformer::cat;
28 using ::clang::transformer::changeTo;
29 using ::clang::transformer::makeRule;
30 using ::clang::transformer::member;
31 using ::clang::transformer::name;
32 using ::clang::transformer::node;
33 using ::clang::transformer::remove;
34 using ::clang::transformer::rewriteDescendants;
35 using ::clang::transformer::RewriteRule;
36 using ::clang::transformer::statement;
37 using ::testing::ElementsAre;
38 using ::testing::IsEmpty;
39
40 constexpr char KHeaderContents[] = R"cc(
41 struct string {
42 string(const char*);
43 char* c_str();
44 int size();
45 };
46 int strlen(const char*);
47
48 namespace proto {
49 struct PCFProto {
50 int foo();
51 };
52 struct ProtoCommandLineFlag : PCFProto {
53 PCFProto& GetProto();
54 };
55 } // namespace proto
56 class Logger {};
57 void operator<<(Logger& l, string msg);
58 Logger& log(int level);
59 )cc";
60
61 static ast_matchers::internal::Matcher<clang::QualType>
isOrPointsTo(const clang::ast_matchers::DeclarationMatcher & TypeMatcher)62 isOrPointsTo(const clang::ast_matchers::DeclarationMatcher &TypeMatcher) {
63 return anyOf(hasDeclaration(TypeMatcher), pointsTo(TypeMatcher));
64 }
65
format(StringRef Code)66 static std::string format(StringRef Code) {
67 const std::vector<Range> Ranges(1, Range(0, Code.size()));
68 auto Style = format::getLLVMStyle();
69 const auto Replacements = format::reformat(Style, Code, Ranges);
70 auto Formatted = applyAllReplacements(Code, Replacements);
71 if (!Formatted) {
72 ADD_FAILURE() << "Could not format code: "
73 << llvm::toString(Formatted.takeError());
74 return std::string();
75 }
76 return *Formatted;
77 }
78
compareSnippets(StringRef Expected,const llvm::Optional<std::string> & MaybeActual)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));
88 }
89
90 // FIXME: consider separating this class into its own file(s).
91 class ClangRefactoringTestBase : public testing::Test {
92 protected:
appendToHeader(StringRef S)93 void appendToHeader(StringRef S) { FileContents[0].second += S; }
94
addFile(StringRef Filename,StringRef Content)95 void addFile(StringRef Filename, StringRef Content) {
96 FileContents.emplace_back(std::string(Filename), std::string(Content));
97 }
98
rewrite(StringRef Input)99 llvm::Optional<std::string> rewrite(StringRef Input) {
100 std::string Code = ("#include \"header.h\"\n" + Input).str();
101 auto Factory = newFrontendActionFactory(&MatchFinder);
102 if (!runToolOnCodeWithArgs(
103 Factory->create(), Code, std::vector<std::string>(), "input.cc",
104 "clang-tool", std::make_shared<PCHContainerOperations>(),
105 FileContents)) {
106 llvm::errs() << "Running tool failed.\n";
107 return None;
108 }
109 if (ErrorCount != 0) {
110 llvm::errs() << "Generating changes failed.\n";
111 return None;
112 }
113 auto ChangedCode =
114 applyAtomicChanges("input.cc", Code, Changes, ApplyChangesSpec());
115 if (!ChangedCode) {
116 llvm::errs() << "Applying changes failed: "
117 << llvm::toString(ChangedCode.takeError()) << "\n";
118 return None;
119 }
120 return *ChangedCode;
121 }
122
consumer()123 Transformer::ChangeConsumer consumer() {
124 return [this](Expected<AtomicChange> C) {
125 if (C) {
126 Changes.push_back(std::move(*C));
127 } else {
128 // FIXME: stash this error rather then printing.
129 llvm::errs() << "Error generating changes: "
130 << llvm::toString(C.takeError()) << "\n";
131 ++ErrorCount;
132 }
133 };
134 }
135
136 template <typename R>
testRule(R Rule,StringRef Input,StringRef Expected)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));
142 }
143
testRuleFailure(R Rule,StringRef 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";
149 }
150
151 // Transformers are referenced by MatchFinder.
152 std::vector<std::unique_ptr<Transformer>> Transformers;
153 clang::ast_matchers::MatchFinder MatchFinder;
154 // Records whether any errors occurred in individual changes.
155 int ErrorCount = 0;
156 AtomicChanges Changes;
157
158 private:
159 FileContentMappings FileContents = {{"header.h", ""}};
160 };
161
162 class TransformerTest : public ClangRefactoringTestBase {
163 protected:
TransformerTest()164 TransformerTest() { appendToHeader(KHeaderContents); }
165 };
166
167 // Given string s, change strlen($s.c_str()) to REPLACED.
ruleStrlenSize()168 static RewriteRule ruleStrlenSize() {
169 StringRef StringExpr = "strexpr";
170 auto StringType = namedDecl(hasAnyName("::basic_string", "::string"));
171 auto R = makeRule(
172 callExpr(callee(functionDecl(hasName("strlen"))),
173 hasArgument(0, cxxMemberCallExpr(
174 on(expr(hasType(isOrPointsTo(StringType)))
175 .bind(StringExpr)),
176 callee(cxxMethodDecl(hasName("c_str")))))),
177 changeTo(cat("REPLACED")), cat("Use size() method directly on string."));
178 return R;
179 }
180
TEST_F(TransformerTest,StrlenSize)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);
185 }
186
187 // Tests that no change is applied when a match is not expected.
TEST_F(TransformerTest,NoMatch)188 TEST_F(TransformerTest, NoMatch) {
189 std::string Input = "int f(string s) { return s.size(); }";
190 testRule(ruleStrlenSize(), Input, Input);
191 }
192
193 // Tests replacing an expression.
TEST_F(TransformerTest,Flag)194 TEST_F(TransformerTest, Flag) {
195 StringRef Flag = "flag";
196 RewriteRule Rule = makeRule(
197 cxxMemberCallExpr(on(expr(hasType(cxxRecordDecl(
198 hasName("proto::ProtoCommandLineFlag"))))
199 .bind(Flag)),
200 unless(callee(cxxMethodDecl(hasName("GetProto"))))),
201 changeTo(node(std::string(Flag)), cat("EXPR")));
202
203 std::string Input = R"cc(
204 proto::ProtoCommandLineFlag flag;
205 int x = flag.foo();
206 int y = flag.GetProto().foo();
207 )cc";
208 std::string Expected = R"cc(
209 proto::ProtoCommandLineFlag flag;
210 int x = EXPR.foo();
211 int y = flag.GetProto().foo();
212 )cc";
213
214 testRule(std::move(Rule), Input, Expected);
215 }
216
TEST_F(TransformerTest,AddIncludeQuoted)217 TEST_F(TransformerTest, AddIncludeQuoted) {
218 RewriteRule Rule =
219 makeRule(callExpr(callee(functionDecl(hasName("f")))),
220 {addInclude("clang/OtherLib.h"), changeTo(cat("other()"))});
221
222 std::string Input = R"cc(
223 int f(int x);
224 int h(int x) { return f(x); }
225 )cc";
226 std::string Expected = R"cc(#include "clang/OtherLib.h"
227
228 int f(int x);
229 int h(int x) { return other(); }
230 )cc";
231
232 testRule(Rule, Input, Expected);
233 }
234
TEST_F(TransformerTest,AddIncludeAngled)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()"))});
240
241 std::string Input = R"cc(
242 int f(int x);
243 int h(int x) { return f(x); }
244 )cc";
245 std::string Expected = R"cc(#include <clang/OtherLib.h>
246
247 int f(int x);
248 int h(int x) { return other(); }
249 )cc";
250
251 testRule(Rule, Input, Expected);
252 }
253
TEST_F(TransformerTest,AddIncludeQuotedForRule)254 TEST_F(TransformerTest, AddIncludeQuotedForRule) {
255 RewriteRule Rule = makeRule(callExpr(callee(functionDecl(hasName("f")))),
256 changeTo(cat("other()")));
257 addInclude(Rule, "clang/OtherLib.h");
258
259 std::string Input = R"cc(
260 int f(int x);
261 int h(int x) { return f(x); }
262 )cc";
263 std::string Expected = R"cc(#include "clang/OtherLib.h"
264
265 int f(int x);
266 int h(int x) { return other(); }
267 )cc";
268
269 testRule(Rule, Input, Expected);
270 }
271
TEST_F(TransformerTest,AddIncludeAngledForRule)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);
276
277 std::string Input = R"cc(
278 int f(int x);
279 int h(int x) { return f(x); }
280 )cc";
281 std::string Expected = R"cc(#include <clang/OtherLib.h>
282
283 int f(int x);
284 int h(int x) { return other(); }
285 )cc";
286
287 testRule(Rule, Input, Expected);
288 }
289
TEST_F(TransformerTest,NodePartNameNamedDecl)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")));
294
295 std::string Input = R"cc(
296 int bad(int x);
297 int bad(int x) { return x * x; }
298 )cc";
299 std::string Expected = R"cc(
300 int good(int x);
301 int good(int x) { return x * x; }
302 )cc";
303
304 testRule(Rule, Input, Expected);
305 }
306
TEST_F(TransformerTest,NodePartNameDeclRef)307 TEST_F(TransformerTest, NodePartNameDeclRef) {
308 std::string Input = R"cc(
309 template <typename T>
310 T bad(T x) {
311 return x;
312 }
313 int neutral(int x) { return bad<int>(x) * x; }
314 )cc";
315 std::string Expected = R"cc(
316 template <typename T>
317 T bad(T x) {
318 return x;
319 }
320 int neutral(int x) { return good<int>(x) * x; }
321 )cc";
322
323 StringRef Ref = "ref";
324 testRule(makeRule(declRefExpr(to(functionDecl(hasName("bad")))).bind(Ref),
325 changeTo(name(std::string(Ref)), cat("good"))),
326 Input, Expected);
327 }
328
TEST_F(TransformerTest,NodePartNameDeclRefFailure)329 TEST_F(TransformerTest, NodePartNameDeclRefFailure) {
330 std::string Input = R"cc(
331 struct Y {
332 int operator*();
333 };
334 int neutral(int x) {
335 Y y;
336 int (Y::*ptr)() = &Y::operator*;
337 return *y + x;
338 }
339 )cc";
340
341 StringRef Ref = "ref";
342 Transformer T(makeRule(declRefExpr(to(functionDecl())).bind(Ref),
343 changeTo(name(std::string(Ref)), cat("good"))),
344 consumer());
345 T.registerMatchers(&MatchFinder);
346 EXPECT_FALSE(rewrite(Input));
347 }
348
TEST_F(TransformerTest,NodePartMember)349 TEST_F(TransformerTest, NodePartMember) {
350 StringRef E = "expr";
351 RewriteRule Rule =
352 makeRule(memberExpr(clang::ast_matchers::member(hasName("bad"))).bind(E),
353 changeTo(member(std::string(E)), cat("good")));
354
355 std::string Input = R"cc(
356 struct S {
357 int bad;
358 };
359 int g() {
360 S s;
361 return s.bad;
362 }
363 )cc";
364 std::string Expected = R"cc(
365 struct S {
366 int bad;
367 };
368 int g() {
369 S s;
370 return s.good;
371 }
372 )cc";
373
374 testRule(Rule, Input, Expected);
375 }
376
TEST_F(TransformerTest,NodePartMemberQualified)377 TEST_F(TransformerTest, NodePartMemberQualified) {
378 std::string Input = R"cc(
379 struct S {
380 int bad;
381 int good;
382 };
383 struct T : public S {
384 int bad;
385 };
386 int g() {
387 T t;
388 return t.S::bad;
389 }
390 )cc";
391 std::string Expected = R"cc(
392 struct S {
393 int bad;
394 int good;
395 };
396 struct T : public S {
397 int bad;
398 };
399 int g() {
400 T t;
401 return t.S::good;
402 }
403 )cc";
404
405 StringRef E = "expr";
406 testRule(makeRule(memberExpr().bind(E),
407 changeTo(member(std::string(E)), cat("good"))),
408 Input, Expected);
409 }
410
TEST_F(TransformerTest,NodePartMemberMultiToken)411 TEST_F(TransformerTest, NodePartMemberMultiToken) {
412 std::string Input = R"cc(
413 struct Y {
414 int operator*();
415 int good();
416 template <typename T> void foo(T t);
417 };
418 int neutral(int x) {
419 Y y;
420 y.template foo<int>(3);
421 return y.operator *();
422 }
423 )cc";
424 std::string Expected = R"cc(
425 struct Y {
426 int operator*();
427 int good();
428 template <typename T> void foo(T t);
429 };
430 int neutral(int x) {
431 Y y;
432 y.template good<int>(3);
433 return y.good();
434 }
435 )cc";
436
437 StringRef MemExpr = "member";
438 testRule(makeRule(memberExpr().bind(MemExpr),
439 changeTo(member(std::string(MemExpr)), cat("good"))),
440 Input, Expected);
441 }
442
TEST_F(TransformerTest,NoEdits)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);
447 }
448
TEST_F(TransformerTest,NoopEdit)449 TEST_F(TransformerTest, NoopEdit) {
450 using transformer::node;
451 using transformer::noopEdit;
452 std::string Input = "int f(int x) { return x; }";
453 testRule(makeRule(returnStmt().bind("return"), noopEdit(node("return"))),
454 Input, Input);
455 }
456
TEST_F(TransformerTest,IfBound2Args)457 TEST_F(TransformerTest, IfBound2Args) {
458 using transformer::ifBound;
459 std::string Input = "int f(int x) { return x; }";
460 std::string Expected = "int f(int x) { CHANGE; }";
461 testRule(makeRule(returnStmt().bind("return"),
462 ifBound("return", changeTo(cat("CHANGE;")))),
463 Input, Expected);
464 }
465
TEST_F(TransformerTest,IfBound3Args)466 TEST_F(TransformerTest, IfBound3Args) {
467 using transformer::ifBound;
468 std::string Input = "int f(int x) { return x; }";
469 std::string Expected = "int f(int x) { CHANGE; }";
470 testRule(makeRule(returnStmt().bind("return"),
471 ifBound("nothing", changeTo(cat("ERROR")),
472 changeTo(cat("CHANGE;")))),
473 Input, Expected);
474 }
475
TEST_F(TransformerTest,ShrinkTo)476 TEST_F(TransformerTest, ShrinkTo) {
477 using transformer::shrinkTo;
478 std::string Input = "int f(int x) { return x; }";
479 std::string Expected = "return x;";
480 testRule(makeRule(functionDecl(hasDescendant(returnStmt().bind("return")))
481 .bind("function"),
482 shrinkTo(node("function"), node("return"))),
483 Input, Expected);
484 }
485
486 // Rewrite various Stmts inside a Decl.
TEST_F(TransformerTest,RewriteDescendantsDeclChangeStmt)487 TEST_F(TransformerTest, RewriteDescendantsDeclChangeStmt) {
488 std::string Input =
489 "int f(int x) { int y = x; { int z = x * x; } return x; }";
490 std::string Expected =
491 "int f(int x) { int y = 3; { int z = 3 * 3; } return 3; }";
492 auto InlineX =
493 makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
494 testRule(makeRule(functionDecl(hasName("f")).bind("fun"),
495 rewriteDescendants("fun", InlineX)),
496 Input, Expected);
497 }
498
499 // Rewrite various TypeLocs inside a Decl.
TEST_F(TransformerTest,RewriteDescendantsDeclChangeTypeLoc)500 TEST_F(TransformerTest, RewriteDescendantsDeclChangeTypeLoc) {
501 std::string Input = "int f(int *x) { return *x; }";
502 std::string Expected = "char f(char *x) { return *x; }";
503 auto IntToChar = makeRule(typeLoc(loc(qualType(isInteger(), builtinType()))),
504 changeTo(cat("char")));
505 testRule(makeRule(functionDecl(hasName("f")).bind("fun"),
506 rewriteDescendants("fun", IntToChar)),
507 Input, Expected);
508 }
509
TEST_F(TransformerTest,RewriteDescendantsStmt)510 TEST_F(TransformerTest, RewriteDescendantsStmt) {
511 // Add an unrelated definition to the header that also has a variable named
512 // "x", to test that the rewrite is limited to the scope we intend.
513 appendToHeader(R"cc(int g(int x) { return x; })cc");
514 std::string Input =
515 "int f(int x) { int y = x; { int z = x * x; } return x; }";
516 std::string Expected =
517 "int f(int x) { int y = 3; { int z = 3 * 3; } return 3; }";
518 auto InlineX =
519 makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
520 testRule(makeRule(functionDecl(hasName("f"), hasBody(stmt().bind("body"))),
521 rewriteDescendants("body", InlineX)),
522 Input, Expected);
523 }
524
TEST_F(TransformerTest,RewriteDescendantsStmtWithAdditionalChange)525 TEST_F(TransformerTest, RewriteDescendantsStmtWithAdditionalChange) {
526 std::string Input =
527 "int f(int x) { int y = x; { int z = x * x; } return x; }";
528 std::string Expected =
529 "int newName(int x) { int y = 3; { int z = 3 * 3; } return 3; }";
530 auto InlineX =
531 makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
532 testRule(
533 makeRule(
534 functionDecl(hasName("f"), hasBody(stmt().bind("body"))).bind("f"),
535 flatten(changeTo(name("f"), cat("newName")),
536 rewriteDescendants("body", InlineX))),
537 Input, Expected);
538 }
539
TEST_F(TransformerTest,RewriteDescendantsTypeLoc)540 TEST_F(TransformerTest, RewriteDescendantsTypeLoc) {
541 std::string Input = "int f(int *x) { return *x; }";
542 std::string Expected = "int f(char *x) { return *x; }";
543 auto IntToChar =
544 makeRule(typeLoc(loc(qualType(isInteger(), builtinType()))).bind("loc"),
545 changeTo(cat("char")));
546 testRule(
547 makeRule(functionDecl(hasName("f"),
548 hasParameter(0, varDecl(hasTypeLoc(
549 typeLoc().bind("parmType"))))),
550 rewriteDescendants("parmType", IntToChar)),
551 Input, Expected);
552 }
553
TEST_F(TransformerTest,RewriteDescendantsReferToParentBinding)554 TEST_F(TransformerTest, RewriteDescendantsReferToParentBinding) {
555 std::string Input =
556 "int f(int p) { int y = p; { int z = p * p; } return p; }";
557 std::string Expected =
558 "int f(int p) { int y = 3; { int z = 3 * 3; } return 3; }";
559 std::string VarId = "var";
560 auto InlineVar = makeRule(declRefExpr(to(varDecl(equalsBoundNode(VarId)))),
561 changeTo(cat("3")));
562 testRule(makeRule(functionDecl(hasName("f"),
563 hasParameter(0, varDecl().bind(VarId)))
564 .bind("fun"),
565 rewriteDescendants("fun", InlineVar)),
566 Input, Expected);
567 }
568
TEST_F(TransformerTest,RewriteDescendantsUnboundNode)569 TEST_F(TransformerTest, RewriteDescendantsUnboundNode) {
570 std::string Input =
571 "int f(int x) { int y = x; { int z = x * x; } return x; }";
572 auto InlineX =
573 makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
574 Transformer T(makeRule(functionDecl(hasName("f")),
575 rewriteDescendants("UNBOUND", InlineX)),
576 consumer());
577 T.registerMatchers(&MatchFinder);
578 EXPECT_FALSE(rewrite(Input));
579 EXPECT_THAT(Changes, IsEmpty());
580 EXPECT_EQ(ErrorCount, 1);
581 }
582
TEST_F(TransformerTest,RewriteDescendantsInvalidNodeType)583 TEST_F(TransformerTest, RewriteDescendantsInvalidNodeType) {
584 std::string Input =
585 "int f(int x) { int y = x; { int z = x * x; } return x; }";
586 auto IntToChar =
587 makeRule(qualType(isInteger(), builtinType()), changeTo(cat("char")));
588 Transformer T(
589 makeRule(functionDecl(
590 hasName("f"),
591 hasParameter(0, varDecl(hasType(qualType().bind("type"))))),
592 rewriteDescendants("type", IntToChar)),
593 consumer());
594 T.registerMatchers(&MatchFinder);
595 EXPECT_FALSE(rewrite(Input));
596 EXPECT_THAT(Changes, IsEmpty());
597 EXPECT_EQ(ErrorCount, 1);
598 }
599
600 //
601 // We include one test per typed overload. We don't test extensively since that
602 // is already covered by the tests above.
603 //
604
TEST_F(TransformerTest,RewriteDescendantsTypedStmt)605 TEST_F(TransformerTest, RewriteDescendantsTypedStmt) {
606 // Add an unrelated definition to the header that also has a variable named
607 // "x", to test that the rewrite is limited to the scope we intend.
608 appendToHeader(R"cc(int g(int x) { return x; })cc");
609 std::string Input =
610 "int f(int x) { int y = x; { int z = x * x; } return x; }";
611 std::string Expected =
612 "int f(int x) { int y = 3; { int z = 3 * 3; } return 3; }";
613 auto InlineX =
614 makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
615 testRule(makeRule(functionDecl(hasName("f"), hasBody(stmt().bind("body"))),
616 [&InlineX](const MatchFinder::MatchResult &R) {
617 const auto *Node = R.Nodes.getNodeAs<Stmt>("body");
618 assert(Node != nullptr && "body must be bound");
619 return transformer::detail::rewriteDescendants(
620 *Node, InlineX, R);
621 }),
622 Input, Expected);
623 }
624
TEST_F(TransformerTest,RewriteDescendantsTypedDecl)625 TEST_F(TransformerTest, RewriteDescendantsTypedDecl) {
626 std::string Input =
627 "int f(int x) { int y = x; { int z = x * x; } return x; }";
628 std::string Expected =
629 "int f(int x) { int y = 3; { int z = 3 * 3; } return 3; }";
630 auto InlineX =
631 makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
632 testRule(makeRule(functionDecl(hasName("f")).bind("fun"),
633 [&InlineX](const MatchFinder::MatchResult &R) {
634 const auto *Node = R.Nodes.getNodeAs<Decl>("fun");
635 assert(Node != nullptr && "fun must be bound");
636 return transformer::detail::rewriteDescendants(
637 *Node, InlineX, R);
638 }),
639 Input, Expected);
640 }
641
TEST_F(TransformerTest,RewriteDescendantsTypedTypeLoc)642 TEST_F(TransformerTest, RewriteDescendantsTypedTypeLoc) {
643 std::string Input = "int f(int *x) { return *x; }";
644 std::string Expected = "int f(char *x) { return *x; }";
645 auto IntToChar =
646 makeRule(typeLoc(loc(qualType(isInteger(), builtinType()))).bind("loc"),
647 changeTo(cat("char")));
648 testRule(
649 makeRule(
650 functionDecl(
651 hasName("f"),
652 hasParameter(0, varDecl(hasTypeLoc(typeLoc().bind("parmType"))))),
653 [&IntToChar](const MatchFinder::MatchResult &R) {
654 const auto *Node = R.Nodes.getNodeAs<TypeLoc>("parmType");
655 assert(Node != nullptr && "parmType must be bound");
656 return transformer::detail::rewriteDescendants(*Node, IntToChar, R);
657 }),
658 Input, Expected);
659 }
660
TEST_F(TransformerTest,RewriteDescendantsTypedDynTyped)661 TEST_F(TransformerTest, RewriteDescendantsTypedDynTyped) {
662 // Add an unrelated definition to the header that also has a variable named
663 // "x", to test that the rewrite is limited to the scope we intend.
664 appendToHeader(R"cc(int g(int x) { return x; })cc");
665 std::string Input =
666 "int f(int x) { int y = x; { int z = x * x; } return x; }";
667 std::string Expected =
668 "int f(int x) { int y = 3; { int z = 3 * 3; } return 3; }";
669 auto InlineX =
670 makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
671 testRule(
672 makeRule(functionDecl(hasName("f"), hasBody(stmt().bind("body"))),
673 [&InlineX](const MatchFinder::MatchResult &R) {
674 auto It = R.Nodes.getMap().find("body");
675 assert(It != R.Nodes.getMap().end() && "body must be bound");
676 return transformer::detail::rewriteDescendants(It->second,
677 InlineX, R);
678 }),
679 Input, Expected);
680 }
681
TEST_F(TransformerTest,InsertBeforeEdit)682 TEST_F(TransformerTest, InsertBeforeEdit) {
683 std::string Input = R"cc(
684 int f() {
685 return 7;
686 }
687 )cc";
688 std::string Expected = R"cc(
689 int f() {
690 int y = 3;
691 return 7;
692 }
693 )cc";
694
695 StringRef Ret = "return";
696 testRule(
697 makeRule(returnStmt().bind(Ret),
698 insertBefore(statement(std::string(Ret)), cat("int y = 3;"))),
699 Input, Expected);
700 }
701
TEST_F(TransformerTest,InsertAfterEdit)702 TEST_F(TransformerTest, InsertAfterEdit) {
703 std::string Input = R"cc(
704 int f() {
705 int x = 5;
706 return 7;
707 }
708 )cc";
709 std::string Expected = R"cc(
710 int f() {
711 int x = 5;
712 int y = 3;
713 return 7;
714 }
715 )cc";
716
717 StringRef Decl = "decl";
718 testRule(
719 makeRule(declStmt().bind(Decl),
720 insertAfter(statement(std::string(Decl)), cat("int y = 3;"))),
721 Input, Expected);
722 }
723
TEST_F(TransformerTest,RemoveEdit)724 TEST_F(TransformerTest, RemoveEdit) {
725 std::string Input = R"cc(
726 int f() {
727 int x = 5;
728 return 7;
729 }
730 )cc";
731 std::string Expected = R"cc(
732 int f() {
733 return 7;
734 }
735 )cc";
736
737 StringRef Decl = "decl";
738 testRule(
739 makeRule(declStmt().bind(Decl), remove(statement(std::string(Decl)))),
740 Input, Expected);
741 }
742
TEST_F(TransformerTest,WithMetadata)743 TEST_F(TransformerTest, WithMetadata) {
744 auto makeMetadata = [](const MatchFinder::MatchResult &R) -> llvm::Any {
745 int N =
746 R.Nodes.getNodeAs<IntegerLiteral>("int")->getValue().getLimitedValue();
747 return N;
748 };
749
750 std::string Input = R"cc(
751 int f() {
752 int x = 5;
753 return 7;
754 }
755 )cc";
756
757 Transformer T(
758 makeRule(
759 declStmt(containsDeclaration(0, varDecl(hasInitializer(
760 integerLiteral().bind("int")))))
761 .bind("decl"),
762 withMetadata(remove(statement(std::string("decl"))), makeMetadata)),
763 consumer());
764 T.registerMatchers(&MatchFinder);
765 auto Factory = newFrontendActionFactory(&MatchFinder);
766 EXPECT_TRUE(runToolOnCodeWithArgs(
767 Factory->create(), Input, std::vector<std::string>(), "input.cc",
768 "clang-tool", std::make_shared<PCHContainerOperations>(), {}));
769 ASSERT_EQ(Changes.size(), 1u);
770 const llvm::Any &Metadata = Changes[0].getMetadata();
771 ASSERT_TRUE(llvm::any_isa<int>(Metadata));
772 EXPECT_THAT(llvm::any_cast<int>(Metadata), 5);
773 }
774
TEST_F(TransformerTest,MultiChange)775 TEST_F(TransformerTest, MultiChange) {
776 std::string Input = R"cc(
777 void foo() {
778 if (10 > 1.0)
779 log(1) << "oh no!";
780 else
781 log(0) << "ok";
782 }
783 )cc";
784 std::string Expected = R"(
785 void foo() {
786 if (true) { /* then */ }
787 else { /* else */ }
788 }
789 )";
790
791 StringRef C = "C", T = "T", E = "E";
792 testRule(
793 makeRule(ifStmt(hasCondition(expr().bind(C)), hasThen(stmt().bind(T)),
794 hasElse(stmt().bind(E))),
795 {changeTo(node(std::string(C)), cat("true")),
796 changeTo(statement(std::string(T)), cat("{ /* then */ }")),
797 changeTo(statement(std::string(E)), cat("{ /* else */ }"))}),
798 Input, Expected);
799 }
800
TEST_F(TransformerTest,EditList)801 TEST_F(TransformerTest, EditList) {
802 using clang::transformer::editList;
803 std::string Input = R"cc(
804 void foo() {
805 if (10 > 1.0)
806 log(1) << "oh no!";
807 else
808 log(0) << "ok";
809 }
810 )cc";
811 std::string Expected = R"(
812 void foo() {
813 if (true) { /* then */ }
814 else { /* else */ }
815 }
816 )";
817
818 StringRef C = "C", T = "T", E = "E";
819 testRule(makeRule(ifStmt(hasCondition(expr().bind(C)),
820 hasThen(stmt().bind(T)), hasElse(stmt().bind(E))),
821 editList({changeTo(node(std::string(C)), cat("true")),
822 changeTo(statement(std::string(T)),
823 cat("{ /* then */ }")),
824 changeTo(statement(std::string(E)),
825 cat("{ /* else */ }"))})),
826 Input, Expected);
827 }
828
TEST_F(TransformerTest,Flatten)829 TEST_F(TransformerTest, Flatten) {
830 using clang::transformer::editList;
831 std::string Input = R"cc(
832 void foo() {
833 if (10 > 1.0)
834 log(1) << "oh no!";
835 else
836 log(0) << "ok";
837 }
838 )cc";
839 std::string Expected = R"(
840 void foo() {
841 if (true) { /* then */ }
842 else { /* else */ }
843 }
844 )";
845
846 StringRef C = "C", T = "T", E = "E";
847 testRule(
848 makeRule(
849 ifStmt(hasCondition(expr().bind(C)), hasThen(stmt().bind(T)),
850 hasElse(stmt().bind(E))),
851 flatten(changeTo(node(std::string(C)), cat("true")),
852 changeTo(statement(std::string(T)), cat("{ /* then */ }")),
853 changeTo(statement(std::string(E)), cat("{ /* else */ }")))),
854 Input, Expected);
855 }
856
TEST_F(TransformerTest,FlattenWithMixedArgs)857 TEST_F(TransformerTest, FlattenWithMixedArgs) {
858 using clang::transformer::editList;
859 std::string Input = R"cc(
860 void foo() {
861 if (10 > 1.0)
862 log(1) << "oh no!";
863 else
864 log(0) << "ok";
865 }
866 )cc";
867 std::string Expected = R"(
868 void foo() {
869 if (true) { /* then */ }
870 else { /* else */ }
871 }
872 )";
873
874 StringRef C = "C", T = "T", E = "E";
875 testRule(makeRule(ifStmt(hasCondition(expr().bind(C)),
876 hasThen(stmt().bind(T)), hasElse(stmt().bind(E))),
877 flatten(changeTo(node(std::string(C)), cat("true")),
878 edit(changeTo(statement(std::string(T)),
879 cat("{ /* then */ }"))),
880 editList({changeTo(statement(std::string(E)),
881 cat("{ /* else */ }"))}))),
882 Input, Expected);
883 }
884
TEST_F(TransformerTest,OrderedRuleUnrelated)885 TEST_F(TransformerTest, OrderedRuleUnrelated) {
886 StringRef Flag = "flag";
887 RewriteRule FlagRule = makeRule(
888 cxxMemberCallExpr(on(expr(hasType(cxxRecordDecl(
889 hasName("proto::ProtoCommandLineFlag"))))
890 .bind(Flag)),
891 unless(callee(cxxMethodDecl(hasName("GetProto"))))),
892 changeTo(node(std::string(Flag)), cat("PROTO")));
893
894 std::string Input = R"cc(
895 proto::ProtoCommandLineFlag flag;
896 int x = flag.foo();
897 int y = flag.GetProto().foo();
898 int f(string s) { return strlen(s.c_str()); }
899 )cc";
900 std::string Expected = R"cc(
901 proto::ProtoCommandLineFlag flag;
902 int x = PROTO.foo();
903 int y = flag.GetProto().foo();
904 int f(string s) { return REPLACED; }
905 )cc";
906
907 testRule(applyFirst({ruleStrlenSize(), FlagRule}), Input, Expected);
908 }
909
TEST_F(TransformerTest,OrderedRuleRelated)910 TEST_F(TransformerTest, OrderedRuleRelated) {
911 std::string Input = R"cc(
912 void f1();
913 void f2();
914 void call_f1() { f1(); }
915 void call_f2() { f2(); }
916 )cc";
917 std::string Expected = R"cc(
918 void f1();
919 void f2();
920 void call_f1() { REPLACE_F1; }
921 void call_f2() { REPLACE_F1_OR_F2; }
922 )cc";
923
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);
931 }
932
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.
TEST_F(TransformerTest,OrderedRuleRelatedSwapped)935 TEST_F(TransformerTest, OrderedRuleRelatedSwapped) {
936 std::string Input = R"cc(
937 void f1();
938 void f2();
939 void call_f1() { f1(); }
940 void call_f2() { f2(); }
941 )cc";
942 std::string Expected = R"cc(
943 void f1();
944 void f2();
945 void call_f1() { REPLACE_F1_OR_F2; }
946 void call_f2() { REPLACE_F1_OR_F2; }
947 )cc";
948
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);
956 }
957
958 // Verify that a set of rules whose matchers have different base kinds works
959 // properly, including that `applyFirst` produces multiple matchers. We test
960 // two different kinds of rules: Expr and Decl. We place the Decl rule in the
961 // middle to test that `buildMatchers` works even when the kinds aren't grouped
962 // together.
TEST_F(TransformerTest,OrderedRuleMultipleKinds)963 TEST_F(TransformerTest, OrderedRuleMultipleKinds) {
964 std::string Input = R"cc(
965 void f1();
966 void f2();
967 void call_f1() { f1(); }
968 void call_f2() { f2(); }
969 )cc";
970 std::string Expected = R"cc(
971 void f1();
972 void DECL_RULE();
973 void call_f1() { REPLACE_F1; }
974 void call_f2() { REPLACE_F1_OR_F2; }
975 )cc";
976
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")));
985
986 RewriteRule Rule = applyFirst({ReplaceF1, DeclRule, ReplaceF1OrF2});
987 EXPECT_EQ(transformer::detail::buildMatchers(Rule).size(), 2UL);
988 testRule(Rule, Input, Expected);
989 }
990
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.
TEST_F(TransformerTest,OrderedRuleImplicitMatched)993 TEST_F(TransformerTest, OrderedRuleImplicitMatched) {
994 std::string Input = R"cc(
995 void f1();
996 int f2();
997 void call_f1() { f1(); }
998 float call_f2() { return f2(); }
999 )cc";
1000 std::string Expected = R"cc(
1001 void f1();
1002 int f2();
1003 void call_f1() { REPLACE_F1; }
1004 float call_f2() { return REPLACE_F2; }
1005 )cc";
1006
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);
1014 }
1015
1016 //
1017 // Negative tests (where we expect no transformation to occur).
1018 //
1019
1020 // Tests for a conflict in edits from a single match for a rule.
TEST_F(TransformerTest,TextGeneratorFailure)1021 TEST_F(TransformerTest, TextGeneratorFailure) {
1022 std::string Input = "int conflictOneRule() { return 3 + 7; }";
1023 // Try to change the whole binary-operator expression AND one its operands:
1024 StringRef O = "O";
1025 class AlwaysFail : public transformer::MatchComputation<std::string> {
1026 llvm::Error eval(const ast_matchers::MatchFinder::MatchResult &,
1027 std::string *) const override {
1028 return llvm::createStringError(llvm::errc::invalid_argument, "ERROR");
1029 }
1030 std::string toString() const override { return "AlwaysFail"; }
1031 };
1032 Transformer T(
1033 makeRule(binaryOperator().bind(O),
1034 changeTo(node(std::string(O)), std::make_shared<AlwaysFail>())),
1035 consumer());
1036 T.registerMatchers(&MatchFinder);
1037 EXPECT_FALSE(rewrite(Input));
1038 EXPECT_THAT(Changes, IsEmpty());
1039 EXPECT_EQ(ErrorCount, 1);
1040 }
1041
1042 // Tests for a conflict in edits from a single match for a rule.
TEST_F(TransformerTest,OverlappingEditsInRule)1043 TEST_F(TransformerTest, OverlappingEditsInRule) {
1044 std::string Input = "int conflictOneRule() { return 3 + 7; }";
1045 // Try to change the whole binary-operator expression AND one its operands:
1046 StringRef O = "O", L = "L";
1047 Transformer T(makeRule(binaryOperator(hasLHS(expr().bind(L))).bind(O),
1048 {changeTo(node(std::string(O)), cat("DELETE_OP")),
1049 changeTo(node(std::string(L)), cat("DELETE_LHS"))}),
1050 consumer());
1051 T.registerMatchers(&MatchFinder);
1052 EXPECT_FALSE(rewrite(Input));
1053 EXPECT_THAT(Changes, IsEmpty());
1054 EXPECT_EQ(ErrorCount, 1);
1055 }
1056
1057 // Tests for a conflict in edits across multiple matches (of the same rule).
TEST_F(TransformerTest,OverlappingEditsMultipleMatches)1058 TEST_F(TransformerTest, OverlappingEditsMultipleMatches) {
1059 std::string Input = "int conflictOneRule() { return -7; }";
1060 // Try to change the whole binary-operator expression AND one its operands:
1061 StringRef E = "E";
1062 Transformer T(makeRule(expr().bind(E),
1063 changeTo(node(std::string(E)), cat("DELETE_EXPR"))),
1064 consumer());
1065 T.registerMatchers(&MatchFinder);
1066 // The rewrite process fails because the changes conflict with each other...
1067 EXPECT_FALSE(rewrite(Input));
1068 // ... but two changes were produced.
1069 EXPECT_EQ(Changes.size(), 2u);
1070 EXPECT_EQ(ErrorCount, 0);
1071 }
1072
TEST_F(TransformerTest,ErrorOccurredMatchSkipped)1073 TEST_F(TransformerTest, ErrorOccurredMatchSkipped) {
1074 // Syntax error in the function body:
1075 std::string Input = "void errorOccurred() { 3 }";
1076 Transformer T(makeRule(functionDecl(hasName("errorOccurred")),
1077 changeTo(cat("DELETED;"))),
1078 consumer());
1079 T.registerMatchers(&MatchFinder);
1080 // The rewrite process itself fails...
1081 EXPECT_FALSE(rewrite(Input));
1082 // ... and no changes or errors are produced in the process.
1083 EXPECT_THAT(Changes, IsEmpty());
1084 EXPECT_EQ(ErrorCount, 0);
1085 }
1086
TEST_F(TransformerTest,ImplicitNodes_ConstructorDecl)1087 TEST_F(TransformerTest, ImplicitNodes_ConstructorDecl) {
1088
1089 std::string OtherStructPrefix = R"cpp(
1090 struct Other {
1091 )cpp";
1092 std::string OtherStructSuffix = "};";
1093
1094 std::string CopyableStructName = "struct Copyable";
1095 std::string BrokenStructName = "struct explicit Copyable";
1096
1097 std::string CodeSuffix = R"cpp(
1098 {
1099 Other m_i;
1100 Copyable();
1101 };
1102 )cpp";
1103
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;";
1108
1109 std::string RewriteInput = OtherStructPrefix + CopyCtor + OtherStructSuffix +
1110 CopyableStructName + CodeSuffix;
1111 std::string ExpectedRewriteOutput = OtherStructPrefix + ExplicitCopyCtor +
1112 OtherStructSuffix + CopyableStructName +
1113 CodeSuffix;
1114 std::string BrokenRewriteOutput = OtherStructPrefix + BrokenExplicitCopyCtor +
1115 OtherStructSuffix + BrokenStructName +
1116 CodeSuffix;
1117
1118 auto MatchedRecord =
1119 cxxConstructorDecl(isCopyConstructor()).bind("copyConstructor");
1120
1121 auto RewriteRule =
1122 changeTo(before(node("copyConstructor")), cat("explicit "));
1123
1124 testRule(makeRule(traverse(TK_IgnoreUnlessSpelledInSource, MatchedRecord),
1125 RewriteRule),
1126 RewriteInput, ExpectedRewriteOutput);
1127
1128 testRule(makeRule(traverse(TK_AsIs, MatchedRecord), RewriteRule),
1129 RewriteInput, BrokenRewriteOutput);
1130 }
1131
TEST_F(TransformerTest,ImplicitNodes_RangeFor)1132 TEST_F(TransformerTest, ImplicitNodes_RangeFor) {
1133
1134 std::string CodePrefix = R"cpp(
1135 struct Container
1136 {
1137 int* begin() const;
1138 int* end() const;
1139 int* cbegin() const;
1140 int* cend() const;
1141 };
1142
1143 void foo()
1144 {
1145 const Container c;
1146 )cpp";
1147
1148 std::string BeginCallBefore = " c.begin();";
1149 std::string BeginCallAfter = " c.cbegin();";
1150
1151 std::string ForLoop = "for (auto i : c)";
1152 std::string BrokenForLoop = "for (auto i :.cbegin() c)";
1153
1154 std::string CodeSuffix = R"cpp(
1155 {
1156 }
1157 }
1158 )cpp";
1159
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;
1166
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");
1174
1175 auto RewriteRule =
1176 changeTo(node("constBeginCall"), cat(name("callTarget"), ".cbegin()"));
1177
1178 testRule(makeRule(traverse(TK_IgnoreUnlessSpelledInSource, MatchedRecord),
1179 RewriteRule),
1180 RewriteInput, ExpectedRewriteOutput);
1181
1182 testRule(makeRule(traverse(TK_AsIs, MatchedRecord), RewriteRule),
1183 RewriteInput, BrokenRewriteOutput);
1184 }
1185
TEST_F(TransformerTest,ImplicitNodes_ForStmt)1186 TEST_F(TransformerTest, ImplicitNodes_ForStmt) {
1187
1188 std::string CodePrefix = R"cpp(
1189 struct NonTrivial {
1190 NonTrivial() {}
1191 NonTrivial(NonTrivial&) {}
1192 NonTrivial& operator=(NonTrivial const&) { return *this; }
1193
1194 ~NonTrivial() {}
1195 };
1196
1197 struct ContainsArray {
1198 NonTrivial arr[2];
1199 ContainsArray& operator=(ContainsArray const&) = default;
1200 };
1201
1202 void testIt()
1203 {
1204 ContainsArray ca1;
1205 ContainsArray ca2;
1206 ca2 = ca1;
1207 )cpp";
1208
1209 auto CodeSuffix = "}";
1210
1211 auto LoopBody = R"cpp(
1212 {
1213
1214 }
1215 )cpp";
1216
1217 auto RawLoop = "for (auto i = 0; i != 5; ++i)";
1218
1219 auto RangeLoop = "for (auto i : boost::irange(5))";
1220
1221 // Expect to rewrite the raw loop to the ranged loop.
1222 // This works in TK_IgnoreUnlessSpelledInSource mode, but TK_AsIs
1223 // mode also matches the hidden for loop generated in the copy assignment
1224 // operator of ContainsArray. Transformer then fails to transform the code at
1225 // all.
1226
1227 auto RewriteInput =
1228 CodePrefix + RawLoop + LoopBody + RawLoop + LoopBody + CodeSuffix;
1229
1230 auto RewriteOutput =
1231 CodePrefix + RangeLoop + LoopBody + RangeLoop + LoopBody + CodeSuffix;
1232
1233 auto MatchedLoop = forStmt(
1234 has(declStmt(
1235 hasSingleDecl(varDecl(hasInitializer(integerLiteral(equals(0))))
1236 .bind("loopVar")))),
1237 has(binaryOperator(hasOperatorName("!="),
1238 hasLHS(ignoringImplicit(declRefExpr(
1239 to(varDecl(equalsBoundNode("loopVar")))))),
1240 hasRHS(expr().bind("upperBoundExpr")))),
1241 has(unaryOperator(hasOperatorName("++"),
1242 hasUnaryOperand(declRefExpr(
1243 to(varDecl(equalsBoundNode("loopVar"))))))
1244 .bind("incrementOp")));
1245
1246 auto RewriteRule =
1247 changeTo(transformer::enclose(node("loopVar"), node("incrementOp")),
1248 cat("auto ", name("loopVar"), " : boost::irange(",
1249 node("upperBoundExpr"), ")"));
1250
1251 testRule(makeRule(traverse(TK_IgnoreUnlessSpelledInSource, MatchedLoop),
1252 RewriteRule),
1253 RewriteInput, RewriteOutput);
1254
1255 testRuleFailure(makeRule(traverse(TK_AsIs, MatchedLoop), RewriteRule),
1256 RewriteInput);
1257
1258 }
1259
TEST_F(TransformerTest,ImplicitNodes_ForStmt2)1260 TEST_F(TransformerTest, ImplicitNodes_ForStmt2) {
1261
1262 std::string CodePrefix = R"cpp(
1263 struct NonTrivial {
1264 NonTrivial() {}
1265 NonTrivial(NonTrivial&) {}
1266 NonTrivial& operator=(NonTrivial const&) { return *this; }
1267
1268 ~NonTrivial() {}
1269 };
1270
1271 struct ContainsArray {
1272 NonTrivial arr[2];
1273 ContainsArray& operator=(ContainsArray const&) = default;
1274 };
1275
1276 void testIt()
1277 {
1278 ContainsArray ca1;
1279 ContainsArray ca2;
1280 ca2 = ca1;
1281 )cpp";
1282
1283 auto CodeSuffix = "}";
1284
1285 auto LoopBody = R"cpp(
1286 {
1287
1288 }
1289 )cpp";
1290
1291 auto RawLoop = "for (auto i = 0; i != 5; ++i)";
1292
1293 auto RangeLoop = "for (auto i : boost::irange(5))";
1294
1295 // Expect to rewrite the raw loop to the ranged loop.
1296 // This works in TK_IgnoreUnlessSpelledInSource mode, but TK_AsIs
1297 // mode also matches the hidden for loop generated in the copy assignment
1298 // operator of ContainsArray. Transformer then fails to transform the code at
1299 // all.
1300
1301 auto RewriteInput =
1302 CodePrefix + RawLoop + LoopBody + RawLoop + LoopBody + CodeSuffix;
1303
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")));
1318
1319 auto RewriteRule =
1320 changeTo(transformer::enclose(node("loopVar"), node("incrementOp")),
1321 cat("auto ", name("loopVar"), " : boost::irange(",
1322 node("upperBoundExpr"), ")"));
1323
1324 testRule(makeRule(traverse(TK_IgnoreUnlessSpelledInSource, MatchedLoop),
1325 RewriteRule),
1326 RewriteInput, RewriteOutput);
1327
1328 testRuleFailure(makeRule(traverse(TK_AsIs, MatchedLoop), RewriteRule),
1329 RewriteInput);
1330
1331 }
1332
TEST_F(TransformerTest,TemplateInstantiation)1333 TEST_F(TransformerTest, TemplateInstantiation) {
1334
1335 std::string NonTemplatesInput = R"cpp(
1336 struct S {
1337 int m_i;
1338 };
1339 )cpp";
1340 std::string NonTemplatesExpected = R"cpp(
1341 struct S {
1342 safe_int m_i;
1343 };
1344 )cpp";
1345
1346 std::string TemplatesInput = R"cpp(
1347 template<typename T>
1348 struct TemplStruct {
1349 TemplStruct() {}
1350 ~TemplStruct() {}
1351
1352 private:
1353 T m_t;
1354 };
1355
1356 void instantiate()
1357 {
1358 TemplStruct<int> ti;
1359 }
1360 )cpp";
1361
1362 auto MatchedField = fieldDecl(hasType(asString("int"))).bind("theField");
1363
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);
1369
1370 // In AsIs mode, template instantiations are modified, which is
1371 // often not desired:
1372
1373 std::string IncorrectTemplatesExpected = R"cpp(
1374 template<typename T>
1375 struct TemplStruct {
1376 TemplStruct() {}
1377 ~TemplStruct() {}
1378
1379 private:
1380 safe_int m_t;
1381 };
1382
1383 void instantiate()
1384 {
1385 TemplStruct<int> ti;
1386 }
1387 )cpp";
1388
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"), ";"))),
1392
1393 NonTemplatesInput + TemplatesInput,
1394 NonTemplatesExpected + IncorrectTemplatesExpected);
1395 }
1396
1397 // Transformation of macro source text when the change encompasses the entirety
1398 // of the expanded text.
TEST_F(TransformerTest,SimpleMacro)1399 TEST_F(TransformerTest, SimpleMacro) {
1400 std::string Input = R"cc(
1401 #define ZERO 0
1402 int f(string s) { return ZERO; }
1403 )cc";
1404 std::string Expected = R"cc(
1405 #define ZERO 0
1406 int f(string s) { return 999; }
1407 )cc";
1408
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);
1413 }
1414
1415 // Transformation of macro source text when the change encompasses the entirety
1416 // of the expanded text, for the case of function-style macros.
TEST_F(TransformerTest,FunctionMacro)1417 TEST_F(TransformerTest, FunctionMacro) {
1418 std::string Input = R"cc(
1419 #define MACRO(str) strlen((str).c_str())
1420 int f(string s) { return MACRO(s); }
1421 )cc";
1422 std::string Expected = R"cc(
1423 #define MACRO(str) strlen((str).c_str())
1424 int f(string s) { return REPLACED; }
1425 )cc";
1426
1427 testRule(ruleStrlenSize(), Input, Expected);
1428 }
1429
1430 // Tests that expressions in macro arguments can be rewritten.
TEST_F(TransformerTest,MacroArg)1431 TEST_F(TransformerTest, MacroArg) {
1432 std::string Input = R"cc(
1433 #define PLUS(e) e + 1
1434 int f(string s) { return PLUS(strlen(s.c_str())); }
1435 )cc";
1436 std::string Expected = R"cc(
1437 #define PLUS(e) e + 1
1438 int f(string s) { return PLUS(REPLACED); }
1439 )cc";
1440
1441 testRule(ruleStrlenSize(), Input, Expected);
1442 }
1443
1444 // Tests that expressions in macro arguments can be rewritten, even when the
1445 // macro call occurs inside another macro's definition.
TEST_F(TransformerTest,MacroArgInMacroDef)1446 TEST_F(TransformerTest, MacroArgInMacroDef) {
1447 std::string Input = R"cc(
1448 #define NESTED(e) e
1449 #define MACRO(str) NESTED(strlen((str).c_str()))
1450 int f(string s) { return MACRO(s); }
1451 )cc";
1452 std::string Expected = R"cc(
1453 #define NESTED(e) e
1454 #define MACRO(str) NESTED(strlen((str).c_str()))
1455 int f(string s) { return REPLACED; }
1456 )cc";
1457
1458 testRule(ruleStrlenSize(), Input, Expected);
1459 }
1460
1461 // Tests the corner case of the identity macro, specifically that it is
1462 // discarded in the rewrite rather than preserved (like PLUS is preserved in the
1463 // previous test). This behavior is of dubious value (and marked with a FIXME
1464 // in the code), but we test it to verify (and demonstrate) how this case is
1465 // handled.
TEST_F(TransformerTest,IdentityMacro)1466 TEST_F(TransformerTest, IdentityMacro) {
1467 std::string Input = R"cc(
1468 #define ID(e) e
1469 int f(string s) { return ID(strlen(s.c_str())); }
1470 )cc";
1471 std::string Expected = R"cc(
1472 #define ID(e) e
1473 int f(string s) { return REPLACED; }
1474 )cc";
1475
1476 testRule(ruleStrlenSize(), Input, Expected);
1477 }
1478
1479 // Tests that two changes in a single macro expansion do not lead to conflicts
1480 // in applying the changes.
TEST_F(TransformerTest,TwoChangesInOneMacroExpansion)1481 TEST_F(TransformerTest, TwoChangesInOneMacroExpansion) {
1482 std::string Input = R"cc(
1483 #define PLUS(a,b) (a) + (b)
1484 int f() { return PLUS(3, 4); }
1485 )cc";
1486 std::string Expected = R"cc(
1487 #define PLUS(a,b) (a) + (b)
1488 int f() { return PLUS(LIT, LIT); }
1489 )cc";
1490
1491 testRule(makeRule(integerLiteral(), changeTo(cat("LIT"))), Input, Expected);
1492 }
1493
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.
TEST_F(TransformerTest,MatchSpansMacroTextButChangeDoesNot)1496 TEST_F(TransformerTest, MatchSpansMacroTextButChangeDoesNot) {
1497 std::string Input = R"cc(
1498 #define PLUS_ONE(a) a + 1
1499 int f() { return PLUS_ONE(3); }
1500 )cc";
1501 std::string Expected = R"cc(
1502 #define PLUS_ONE(a) a + 1
1503 int f() { return PLUS_ONE(LIT); }
1504 )cc";
1505
1506 StringRef E = "expr";
1507 testRule(makeRule(binaryOperator(hasLHS(expr().bind(E))),
1508 changeTo(node(std::string(E)), cat("LIT"))),
1509 Input, Expected);
1510 }
1511
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.
TEST_F(TransformerTest,MatchSpansMacroTextButChangeDoesNotAnchoredInMacro)1514 TEST_F(TransformerTest, MatchSpansMacroTextButChangeDoesNotAnchoredInMacro) {
1515 std::string Input = R"cc(
1516 #define PLUS_ONE(a) 1 + a
1517 int f() { return PLUS_ONE(3); }
1518 )cc";
1519 std::string Expected = R"cc(
1520 #define PLUS_ONE(a) 1 + a
1521 int f() { return PLUS_ONE(LIT); }
1522 )cc";
1523
1524 StringRef E = "expr";
1525 testRule(makeRule(binaryOperator(hasRHS(expr().bind(E))),
1526 changeTo(node(std::string(E)), cat("LIT"))),
1527 Input, Expected);
1528 }
1529
1530 // No rewrite is applied when the changed text does not encompass the entirety
1531 // of the expanded text. That is, the edit would have to be applied to the
1532 // macro's definition to succeed and editing the expansion point would not
1533 // suffice.
TEST_F(TransformerTest,NoPartialRewriteOMacroExpansion)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";
1538
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);
1543 }
1544
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.
TEST_F(TransformerTest,NoPartialRewriteOfMacroExpansionForMacroArgs)1549 TEST_F(TransformerTest, NoPartialRewriteOfMacroExpansionForMacroArgs) {
1550 std::string Input = R"cc(
1551 #define NESTED(e) e
1552 #define MACRO(str) 1 + NESTED(strlen((str).c_str()))
1553 int f(string s) { return MACRO(s); }
1554 )cc";
1555
1556 testRule(ruleStrlenSize(), Input, Input);
1557 }
1558
1559 #if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST
1560 // Verifies that `Type` and `QualType` are not allowed as top-level matchers in
1561 // rules.
TEST(TransformerDeathTest,OrderedRuleTypes)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");
1566
1567 RewriteRule TypeRule = makeRule(arrayType(), changeTo(cat("T")));
1568 EXPECT_DEATH(transformer::detail::buildMatchers(TypeRule),
1569 "Matcher must be.*node matcher");
1570 }
1571 #endif
1572
1573 // Edits are able to span multiple files; in this case, a header and an
1574 // implementation file.
TEST_F(TransformerTest,MultipleFiles)1575 TEST_F(TransformerTest, MultipleFiles) {
1576 std::string Header = R"cc(void RemoveThisFunction();)cc";
1577 std::string Source = R"cc(#include "input.h"
1578 void RemoveThisFunction();)cc";
1579 Transformer T(
1580 makeRule(functionDecl(hasName("RemoveThisFunction")), changeTo(cat(""))),
1581 consumer());
1582 T.registerMatchers(&MatchFinder);
1583 auto Factory = newFrontendActionFactory(&MatchFinder);
1584 EXPECT_TRUE(runToolOnCodeWithArgs(
1585 Factory->create(), Source, std::vector<std::string>(), "input.cc",
1586 "clang-tool", std::make_shared<PCHContainerOperations>(),
1587 {{"input.h", Header}}));
1588
1589 std::sort(Changes.begin(), Changes.end(),
1590 [](const AtomicChange &L, const AtomicChange &R) {
1591 return L.getFilePath() < R.getFilePath();
1592 });
1593
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), "");
1603
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"));
1612 }
1613
TEST_F(TransformerTest,AddIncludeMultipleFiles)1614 TEST_F(TransformerTest, AddIncludeMultipleFiles) {
1615 std::string Header = R"cc(void RemoveThisFunction();)cc";
1616 std::string Source = R"cc(#include "input.h"
1617 void Foo() {RemoveThisFunction();})cc";
1618 Transformer T(
1619 makeRule(callExpr(callee(
1620 functionDecl(hasName("RemoveThisFunction")).bind("fun"))),
1621 addInclude(node("fun"), "header.h")),
1622 consumer());
1623 T.registerMatchers(&MatchFinder);
1624 auto Factory = newFrontendActionFactory(&MatchFinder);
1625 EXPECT_TRUE(runToolOnCodeWithArgs(
1626 Factory->create(), Source, std::vector<std::string>(), "input.cc",
1627 "clang-tool", std::make_shared<PCHContainerOperations>(),
1628 {{"input.h", Header}}));
1629
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));
1640 }
1641 } // namespace
1642