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 <welldr...@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; }"; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits