[clang] Allow usage of applyFirst with rewriteDescendants (PR #117658)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Nov 25 17:54:00 PST 2024
https://github.com/SherAndrei created https://github.com/llvm/llvm-project/pull/117658
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.
>From 9634a781ff6eec0e378c30eb6811df1d17bac1cb Mon Sep 17 00:00:00 2001
From: SherAndrei <welldryus at gmail.com>
Date: Tue, 26 Nov 2024 03:30:46 +0300
Subject: [PATCH] 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.
---
clang/lib/Tooling/Transformer/RewriteRule.cpp | 6 ++-
clang/unittests/Tooling/TransformerTest.cpp | 43 +++++++++++++++++++
2 files changed, 47 insertions(+), 2 deletions(-)
diff --git a/clang/lib/Tooling/Transformer/RewriteRule.cpp b/clang/lib/Tooling/Transformer/RewriteRule.cpp
index eefddc34940487..196249260ec8b4 100644
--- a/clang/lib/Tooling/Transformer/RewriteRule.cpp
+++ b/clang/lib/Tooling/Transformer/RewriteRule.cpp
@@ -382,9 +382,10 @@ static std::vector<DynTypedMatcher> taggedMatchers(
std::vector<DynTypedMatcher> Matchers;
Matchers.reserve(Cases.size());
for (const auto &Case : Cases) {
- std::string Tag = (TagBase + Twine(Case.first)).str();
// HACK: Many matchers are not bindable, so ensure that tryBind will work.
DynTypedMatcher BoundMatcher(Case.second.Matcher);
+ const auto [_, ID] = BoundMatcher.getID();
+ std::string Tag = (TagBase + Twine(ID)).str();
BoundMatcher.setAllowBind(true);
auto M = *BoundMatcher.tryBind(Tag);
Matchers.push_back(!M.getTraversalKind()
@@ -469,7 +470,8 @@ size_t transformer::detail::findSelectedCase(const MatchResult &Result,
auto &NodesMap = Result.Nodes.getMap();
for (size_t i = 0, N = Rule.Cases.size(); i < N; ++i) {
- std::string Tag = ("Tag" + Twine(i)).str();
+ const auto [_, ID] = Rule.Cases[i].Matcher.getID();
+ std::string Tag = ("Tag" + Twine(ID)).str();
if (NodesMap.find(Tag) != NodesMap.end())
return i;
}
diff --git a/clang/unittests/Tooling/TransformerTest.cpp b/clang/unittests/Tooling/TransformerTest.cpp
index cbd84ab794a49a..0404c81862468f 100644
--- a/clang/unittests/Tooling/TransformerTest.cpp
+++ b/clang/unittests/Tooling/TransformerTest.cpp
@@ -605,6 +605,49 @@ TEST_F(TransformerTest, RewriteDescendantsReferToParentBinding) {
Input, Expected);
}
+TEST_F(TransformerTest, RewriteDescendantsApplyFirstOrderedRuleUnrelated) {
+ std::string Input = "int f(int x) { int y = x; return x; }";
+ std::string Expected = "int f(int x) { char y = 3; return 3; }";
+ auto IntToChar = makeRule(typeLoc(loc(qualType(isInteger(), builtinType()))),
+ changeTo(cat("char")));
+ auto InlineX =
+ makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
+ testRule(
+ makeRule(functionDecl(hasName("f"), hasBody(stmt().bind("body"))),
+ rewriteDescendants("body", applyFirst({InlineX, IntToChar}))),
+ Input, Expected);
+}
+
+TEST_F(TransformerTest, RewriteDescendantsApplyFirstOrderedRuleRelated) {
+ std::string Input = "int f(int x) { int y = x; return x; }";
+ std::string Expected = "int f(int x) { int y = 3; return y; }";
+ auto ReturnY = makeRule(
+ traverse(TK_IgnoreUnlessSpelledInSource,
+ declRefExpr(to(varDecl(hasName("x"))), hasParent(returnStmt()))),
+ changeTo(cat("y")));
+ auto InlineX = makeRule(traverse(TK_IgnoreUnlessSpelledInSource,
+ declRefExpr(to(varDecl(hasName("x"))))),
+ changeTo(cat("3")));
+ testRule(makeRule(functionDecl(hasName("f"), hasBody(stmt().bind("body"))),
+ rewriteDescendants("body", applyFirst({ReturnY, InlineX}))),
+ Input, Expected);
+}
+
+TEST_F(TransformerTest, RewriteDescendantsApplyFirstOrderedRuleRelatedSwapped) {
+ std::string Input = "int f(int x) { int y = x; return x; }";
+ std::string Expected = "int f(int x) { int y = 3; return 3; }";
+ auto ReturnY = makeRule(
+ traverse(TK_IgnoreUnlessSpelledInSource,
+ declRefExpr(to(varDecl(hasName("x"))), hasParent(returnStmt()))),
+ changeTo(cat("y")));
+ auto InlineX = makeRule(traverse(TK_IgnoreUnlessSpelledInSource,
+ declRefExpr(to(varDecl(hasName("x"))))),
+ changeTo(cat("3")));
+ testRule(makeRule(functionDecl(hasName("f"), hasBody(stmt().bind("body"))),
+ rewriteDescendants("body", applyFirst({InlineX, ReturnY}))),
+ Input, Expected);
+}
+
TEST_F(TransformerTest, RewriteDescendantsUnboundNode) {
std::string Input =
"int f(int x) { int y = x; { int z = x * x; } return x; }";
More information about the cfe-commits
mailing list