Skip to content

Commit 5eea966

Browse files
committed
[clang][transformer] Allow usage of applyFirst with rewriteDescendants
Without these changes a clash appears between a Tag, which is bound to enclosing match, and a Tag, which is associated with first Case of applyFirst in rewriteDescendands. We fix this by making sure that associated Tags are unique and deterministic as they are intend to be.
1 parent 31bde71 commit 5eea966

File tree

2 files changed

+47
-2
lines changed

2 files changed

+47
-2
lines changed

clang/lib/Tooling/Transformer/RewriteRule.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -382,9 +382,10 @@ static std::vector<DynTypedMatcher> taggedMatchers(
382382
std::vector<DynTypedMatcher> Matchers;
383383
Matchers.reserve(Cases.size());
384384
for (const auto &Case : Cases) {
385-
std::string Tag = (TagBase + Twine(Case.first)).str();
386385
// HACK: Many matchers are not bindable, so ensure that tryBind will work.
387386
DynTypedMatcher BoundMatcher(Case.second.Matcher);
387+
const auto [_, ID] = BoundMatcher.getID();
388+
std::string Tag = (TagBase + Twine(ID)).str();
388389
BoundMatcher.setAllowBind(true);
389390
auto M = *BoundMatcher.tryBind(Tag);
390391
Matchers.push_back(!M.getTraversalKind()
@@ -469,7 +470,8 @@ size_t transformer::detail::findSelectedCase(const MatchResult &Result,
469470

470471
auto &NodesMap = Result.Nodes.getMap();
471472
for (size_t i = 0, N = Rule.Cases.size(); i < N; ++i) {
472-
std::string Tag = ("Tag" + Twine(i)).str();
473+
const auto [_, ID] = Rule.Cases[i].Matcher.getID();
474+
std::string Tag = ("Tag" + Twine(ID)).str();
473475
if (NodesMap.find(Tag) != NodesMap.end())
474476
return i;
475477
}

clang/unittests/Tooling/TransformerTest.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -605,6 +605,49 @@ TEST_F(TransformerTest, RewriteDescendantsReferToParentBinding) {
605605
Input, Expected);
606606
}
607607

608+
TEST_F(TransformerTest, RewriteDescendantsApplyFirstOrderedRuleUnrelated) {
609+
std::string Input = "int f(int x) { int y = x; return x; }";
610+
std::string Expected = "int f(int x) { char y = 3; return 3; }";
611+
auto IntToChar = makeRule(typeLoc(loc(qualType(isInteger(), builtinType()))),
612+
changeTo(cat("char")));
613+
auto InlineX =
614+
makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
615+
testRule(
616+
makeRule(functionDecl(hasName("f"), hasBody(stmt().bind("body"))),
617+
rewriteDescendants("body", applyFirst({InlineX, IntToChar}))),
618+
Input, Expected);
619+
}
620+
621+
TEST_F(TransformerTest, RewriteDescendantsApplyFirstOrderedRuleRelated) {
622+
std::string Input = "int f(int x) { int y = x; return x; }";
623+
std::string Expected = "int f(int x) { int y = 3; return y; }";
624+
auto ReturnY = makeRule(
625+
traverse(TK_IgnoreUnlessSpelledInSource,
626+
declRefExpr(to(varDecl(hasName("x"))), hasParent(returnStmt()))),
627+
changeTo(cat("y")));
628+
auto InlineX = makeRule(traverse(TK_IgnoreUnlessSpelledInSource,
629+
declRefExpr(to(varDecl(hasName("x"))))),
630+
changeTo(cat("3")));
631+
testRule(makeRule(functionDecl(hasName("f"), hasBody(stmt().bind("body"))),
632+
rewriteDescendants("body", applyFirst({ReturnY, InlineX}))),
633+
Input, Expected);
634+
}
635+
636+
TEST_F(TransformerTest, RewriteDescendantsApplyFirstOrderedRuleRelatedSwapped) {
637+
std::string Input = "int f(int x) { int y = x; return x; }";
638+
std::string Expected = "int f(int x) { int y = 3; return 3; }";
639+
auto ReturnY = makeRule(
640+
traverse(TK_IgnoreUnlessSpelledInSource,
641+
declRefExpr(to(varDecl(hasName("x"))), hasParent(returnStmt()))),
642+
changeTo(cat("y")));
643+
auto InlineX = makeRule(traverse(TK_IgnoreUnlessSpelledInSource,
644+
declRefExpr(to(varDecl(hasName("x"))))),
645+
changeTo(cat("3")));
646+
testRule(makeRule(functionDecl(hasName("f"), hasBody(stmt().bind("body"))),
647+
rewriteDescendants("body", applyFirst({InlineX, ReturnY}))),
648+
Input, Expected);
649+
}
650+
608651
TEST_F(TransformerTest, RewriteDescendantsUnboundNode) {
609652
std::string Input =
610653
"int f(int x) { int y = x; { int z = x * x; } return x; }";

0 commit comments

Comments
 (0)