aboutsummaryrefslogtreecommitdiff
path: root/clang/unittests/Tooling/TransformerTest.cpp
diff options
context:
space:
mode:
authorYitzhak Mandelbaum <yitzhakm@google.com>2020-07-24 13:27:51 +0000
committerYitzhak Mandelbaum <yitzhakm@google.com>2020-07-24 14:38:17 +0000
commitc332a984aefc6f8a6b44fd3687a5bbce3f8f035c (patch)
treecd8d5d8e4847fb7944e87a9c4dc1a4eb30c19d22 /clang/unittests/Tooling/TransformerTest.cpp
parent4ef2e594d5be2e0e6d4446c8082b15466bc7ffcb (diff)
downloadllvm-c332a984aefc6f8a6b44fd3687a5bbce3f8f035c.zip
llvm-c332a984aefc6f8a6b44fd3687a5bbce3f8f035c.tar.gz
llvm-c332a984aefc6f8a6b44fd3687a5bbce3f8f035c.tar.bz2
[libTooling] Add an `EditGenerator` that applies a rule throughout a bound node.
The new combinator, `rewriteDescendants`, applies a rewrite rule to all descendants of a specified bound node. That rewrite rule can refer to nodes bound by the parent, both in the matcher and in the edits. Reviewed By: gribozavr2 Differential Revision: https://reviews.llvm.org/D84409
Diffstat (limited to 'clang/unittests/Tooling/TransformerTest.cpp')
-rw-r--r--clang/unittests/Tooling/TransformerTest.cpp118
1 files changed, 117 insertions, 1 deletions
diff --git a/clang/unittests/Tooling/TransformerTest.cpp b/clang/unittests/Tooling/TransformerTest.cpp
index 1a68eb1..77fd380 100644
--- a/clang/unittests/Tooling/TransformerTest.cpp
+++ b/clang/unittests/Tooling/TransformerTest.cpp
@@ -114,7 +114,9 @@ protected:
if (C) {
Changes.push_back(std::move(*C));
} else {
- consumeError(C.takeError());
+ // FIXME: stash this error rather then printing.
+ llvm::errs() << "Error generating changes: "
+ << llvm::toString(C.takeError()) << "\n";
++ErrorCount;
}
};
@@ -414,6 +416,120 @@ TEST_F(TransformerTest, ShrinkTo) {
Input, Expected);
}
+// Rewrite various Stmts inside a Decl.
+TEST_F(TransformerTest, RewriteDescendantsDeclChangeStmt) {
+ 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"),
+ rewriteDescendants("fun", InlineX)),
+ Input, Expected);
+}
+
+// Rewrite various TypeLocs inside a Decl.
+TEST_F(TransformerTest, RewriteDescendantsDeclChangeTypeLoc) {
+ std::string Input = "int f(int *x) { return *x; }";
+ std::string Expected = "char f(char *x) { return *x; }";
+ auto IntToChar = makeRule(typeLoc(loc(qualType(isInteger(), builtinType()))),
+ changeTo(cat("char")));
+ testRule(makeRule(functionDecl(hasName("f")).bind("fun"),
+ rewriteDescendants("fun", IntToChar)),
+ Input, Expected);
+}
+
+TEST_F(TransformerTest, RewriteDescendantsStmt) {
+ // 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"))),
+ rewriteDescendants("body", InlineX)),
+ Input, Expected);
+}
+
+TEST_F(TransformerTest, RewriteDescendantsStmtWithAdditionalChange) {
+ std::string Input =
+ "int f(int x) { int y = x; { int z = x * x; } return x; }";
+ std::string Expected =
+ "int newName(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"))).bind("f"),
+ flatten(changeTo(name("f"), cat("newName")),
+ rewriteDescendants("body", InlineX))),
+ Input, Expected);
+}
+
+TEST_F(TransformerTest, RewriteDescendantsTypeLoc) {
+ 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"))))),
+ rewriteDescendants("parmType", IntToChar)),
+ Input, Expected);
+}
+
+TEST_F(TransformerTest, RewriteDescendantsReferToParentBinding) {
+ std::string Input =
+ "int f(int p) { int y = p; { int z = p * p; } return p; }";
+ std::string Expected =
+ "int f(int p) { int y = 3; { int z = 3 * 3; } return 3; }";
+ std::string VarId = "var";
+ auto InlineVar = makeRule(declRefExpr(to(varDecl(equalsBoundNode(VarId)))),
+ changeTo(cat("3")));
+ testRule(makeRule(functionDecl(hasName("f"),
+ hasParameter(0, varDecl().bind(VarId)))
+ .bind("fun"),
+ rewriteDescendants("fun", InlineVar)),
+ Input, Expected);
+}
+
+TEST_F(TransformerTest, RewriteDescendantsUnboundNode) {
+ std::string Input =
+ "int f(int x) { int y = x; { int z = x * x; } return x; }";
+ auto InlineX =
+ makeRule(declRefExpr(to(varDecl(hasName("x")))), changeTo(cat("3")));
+ Transformer T(makeRule(functionDecl(hasName("f")),
+ rewriteDescendants("UNBOUND", InlineX)),
+ consumer());
+ T.registerMatchers(&MatchFinder);
+ EXPECT_FALSE(rewrite(Input));
+ EXPECT_THAT(Changes, IsEmpty());
+ EXPECT_EQ(ErrorCount, 1);
+}
+
+TEST_F(TransformerTest, RewriteDescendantsInvalidNodeType) {
+ std::string Input =
+ "int f(int x) { int y = x; { int z = x * x; } return x; }";
+ auto IntToChar =
+ makeRule(qualType(isInteger(), builtinType()), changeTo(cat("char")));
+ Transformer T(
+ makeRule(functionDecl(
+ hasName("f"),
+ hasParameter(0, varDecl(hasType(qualType().bind("type"))))),
+ rewriteDescendants("type", IntToChar)),
+ consumer());
+ T.registerMatchers(&MatchFinder);
+ EXPECT_FALSE(rewrite(Input));
+ EXPECT_THAT(Changes, IsEmpty());
+ EXPECT_EQ(ErrorCount, 1);
+}
+
TEST_F(TransformerTest, InsertBeforeEdit) {
std::string Input = R"cc(
int f() {