aboutsummaryrefslogtreecommitdiff
path: root/clang/unittests/Tooling/TransformerTest.cpp
diff options
context:
space:
mode:
authorYitzhak Mandelbaum <yitzhakm@google.com>2020-09-02 14:10:22 +0000
committerYitzhak Mandelbaum <yitzhakm@google.com>2020-09-03 14:39:50 +0000
commitd4f3903131292d36b3bc22c28798b8e9dae20af6 (patch)
treefc55d686ec64ecdd20060eb6abea25fa00130bad /clang/unittests/Tooling/TransformerTest.cpp
parent58afaecdc23148219d18d566dbaf79f37950f716 (diff)
downloadllvm-d4f3903131292d36b3bc22c28798b8e9dae20af6.zip
llvm-d4f3903131292d36b3bc22c28798b8e9dae20af6.tar.gz
llvm-d4f3903131292d36b3bc22c28798b8e9dae20af6.tar.bz2
[libTooling] Provide overloads of `rewriteDescendants` that operate directly on an AST node.
The new overloads apply directly to a node, like the `clang::ast_matchers::match` functions, Rather than generating an `EditGenerator` combinator. Differential Revision: https://reviews.llvm.org/D87031
Diffstat (limited to 'clang/unittests/Tooling/TransformerTest.cpp')
-rw-r--r--clang/unittests/Tooling/TransformerTest.cpp83
1 files changed, 83 insertions, 0 deletions
diff --git a/clang/unittests/Tooling/TransformerTest.cpp b/clang/unittests/Tooling/TransformerTest.cpp
index 2c9bd7d..a8d6d3d 100644
--- a/clang/unittests/Tooling/TransformerTest.cpp
+++ b/clang/unittests/Tooling/TransformerTest.cpp
@@ -25,6 +25,7 @@ using ::testing::ElementsAre;
using ::testing::IsEmpty;
using transformer::cat;
using transformer::changeTo;
+using transformer::rewriteDescendants;
using transformer::RewriteRule;
constexpr char KHeaderContents[] = R"cc(
@@ -568,6 +569,88 @@ TEST_F(TransformerTest, RewriteDescendantsInvalidNodeType) {
EXPECT_EQ(ErrorCount, 1);
}
+//
+// We include one test per typed overload. We don't test extensively since that
+// is already covered by the tests above.
+//
+
+TEST_F(TransformerTest, RewriteDescendantsTypedStmt) {
+ // Add an unrelated definition to the header that also has a variable named
+ // "x", to test that the rewrite is limited to the scope we intend.
+ appendToHeader(R"cc(int g(int x) { return x; })cc");
+ std::string Input =
+ "int f(int x) { int y = x; { int z = x * x; } return x; }";
+ std::string Expected =
+ "int f(int x) { int y = 3; { int z = 3 * 3; } return 3; }";
+ auto InlineX =
+ makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
+ testRule(makeRule(functionDecl(hasName("f"), hasBody(stmt().bind("body"))),
+ [&InlineX](const MatchFinder::MatchResult &R) {
+ const auto *Node = R.Nodes.getNodeAs<Stmt>("body");
+ assert(Node != nullptr && "body must be bound");
+ return transformer::detail::rewriteDescendants(
+ *Node, InlineX, R);
+ }),
+ Input, Expected);
+}
+
+TEST_F(TransformerTest, RewriteDescendantsTypedDecl) {
+ std::string Input =
+ "int f(int x) { int y = x; { int z = x * x; } return x; }";
+ std::string Expected =
+ "int f(int x) { int y = 3; { int z = 3 * 3; } return 3; }";
+ auto InlineX =
+ makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
+ testRule(makeRule(functionDecl(hasName("f")).bind("fun"),
+ [&InlineX](const MatchFinder::MatchResult &R) {
+ const auto *Node = R.Nodes.getNodeAs<Decl>("fun");
+ assert(Node != nullptr && "fun must be bound");
+ return transformer::detail::rewriteDescendants(
+ *Node, InlineX, R);
+ }),
+ Input, Expected);
+}
+
+TEST_F(TransformerTest, RewriteDescendantsTypedTypeLoc) {
+ std::string Input = "int f(int *x) { return *x; }";
+ std::string Expected = "int f(char *x) { return *x; }";
+ auto IntToChar =
+ makeRule(typeLoc(loc(qualType(isInteger(), builtinType()))).bind("loc"),
+ changeTo(cat("char")));
+ testRule(
+ makeRule(
+ functionDecl(
+ hasName("f"),
+ hasParameter(0, varDecl(hasTypeLoc(typeLoc().bind("parmType"))))),
+ [&IntToChar](const MatchFinder::MatchResult &R) {
+ const auto *Node = R.Nodes.getNodeAs<TypeLoc>("parmType");
+ assert(Node != nullptr && "parmType must be bound");
+ return transformer::detail::rewriteDescendants(*Node, IntToChar, R);
+ }),
+ Input, Expected);
+}
+
+TEST_F(TransformerTest, RewriteDescendantsTypedDynTyped) {
+ // Add an unrelated definition to the header that also has a variable named
+ // "x", to test that the rewrite is limited to the scope we intend.
+ appendToHeader(R"cc(int g(int x) { return x; })cc");
+ std::string Input =
+ "int f(int x) { int y = x; { int z = x * x; } return x; }";
+ std::string Expected =
+ "int f(int x) { int y = 3; { int z = 3 * 3; } return 3; }";
+ auto InlineX =
+ makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
+ testRule(
+ makeRule(functionDecl(hasName("f"), hasBody(stmt().bind("body"))),
+ [&InlineX](const MatchFinder::MatchResult &R) {
+ auto It = R.Nodes.getMap().find("body");
+ assert(It != R.Nodes.getMap().end() && "body must be bound");
+ return transformer::detail::rewriteDescendants(It->second,
+ InlineX, R);
+ }),
+ Input, Expected);
+}
+
TEST_F(TransformerTest, InsertBeforeEdit) {
std::string Input = R"cc(
int f() {