[PATCH] D69613: [libTooling] Simplify type structure of `Stencil`s.

2019-11-06 Thread Yitzhak Mandelbaum via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rGce2b5cb6decb: [libTooling] Simplify type structure of 
`Stencil`s. (authored by ymandel).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D69613/new/

https://reviews.llvm.org/D69613

Files:
  clang/include/clang/Tooling/Transformer/Stencil.h
  clang/lib/Tooling/Transformer/Stencil.cpp
  clang/unittests/Tooling/StencilTest.cpp

Index: clang/unittests/Tooling/StencilTest.cpp
===
--- clang/unittests/Tooling/StencilTest.cpp
+++ clang/unittests/Tooling/StencilTest.cpp
@@ -96,7 +96,7 @@
  .bind("expr")))
 .bind("stmt"));
 ASSERT_TRUE(StmtMatch);
-if (auto ResultOrErr = Stencil.eval(StmtMatch->Result)) {
+if (auto ResultOrErr = Stencil->eval(StmtMatch->Result)) {
   ADD_FAILURE() << "Expected failure but succeeded: " << *ResultOrErr;
 } else {
   auto Err = llvm::handleErrors(ResultOrErr.takeError(),
@@ -131,11 +131,12 @@
   // Invert the if-then-else.
   auto Stencil = cat("if (!", node(Condition), ") ", statement(Else), " else ",
  statement(Then));
-  EXPECT_THAT_EXPECTED(Stencil.eval(StmtMatch->Result),
+  EXPECT_THAT_EXPECTED(Stencil->eval(StmtMatch->Result),
HasValue("if (!true) return 0; else return 1;"));
 }
 
-TEST_F(StencilTest, SingleStatementCallOperator) {
+// Tests `stencil`.
+TEST_F(StencilTest, StencilFactoryFunction) {
   StringRef Condition("C"), Then("T"), Else("E");
   const std::string Snippet = R"cc(
 if (true)
@@ -148,9 +149,9 @@
   hasThen(stmt().bind(Then)), hasElse(stmt().bind(Else;
   ASSERT_TRUE(StmtMatch);
   // Invert the if-then-else.
-  Stencil S = cat("if (!", node(Condition), ") ", statement(Else), " else ",
-  statement(Then));
-  EXPECT_THAT_EXPECTED(S(StmtMatch->Result),
+  auto Consumer = cat("if (!", node(Condition), ") ", statement(Else), " else ",
+  statement(Then));
+  EXPECT_THAT_EXPECTED(Consumer(StmtMatch->Result),
HasValue("if (!true) return 0; else return 1;"));
 }
 
@@ -165,7 +166,7 @@
  hasThen(stmt().bind("a2";
   ASSERT_TRUE(StmtMatch);
   auto Stencil = cat("if(!", node("a1"), ") ", node("UNBOUND"), ";");
-  auto ResultOrErr = Stencil.eval(StmtMatch->Result);
+  auto ResultOrErr = Stencil->eval(StmtMatch->Result);
   EXPECT_TRUE(llvm::errorToBool(ResultOrErr.takeError()))
   << "Expected unbound node, got " << *ResultOrErr;
 }
@@ -176,14 +177,14 @@
   StringRef Expected) {
   auto StmtMatch = matchStmt(Snippet, expr().bind(Id));
   ASSERT_TRUE(StmtMatch);
-  EXPECT_THAT_EXPECTED(Stencil.eval(StmtMatch->Result), HasValue(Expected));
+  EXPECT_THAT_EXPECTED(Stencil->eval(StmtMatch->Result), HasValue(Expected));
 }
 
 void testFailure(StringRef Id, StringRef Snippet, const Stencil ,
  testing::Matcher MessageMatcher) {
   auto StmtMatch = matchStmt(Snippet, expr().bind(Id));
   ASSERT_TRUE(StmtMatch);
-  EXPECT_THAT_EXPECTED(Stencil.eval(StmtMatch->Result),
+  EXPECT_THAT_EXPECTED(Stencil->eval(StmtMatch->Result),
Failed(testing::Property(
::getMessage, MessageMatcher)));
 }
@@ -195,28 +196,28 @@
 
 TEST_F(StencilTest, IfBoundOpBound) {
   StringRef Id = "id";
-  testExpr(Id, "3;", cat(ifBound(Id, text("5"), text("7"))), "5");
+  testExpr(Id, "3;", ifBound(Id, text("5"), text("7")), "5");
 }
 
 TEST_F(StencilTest, IfBoundOpUnbound) {
   StringRef Id = "id";
-  testExpr(Id, "3;", cat(ifBound("other", text("5"), text("7"))), "7");
+  testExpr(Id, "3;", ifBound("other", text("5"), text("7")), "7");
 }
 
 TEST_F(StencilTest, ExpressionOpNoParens) {
   StringRef Id = "id";
-  testExpr(Id, "3;", cat(expression(Id)), "3");
+  testExpr(Id, "3;", expression(Id), "3");
 }
 
 // Don't parenthesize a parens expression.
 TEST_F(StencilTest, ExpressionOpNoParensParens) {
   StringRef Id = "id";
-  testExpr(Id, "(3);", cat(expression(Id)), "(3)");
+  testExpr(Id, "(3);", expression(Id), "(3)");
 }
 
 TEST_F(StencilTest, ExpressionOpBinaryOpParens) {
   StringRef Id = "id";
-  testExpr(Id, "3+4;", cat(expression(Id)), "(3+4)");
+  testExpr(Id, "3+4;", expression(Id), "(3+4)");
 }
 
 // `expression` shares code with other ops, so we get sufficient coverage of the
@@ -224,33 +225,33 @@
 // tests should be added.
 TEST_F(StencilTest, ExpressionOpUnbound) {
   StringRef Id = "id";
-  testFailure(Id, "3;", cat(expression("ACACA")),
+  testFailure(Id, "3;", expression("ACACA"),
   AllOf(HasSubstr("ACACA"), HasSubstr("not bound")));
 }
 
 TEST_F(StencilTest, DerefPointer) {
   StringRef Id = "id";
-  testExpr(Id, "int *x; x;", cat(deref(Id)), "*x");
+  testExpr(Id, "int *x; x;", deref(Id), "*x");
 }
 
 TEST_F(StencilTest, DerefBinOp) {
   StringRef Id = "id";
- 

[PATCH] D69613: [libTooling] Simplify type structure of `Stencil`s.

2019-11-01 Thread Yitzhak Mandelbaum via Phabricator via cfe-commits
ymandel updated this revision to Diff 227478.
ymandel marked an inline comment as done.
ymandel added a comment.

remove stray comments; clang-format


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D69613/new/

https://reviews.llvm.org/D69613

Files:
  clang/include/clang/Tooling/Transformer/Stencil.h
  clang/lib/Tooling/Transformer/Stencil.cpp
  clang/unittests/Tooling/StencilTest.cpp

Index: clang/unittests/Tooling/StencilTest.cpp
===
--- clang/unittests/Tooling/StencilTest.cpp
+++ clang/unittests/Tooling/StencilTest.cpp
@@ -96,7 +96,7 @@
  .bind("expr")))
 .bind("stmt"));
 ASSERT_TRUE(StmtMatch);
-if (auto ResultOrErr = Stencil.eval(StmtMatch->Result)) {
+if (auto ResultOrErr = Stencil->eval(StmtMatch->Result)) {
   ADD_FAILURE() << "Expected failure but succeeded: " << *ResultOrErr;
 } else {
   auto Err = llvm::handleErrors(ResultOrErr.takeError(),
@@ -131,11 +131,12 @@
   // Invert the if-then-else.
   auto Stencil = cat("if (!", node(Condition), ") ", statement(Else), " else ",
  statement(Then));
-  EXPECT_THAT_EXPECTED(Stencil.eval(StmtMatch->Result),
+  EXPECT_THAT_EXPECTED(Stencil->eval(StmtMatch->Result),
HasValue("if (!true) return 0; else return 1;"));
 }
 
-TEST_F(StencilTest, SingleStatementCallOperator) {
+// Tests `stencil`.
+TEST_F(StencilTest, StencilFactoryFunction) {
   StringRef Condition("C"), Then("T"), Else("E");
   const std::string Snippet = R"cc(
 if (true)
@@ -148,9 +149,9 @@
   hasThen(stmt().bind(Then)), hasElse(stmt().bind(Else;
   ASSERT_TRUE(StmtMatch);
   // Invert the if-then-else.
-  Stencil S = cat("if (!", node(Condition), ") ", statement(Else), " else ",
-  statement(Then));
-  EXPECT_THAT_EXPECTED(S(StmtMatch->Result),
+  auto Consumer = cat("if (!", node(Condition), ") ", statement(Else), " else ",
+  statement(Then));
+  EXPECT_THAT_EXPECTED(Consumer(StmtMatch->Result),
HasValue("if (!true) return 0; else return 1;"));
 }
 
@@ -165,7 +166,7 @@
  hasThen(stmt().bind("a2";
   ASSERT_TRUE(StmtMatch);
   auto Stencil = cat("if(!", node("a1"), ") ", node("UNBOUND"), ";");
-  auto ResultOrErr = Stencil.eval(StmtMatch->Result);
+  auto ResultOrErr = Stencil->eval(StmtMatch->Result);
   EXPECT_TRUE(llvm::errorToBool(ResultOrErr.takeError()))
   << "Expected unbound node, got " << *ResultOrErr;
 }
@@ -176,14 +177,14 @@
   StringRef Expected) {
   auto StmtMatch = matchStmt(Snippet, expr().bind(Id));
   ASSERT_TRUE(StmtMatch);
-  EXPECT_THAT_EXPECTED(Stencil.eval(StmtMatch->Result), HasValue(Expected));
+  EXPECT_THAT_EXPECTED(Stencil->eval(StmtMatch->Result), HasValue(Expected));
 }
 
 void testFailure(StringRef Id, StringRef Snippet, const Stencil ,
  testing::Matcher MessageMatcher) {
   auto StmtMatch = matchStmt(Snippet, expr().bind(Id));
   ASSERT_TRUE(StmtMatch);
-  EXPECT_THAT_EXPECTED(Stencil.eval(StmtMatch->Result),
+  EXPECT_THAT_EXPECTED(Stencil->eval(StmtMatch->Result),
Failed(testing::Property(
::getMessage, MessageMatcher)));
 }
@@ -195,28 +196,28 @@
 
 TEST_F(StencilTest, IfBoundOpBound) {
   StringRef Id = "id";
-  testExpr(Id, "3;", cat(ifBound(Id, text("5"), text("7"))), "5");
+  testExpr(Id, "3;", ifBound(Id, text("5"), text("7")), "5");
 }
 
 TEST_F(StencilTest, IfBoundOpUnbound) {
   StringRef Id = "id";
-  testExpr(Id, "3;", cat(ifBound("other", text("5"), text("7"))), "7");
+  testExpr(Id, "3;", ifBound("other", text("5"), text("7")), "7");
 }
 
 TEST_F(StencilTest, ExpressionOpNoParens) {
   StringRef Id = "id";
-  testExpr(Id, "3;", cat(expression(Id)), "3");
+  testExpr(Id, "3;", expression(Id), "3");
 }
 
 // Don't parenthesize a parens expression.
 TEST_F(StencilTest, ExpressionOpNoParensParens) {
   StringRef Id = "id";
-  testExpr(Id, "(3);", cat(expression(Id)), "(3)");
+  testExpr(Id, "(3);", expression(Id), "(3)");
 }
 
 TEST_F(StencilTest, ExpressionOpBinaryOpParens) {
   StringRef Id = "id";
-  testExpr(Id, "3+4;", cat(expression(Id)), "(3+4)");
+  testExpr(Id, "3+4;", expression(Id), "(3+4)");
 }
 
 // `expression` shares code with other ops, so we get sufficient coverage of the
@@ -224,33 +225,33 @@
 // tests should be added.
 TEST_F(StencilTest, ExpressionOpUnbound) {
   StringRef Id = "id";
-  testFailure(Id, "3;", cat(expression("ACACA")),
+  testFailure(Id, "3;", expression("ACACA"),
   AllOf(HasSubstr("ACACA"), HasSubstr("not bound")));
 }
 
 TEST_F(StencilTest, DerefPointer) {
   StringRef Id = "id";
-  testExpr(Id, "int *x; x;", cat(deref(Id)), "*x");
+  testExpr(Id, "int *x; x;", deref(Id), "*x");
 }
 
 TEST_F(StencilTest, DerefBinOp) {
   StringRef Id = "id";
-  testExpr(Id, "int *x; x + 1;", 

[PATCH] D69613: [libTooling] Simplify type structure of `Stencil`s.

2019-11-01 Thread Yitzhak Mandelbaum via Phabricator via cfe-commits
ymandel marked 12 inline comments as done.
ymandel added a comment.

In D69613#1730238 , @ymandel wrote:

> In D69613#1729703 , @gribozavr2 
> wrote:
>
> > I see. Some decoupling is desirable, I agree. Maybe move `StencilInterface` 
> > and `Stencil` into a separate header that `RewriteRule` can depend on, and 
> > then define the library of stencils in another header?
>
>
> This sounds good. I'll put together a (stacked) revision to do this. It seems 
> worth doing separately given that it will involve a substantial to the 
> RewriteRule library & tests.


In order to keep the client unaffected by the change, I reinstated a simple 
Stencil class to wrap the shared_ptr and provide the call operator.  This means 
that the code is now backwards compatible and forwards compatible (to the 
change we've discussed in RewriteRule to be stencil-aware).  This was simpler 
than adding temporary(?) overloads in `RewriteRule.h` for every function with a 
`TextGenerator` argument.

I included an overload of `operator->` so that we can collapse it back to just 
a type alias.




Comment at: clang/include/clang/Tooling/Transformer/Stencil.h:155
+template  MatchConsumer stencil(Ts &&... Parts) {
+  Stencil S = cat(std::forward(Parts)...);
+  return [S](const ast_matchers::MatchFinder::MatchResult ) {

gribozavr2 wrote:
> I'm not sure the convenience of being able to avoid to say "cat(...)" at the 
> callsite is worth the API complexity. In other words, my suggestion is to 
> make this function take a single stencil.
Based on discussion, removed this entirely.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D69613/new/

https://reviews.llvm.org/D69613



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D69613: [libTooling] Simplify type structure of `Stencil`s.

2019-11-01 Thread Yitzhak Mandelbaum via Phabricator via cfe-commits
ymandel updated this revision to Diff 227473.
ymandel added a comment.

addressed to comments


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D69613/new/

https://reviews.llvm.org/D69613

Files:
  clang/include/clang/Tooling/Transformer/Stencil.h
  clang/lib/Tooling/Transformer/Stencil.cpp
  clang/unittests/Tooling/StencilTest.cpp

Index: clang/unittests/Tooling/StencilTest.cpp
===
--- clang/unittests/Tooling/StencilTest.cpp
+++ clang/unittests/Tooling/StencilTest.cpp
@@ -96,7 +96,7 @@
  .bind("expr")))
 .bind("stmt"));
 ASSERT_TRUE(StmtMatch);
-if (auto ResultOrErr = Stencil.eval(StmtMatch->Result)) {
+if (auto ResultOrErr = Stencil->eval(StmtMatch->Result)) {
   ADD_FAILURE() << "Expected failure but succeeded: " << *ResultOrErr;
 } else {
   auto Err = llvm::handleErrors(ResultOrErr.takeError(),
@@ -131,11 +131,12 @@
   // Invert the if-then-else.
   auto Stencil = cat("if (!", node(Condition), ") ", statement(Else), " else ",
  statement(Then));
-  EXPECT_THAT_EXPECTED(Stencil.eval(StmtMatch->Result),
+  EXPECT_THAT_EXPECTED(Stencil->eval(StmtMatch->Result),
HasValue("if (!true) return 0; else return 1;"));
 }
 
-TEST_F(StencilTest, SingleStatementCallOperator) {
+// Tests `stencil`.
+TEST_F(StencilTest, StencilFactoryFunction) {
   StringRef Condition("C"), Then("T"), Else("E");
   const std::string Snippet = R"cc(
 if (true)
@@ -148,9 +149,9 @@
   hasThen(stmt().bind(Then)), hasElse(stmt().bind(Else;
   ASSERT_TRUE(StmtMatch);
   // Invert the if-then-else.
-  Stencil S = cat("if (!", node(Condition), ") ", statement(Else), " else ",
-  statement(Then));
-  EXPECT_THAT_EXPECTED(S(StmtMatch->Result),
+  auto Consumer = cat("if (!", node(Condition), ") ", statement(Else), " else ",
+  statement(Then));
+  EXPECT_THAT_EXPECTED(Consumer(StmtMatch->Result),
HasValue("if (!true) return 0; else return 1;"));
 }
 
@@ -165,7 +166,7 @@
  hasThen(stmt().bind("a2";
   ASSERT_TRUE(StmtMatch);
   auto Stencil = cat("if(!", node("a1"), ") ", node("UNBOUND"), ";");
-  auto ResultOrErr = Stencil.eval(StmtMatch->Result);
+  auto ResultOrErr = Stencil->eval(StmtMatch->Result);
   EXPECT_TRUE(llvm::errorToBool(ResultOrErr.takeError()))
   << "Expected unbound node, got " << *ResultOrErr;
 }
@@ -176,14 +177,14 @@
   StringRef Expected) {
   auto StmtMatch = matchStmt(Snippet, expr().bind(Id));
   ASSERT_TRUE(StmtMatch);
-  EXPECT_THAT_EXPECTED(Stencil.eval(StmtMatch->Result), HasValue(Expected));
+  EXPECT_THAT_EXPECTED(Stencil->eval(StmtMatch->Result), HasValue(Expected));
 }
 
 void testFailure(StringRef Id, StringRef Snippet, const Stencil ,
  testing::Matcher MessageMatcher) {
   auto StmtMatch = matchStmt(Snippet, expr().bind(Id));
   ASSERT_TRUE(StmtMatch);
-  EXPECT_THAT_EXPECTED(Stencil.eval(StmtMatch->Result),
+  EXPECT_THAT_EXPECTED(Stencil->eval(StmtMatch->Result),
Failed(testing::Property(
::getMessage, MessageMatcher)));
 }
@@ -195,28 +196,28 @@
 
 TEST_F(StencilTest, IfBoundOpBound) {
   StringRef Id = "id";
-  testExpr(Id, "3;", cat(ifBound(Id, text("5"), text("7"))), "5");
+  testExpr(Id, "3;", ifBound(Id, text("5"), text("7")), "5");
 }
 
 TEST_F(StencilTest, IfBoundOpUnbound) {
   StringRef Id = "id";
-  testExpr(Id, "3;", cat(ifBound("other", text("5"), text("7"))), "7");
+  testExpr(Id, "3;", ifBound("other", text("5"), text("7")), "7");
 }
 
 TEST_F(StencilTest, ExpressionOpNoParens) {
   StringRef Id = "id";
-  testExpr(Id, "3;", cat(expression(Id)), "3");
+  testExpr(Id, "3;", expression(Id), "3");
 }
 
 // Don't parenthesize a parens expression.
 TEST_F(StencilTest, ExpressionOpNoParensParens) {
   StringRef Id = "id";
-  testExpr(Id, "(3);", cat(expression(Id)), "(3)");
+  testExpr(Id, "(3);", expression(Id), "(3)");
 }
 
 TEST_F(StencilTest, ExpressionOpBinaryOpParens) {
   StringRef Id = "id";
-  testExpr(Id, "3+4;", cat(expression(Id)), "(3+4)");
+  testExpr(Id, "3+4;", expression(Id), "(3+4)");
 }
 
 // `expression` shares code with other ops, so we get sufficient coverage of the
@@ -224,33 +225,33 @@
 // tests should be added.
 TEST_F(StencilTest, ExpressionOpUnbound) {
   StringRef Id = "id";
-  testFailure(Id, "3;", cat(expression("ACACA")),
+  testFailure(Id, "3;", expression("ACACA"),
   AllOf(HasSubstr("ACACA"), HasSubstr("not bound")));
 }
 
 TEST_F(StencilTest, DerefPointer) {
   StringRef Id = "id";
-  testExpr(Id, "int *x; x;", cat(deref(Id)), "*x");
+  testExpr(Id, "int *x; x;", deref(Id), "*x");
 }
 
 TEST_F(StencilTest, DerefBinOp) {
   StringRef Id = "id";
-  testExpr(Id, "int *x; x + 1;", cat(deref(Id)), "*(x + 1)");
+  testExpr(Id, "int *x; x 

[PATCH] D69613: [libTooling] Simplify type structure of `Stencil`s.

2019-11-01 Thread Yitzhak Mandelbaum via Phabricator via cfe-commits
ymandel marked an inline comment as done.
ymandel added a comment.

In D69613#1729703 , @gribozavr2 wrote:

> I see. Some decoupling is desirable, I agree. Maybe move `StencilInterface` 
> and `Stencil` into a separate header that `RewriteRule` can depend on, and 
> then define the library of stencils in another header?


This sounds good. I'll put together a (stacked) revision to do this. It seems 
worth doing separately given that it will involve a substantial to the 
RewriteRule library & tests.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D69613/new/

https://reviews.llvm.org/D69613



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D69613: [libTooling] Simplify type structure of `Stencil`s.

2019-10-31 Thread Dmitri Gribenko via Phabricator via cfe-commits
gribozavr2 added a comment.

I see. Some decoupling is desirable, I agree. Maybe move `StencilInterface` and 
`Stencil` into a separate header that `RewriteRule` can depend on, and then 
define the library of stencils in another header?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D69613/new/

https://reviews.llvm.org/D69613



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D69613: [libTooling] Simplify type structure of `Stencil`s.

2019-10-31 Thread Yitzhak Mandelbaum via Phabricator via cfe-commits
ymandel marked 8 inline comments as done.
ymandel added inline comments.



Comment at: clang/include/clang/Tooling/Transformer/Stencil.h:154
+/// for more details.
+template  MatchConsumer stencil(Ts &&... Parts) {
+  Stencil S = cat(std::forward(Parts)...);

gribozavr2 wrote:
> ymandel wrote:
> > gribozavr2 wrote:
> > > I'm a bit confused by the name. The function returns a MatchConsumer, but 
> > > it is called "stencil". What is the intended usage?
> > Intended use is something like `makeRule(matcher, change(stencil(...)))`.
> > 
> > The naming is the same as we previously had for `text()`. Since 
> > `MatchConsumer` is so general, the function name describes its argument, 
> > not its particular type.  But, I'm open to other suggestions.
> I see -- thanks. `change()` takes a `TextGenerator`. Aside from stencils, 
> what are the other text generators? If those are not important, could we 
> change `change()` to take a stencil directly? Or if those other text 
> generators are important, we could add overloads to `change()` that accept a 
> stencil.
> 
> My thinking here is that the user is not really concerned with the fact that 
> Stencil-to-TextGenerator conversion is happening here. I think the more 
> complicated operation is the combining of stencils -- and we already have 
> `cat` for that; so adding another way to spell that is better avoided. So, 
> not emphasizing the conversion by making it a part of the `change()` seems 
> fine, and spelling the operation as `cat` seems to be an improvement to me.
> I see -- thanks. change() takes a TextGenerator. Aside from stencils, what 
> are the other text generators? If those are not important, could we change 
> change() to take a stencil directly?

Actually, that was the original design of the library.  We changed it in the 
first submitted version on Ilya's suggestion to avoid the dependency between 
Transformer and Stencil.  In fact, the reason TextGenerator exists is to 
abstract away that dependency.

Looking back, I think it was a reasonable choice at the time, keeping the 
commits, etc. independent. 
But, based on my experience with the library over the last six months, I'd say 
these are clearly a single package and we'd be better off re-introducing the 
dependency in exactly the way you describe.

I think we can start (here) by taking the Stencil as an argument and wrapping 
it as a TextGenerator. But, I should follow up with a cleanup to actually store 
the value as a Stencil rather than wrapped as a TextGenerator.




Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D69613/new/

https://reviews.llvm.org/D69613



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D69613: [libTooling] Simplify type structure of `Stencil`s.

2019-10-31 Thread Dmitri Gribenko via Phabricator via cfe-commits
gribozavr2 added inline comments.



Comment at: clang/include/clang/Tooling/Transformer/Stencil.h:82
+Stencil makeStencil(RangeSelector Selector);
+inline Stencil makeStencil(Stencil S) { return S; }
 

ymandel wrote:
> gribozavr2 wrote:
> > I feel like this should be an implementation detail of `cat` (or other 
> > stencil combinators who want to support such implicit conversions). Users 
> > writing stencils should use concrete factory functions below.
> > 
> > 
> Agreed, but I wasn't sure if it was worth introducing a "detail" namespace 
> for just one (overloaded) function. I liked when these were private methods 
> of Stencil, but we don't have that option now. Should I use a `namespace 
> detail`? something else? 
I don't have a strong opinion, but `namespace detail` should be fine.



Comment at: clang/include/clang/Tooling/Transformer/Stencil.h:137
+/// number.
+Stencil sequence(std::vector Parts);
 

ymandel wrote:
> gribozavr2 wrote:
> > It is the same operation as `cat`, right? So WDYT about `cat_vector`?
> not quite. `cat` is "smart" and optimizes case of one argument to just return 
> that argument. in the future, it might also handle the case of 0 arguments 
> specially. `sequence` just blindly constructs a sequence stencil.
> 
> that said, i can see the argument that the user doesn't care about such 
> details and instead of the three functions:
> ```
> cat(...)
> cat(vector)
> sequence(vector)
> ```
> 
> we should just have the two
> ```
> cat(...)
> catVector(vector)
> ```
> with no "plain" sequence constructor. WDYT?
> i can see the argument that the user doesn't care about such details

I agree, and I would also say that we probably don't even want the users of the 
library to depend on such details either. So I agree, `cat(...)` and 
`catVector(vector)` look like the best option to me.



Comment at: clang/include/clang/Tooling/Transformer/Stencil.h:154
+/// for more details.
+template  MatchConsumer stencil(Ts &&... Parts) {
+  Stencil S = cat(std::forward(Parts)...);

ymandel wrote:
> gribozavr2 wrote:
> > I'm a bit confused by the name. The function returns a MatchConsumer, but 
> > it is called "stencil". What is the intended usage?
> Intended use is something like `makeRule(matcher, change(stencil(...)))`.
> 
> The naming is the same as we previously had for `text()`. Since 
> `MatchConsumer` is so general, the function name describes its argument, not 
> its particular type.  But, I'm open to other suggestions.
I see -- thanks. `change()` takes a `TextGenerator`. Aside from stencils, what 
are the other text generators? If those are not important, could we change 
`change()` to take a stencil directly? Or if those other text generators are 
important, we could add overloads to `change()` that accept a stencil.

My thinking here is that the user is not really concerned with the fact that 
Stencil-to-TextGenerator conversion is happening here. I think the more 
complicated operation is the combining of stencils -- and we already have `cat` 
for that; so adding another way to spell that is better avoided. So, not 
emphasizing the conversion by making it a part of the `change()` seems fine, 
and spelling the operation as `cat` seems to be an improvement to me.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D69613/new/

https://reviews.llvm.org/D69613



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D69613: [libTooling] Simplify type structure of `Stencil`s.

2019-10-31 Thread Yitzhak Mandelbaum via Phabricator via cfe-commits
ymandel marked 5 inline comments as done.
ymandel added a comment.

Thanks for the review! I agreed w/ all the comments, just responding early w/ 
those I had further thoughts/questions on.




Comment at: clang/include/clang/Tooling/Transformer/Stencil.h:82
+Stencil makeStencil(RangeSelector Selector);
+inline Stencil makeStencil(Stencil S) { return S; }
 

gribozavr2 wrote:
> I feel like this should be an implementation detail of `cat` (or other 
> stencil combinators who want to support such implicit conversions). Users 
> writing stencils should use concrete factory functions below.
> 
> 
Agreed, but I wasn't sure if it was worth introducing a "detail" namespace for 
just one (overloaded) function. I liked when these were private methods of 
Stencil, but we don't have that option now. Should I use a `namespace detail`? 
something else? 



Comment at: clang/include/clang/Tooling/Transformer/Stencil.h:137
+/// number.
+Stencil sequence(std::vector Parts);
 

gribozavr2 wrote:
> It is the same operation as `cat`, right? So WDYT about `cat_vector`?
not quite. `cat` is "smart" and optimizes case of one argument to just return 
that argument. in the future, it might also handle the case of 0 arguments 
specially. `sequence` just blindly constructs a sequence stencil.

that said, i can see the argument that the user doesn't care about such details 
and instead of the three functions:
```
cat(...)
cat(vector)
sequence(vector)
```

we should just have the two
```
cat(...)
catVector(vector)
```
with no "plain" sequence constructor. WDYT?



Comment at: clang/include/clang/Tooling/Transformer/Stencil.h:150
 }
-} // namespace stencil
-} // namespace tooling
+Stencil cat(std::vector Parts);
+

gribozavr2 wrote:
> Like I said in the other review, I don't feel great about an overload set 
> with universal references and anything else.
Sorry, I'd forgotten we'd discussed this before. I see your point -- I was 
surprised it worked, but when it did just barelled along. That should have been 
a red flag. :)  I'm happy to rework this, per the comment above,.



Comment at: clang/include/clang/Tooling/Transformer/Stencil.h:154
+/// for more details.
+template  MatchConsumer stencil(Ts &&... Parts) {
+  Stencil S = cat(std::forward(Parts)...);

gribozavr2 wrote:
> I'm a bit confused by the name. The function returns a MatchConsumer, but it 
> is called "stencil". What is the intended usage?
Intended use is something like `makeRule(matcher, change(stencil(...)))`.

The naming is the same as we previously had for `text()`. Since `MatchConsumer` 
is so general, the function name describes its argument, not its particular 
type.  But, I'm open to other suggestions.



Comment at: clang/lib/Tooling/Transformer/Stencil.cpp:262
+
+template  class StencilImpl : public StencilInterface {
   T Data;

gribozavr2 wrote:
> There isn't much logic left in StencilImpl.
> 
> Would the code be simpler if we made the various Data classes implement 
> StencilInterface directly?
Yes! I plan to do that in a followup revision, though I was really tempted to 
do it here already. :)

That said, we could also use a `llvm::PointerSumType` and implement it in 
functional style, fwiw. I'm fine either way.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D69613/new/

https://reviews.llvm.org/D69613



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D69613: [libTooling] Simplify type structure of `Stencil`s.

2019-10-31 Thread Dmitri Gribenko via Phabricator via cfe-commits
gribozavr2 added inline comments.



Comment at: clang/include/clang/Tooling/Transformer/Stencil.h:57
+  /// Constructs a string representation of the StencilInterfacePart.
+  /// StencilInterfaceParts generated by the `selection` and `run` functions do
+  /// not have a unique string representation.

s/Part// (2x)



Comment at: clang/include/clang/Tooling/Transformer/Stencil.h:82
+Stencil makeStencil(RangeSelector Selector);
+inline Stencil makeStencil(Stencil S) { return S; }
 

I feel like this should be an implementation detail of `cat` (or other stencil 
combinators who want to support such implicit conversions). Users writing 
stencils should use concrete factory functions below.





Comment at: clang/include/clang/Tooling/Transformer/Stencil.h:137
+/// number.
+Stencil sequence(std::vector Parts);
 

It is the same operation as `cat`, right? So WDYT about `cat_vector`?



Comment at: clang/include/clang/Tooling/Transformer/Stencil.h:144
 
-namespace tooling {
-// DEPRECATED: These are temporary aliases supporting client migration to the
-// `transformer` namespace.
-using Stencil = transformer::Stencil;
-using StencilPart = transformer::StencilPart;
-namespace stencil {
-using transformer::access;
-using transformer::addressOf;
-using transformer::cat;
-using transformer::deref;
-using transformer::dPrint;
-using transformer::expression;
-using transformer::ifBound;
-using transformer::run;
-using transformer::selection;
-using transformer::text;
-/// \returns the source corresponding to the identified node.
-/// FIXME: Deprecated. Write `selection(node(Id))` instead.
-inline transformer::StencilPart node(llvm::StringRef Id) {
-  return selection(tooling::node(Id));
+/// General-purpose Stencil factory function. Concatenates 0+ stencil pieces
+/// into a single stencil. Arguments can be raw text, ranges in the matched 
code

I think it is better to remove the first sentence.



Comment at: clang/include/clang/Tooling/Transformer/Stencil.h:150
 }
-} // namespace stencil
-} // namespace tooling
+Stencil cat(std::vector Parts);
+

Like I said in the other review, I don't feel great about an overload set with 
universal references and anything else.



Comment at: clang/include/clang/Tooling/Transformer/Stencil.h:152
+
+/// Convenience function for creating a stencil-based MatchConsumer. See `cat`
+/// for more details.

"Creates a MatchConsumer that evaluates a given Stencil."



Comment at: clang/include/clang/Tooling/Transformer/Stencil.h:154
+/// for more details.
+template  MatchConsumer stencil(Ts &&... Parts) {
+  Stencil S = cat(std::forward(Parts)...);

I'm a bit confused by the name. The function returns a MatchConsumer, but it is 
called "stencil". What is the intended usage?



Comment at: clang/include/clang/Tooling/Transformer/Stencil.h:155
+template  MatchConsumer stencil(Ts &&... Parts) {
+  Stencil S = cat(std::forward(Parts)...);
+  return [S](const ast_matchers::MatchFinder::MatchResult ) {

I'm not sure the convenience of being able to avoid to say "cat(...)" at the 
callsite is worth the API complexity. In other words, my suggestion is to make 
this function take a single stencil.



Comment at: clang/lib/Tooling/Transformer/Stencil.cpp:97
+// StencilInteface or just Stencil?
+// unique_ptr or shared_ptr?
+

I think these comments can be deleted now.



Comment at: clang/lib/Tooling/Transformer/Stencil.cpp:262
+
+template  class StencilImpl : public StencilInterface {
   T Data;

There isn't much logic left in StencilImpl.

Would the code be simpler if we made the various Data classes implement 
StencilInterface directly?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D69613/new/

https://reviews.llvm.org/D69613



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D69613: [libTooling] Simplify type structure of `Stencil`s.

2019-10-30 Thread Yitzhak Mandelbaum via Phabricator via cfe-commits
ymandel updated this revision to Diff 227159.
ymandel added a comment.

rebasing onto parent


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D69613/new/

https://reviews.llvm.org/D69613

Files:
  clang/include/clang/Tooling/Transformer/Stencil.h
  clang/lib/Tooling/Transformer/Stencil.cpp
  clang/unittests/Tooling/StencilTest.cpp

Index: clang/unittests/Tooling/StencilTest.cpp
===
--- clang/unittests/Tooling/StencilTest.cpp
+++ clang/unittests/Tooling/StencilTest.cpp
@@ -96,7 +96,7 @@
  .bind("expr")))
 .bind("stmt"));
 ASSERT_TRUE(StmtMatch);
-if (auto ResultOrErr = Stencil.eval(StmtMatch->Result)) {
+if (auto ResultOrErr = Stencil->eval(StmtMatch->Result)) {
   ADD_FAILURE() << "Expected failure but succeeded: " << *ResultOrErr;
 } else {
   auto Err = llvm::handleErrors(ResultOrErr.takeError(),
@@ -131,11 +131,11 @@
   // Invert the if-then-else.
   auto Stencil = cat("if (!", node(Condition), ") ", statement(Else), " else ",
  statement(Then));
-  EXPECT_THAT_EXPECTED(Stencil.eval(StmtMatch->Result),
+  EXPECT_THAT_EXPECTED(Stencil->eval(StmtMatch->Result),
HasValue("if (!true) return 0; else return 1;"));
 }
 
-TEST_F(StencilTest, SingleStatementCallOperator) {
+TEST_F(StencilTest, StencilFactoryFunction) {
   StringRef Condition("C"), Then("T"), Else("E");
   const std::string Snippet = R"cc(
 if (true)
@@ -148,9 +148,9 @@
   hasThen(stmt().bind(Then)), hasElse(stmt().bind(Else;
   ASSERT_TRUE(StmtMatch);
   // Invert the if-then-else.
-  Stencil S = cat("if (!", node(Condition), ") ", statement(Else), " else ",
-  statement(Then));
-  EXPECT_THAT_EXPECTED(S(StmtMatch->Result),
+  auto Consumer = stencil("if (!", node(Condition), ") ", statement(Else),
+  " else ", statement(Then));
+  EXPECT_THAT_EXPECTED(Consumer(StmtMatch->Result),
HasValue("if (!true) return 0; else return 1;"));
 }
 
@@ -165,7 +165,7 @@
  hasThen(stmt().bind("a2";
   ASSERT_TRUE(StmtMatch);
   auto Stencil = cat("if(!", node("a1"), ") ", node("UNBOUND"), ";");
-  auto ResultOrErr = Stencil.eval(StmtMatch->Result);
+  auto ResultOrErr = Stencil->eval(StmtMatch->Result);
   EXPECT_TRUE(llvm::errorToBool(ResultOrErr.takeError()))
   << "Expected unbound node, got " << *ResultOrErr;
 }
@@ -176,14 +176,14 @@
   StringRef Expected) {
   auto StmtMatch = matchStmt(Snippet, expr().bind(Id));
   ASSERT_TRUE(StmtMatch);
-  EXPECT_THAT_EXPECTED(Stencil.eval(StmtMatch->Result), HasValue(Expected));
+  EXPECT_THAT_EXPECTED(Stencil->eval(StmtMatch->Result), HasValue(Expected));
 }
 
 void testFailure(StringRef Id, StringRef Snippet, const Stencil ,
  testing::Matcher MessageMatcher) {
   auto StmtMatch = matchStmt(Snippet, expr().bind(Id));
   ASSERT_TRUE(StmtMatch);
-  EXPECT_THAT_EXPECTED(Stencil.eval(StmtMatch->Result),
+  EXPECT_THAT_EXPECTED(Stencil->eval(StmtMatch->Result),
Failed(testing::Property(
::getMessage, MessageMatcher)));
 }
@@ -195,28 +195,28 @@
 
 TEST_F(StencilTest, IfBoundOpBound) {
   StringRef Id = "id";
-  testExpr(Id, "3;", cat(ifBound(Id, text("5"), text("7"))), "5");
+  testExpr(Id, "3;", ifBound(Id, text("5"), text("7")), "5");
 }
 
 TEST_F(StencilTest, IfBoundOpUnbound) {
   StringRef Id = "id";
-  testExpr(Id, "3;", cat(ifBound("other", text("5"), text("7"))), "7");
+  testExpr(Id, "3;", ifBound("other", text("5"), text("7")), "7");
 }
 
 TEST_F(StencilTest, ExpressionOpNoParens) {
   StringRef Id = "id";
-  testExpr(Id, "3;", cat(expression(Id)), "3");
+  testExpr(Id, "3;", expression(Id), "3");
 }
 
 // Don't parenthesize a parens expression.
 TEST_F(StencilTest, ExpressionOpNoParensParens) {
   StringRef Id = "id";
-  testExpr(Id, "(3);", cat(expression(Id)), "(3)");
+  testExpr(Id, "(3);", expression(Id), "(3)");
 }
 
 TEST_F(StencilTest, ExpressionOpBinaryOpParens) {
   StringRef Id = "id";
-  testExpr(Id, "3+4;", cat(expression(Id)), "(3+4)");
+  testExpr(Id, "3+4;", expression(Id), "(3+4)");
 }
 
 // `expression` shares code with other ops, so we get sufficient coverage of the
@@ -224,33 +224,33 @@
 // tests should be added.
 TEST_F(StencilTest, ExpressionOpUnbound) {
   StringRef Id = "id";
-  testFailure(Id, "3;", cat(expression("ACACA")),
+  testFailure(Id, "3;", expression("ACACA"),
   AllOf(HasSubstr("ACACA"), HasSubstr("not bound")));
 }
 
 TEST_F(StencilTest, DerefPointer) {
   StringRef Id = "id";
-  testExpr(Id, "int *x; x;", cat(deref(Id)), "*x");
+  testExpr(Id, "int *x; x;", deref(Id), "*x");
 }
 
 TEST_F(StencilTest, DerefBinOp) {
   StringRef Id = "id";
-  testExpr(Id, "int *x; x + 1;", cat(deref(Id)), "*(x + 1)");
+  testExpr(Id, "int *x; x + 1;", 

[PATCH] D69613: [libTooling] Simplify type structure of `Stencil`s.

2019-10-30 Thread Yitzhak Mandelbaum via Phabricator via cfe-commits
ymandel updated this revision to Diff 227156.
ymandel added a comment.

added simple overload of `cat` -- needed to support client transition to new 
type structure.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D69613/new/

https://reviews.llvm.org/D69613

Files:
  clang/include/clang/Tooling/Transformer/Stencil.h
  clang/lib/Tooling/Transformer/Stencil.cpp
  clang/unittests/Tooling/StencilTest.cpp

Index: clang/unittests/Tooling/StencilTest.cpp
===
--- clang/unittests/Tooling/StencilTest.cpp
+++ clang/unittests/Tooling/StencilTest.cpp
@@ -96,7 +96,7 @@
  .bind("expr")))
 .bind("stmt"));
 ASSERT_TRUE(StmtMatch);
-if (auto ResultOrErr = Stencil.eval(StmtMatch->Result)) {
+if (auto ResultOrErr = Stencil->eval(StmtMatch->Result)) {
   ADD_FAILURE() << "Expected failure but succeeded: " << *ResultOrErr;
 } else {
   auto Err = llvm::handleErrors(ResultOrErr.takeError(),
@@ -131,11 +131,11 @@
   // Invert the if-then-else.
   auto Stencil = cat("if (!", node(Condition), ") ", statement(Else), " else ",
  statement(Then));
-  EXPECT_THAT_EXPECTED(Stencil.eval(StmtMatch->Result),
+  EXPECT_THAT_EXPECTED(Stencil->eval(StmtMatch->Result),
HasValue("if (!true) return 0; else return 1;"));
 }
 
-TEST_F(StencilTest, SingleStatementCallOperator) {
+TEST_F(StencilTest, StencilFactoryFunction) {
   StringRef Condition("C"), Then("T"), Else("E");
   const std::string Snippet = R"cc(
 if (true)
@@ -148,9 +148,9 @@
   hasThen(stmt().bind(Then)), hasElse(stmt().bind(Else;
   ASSERT_TRUE(StmtMatch);
   // Invert the if-then-else.
-  Stencil S = cat("if (!", node(Condition), ") ", statement(Else), " else ",
-  statement(Then));
-  EXPECT_THAT_EXPECTED(S(StmtMatch->Result),
+  auto Consumer = stencil("if (!", node(Condition), ") ", statement(Else),
+  " else ", statement(Then));
+  EXPECT_THAT_EXPECTED(Consumer(StmtMatch->Result),
HasValue("if (!true) return 0; else return 1;"));
 }
 
@@ -165,7 +165,7 @@
  hasThen(stmt().bind("a2";
   ASSERT_TRUE(StmtMatch);
   auto Stencil = cat("if(!", node("a1"), ") ", node("UNBOUND"), ";");
-  auto ResultOrErr = Stencil.eval(StmtMatch->Result);
+  auto ResultOrErr = Stencil->eval(StmtMatch->Result);
   EXPECT_TRUE(llvm::errorToBool(ResultOrErr.takeError()))
   << "Expected unbound node, got " << *ResultOrErr;
 }
@@ -176,14 +176,14 @@
   StringRef Expected) {
   auto StmtMatch = matchStmt(Snippet, expr().bind(Id));
   ASSERT_TRUE(StmtMatch);
-  EXPECT_THAT_EXPECTED(Stencil.eval(StmtMatch->Result), HasValue(Expected));
+  EXPECT_THAT_EXPECTED(Stencil->eval(StmtMatch->Result), HasValue(Expected));
 }
 
 void testFailure(StringRef Id, StringRef Snippet, const Stencil ,
  testing::Matcher MessageMatcher) {
   auto StmtMatch = matchStmt(Snippet, expr().bind(Id));
   ASSERT_TRUE(StmtMatch);
-  EXPECT_THAT_EXPECTED(Stencil.eval(StmtMatch->Result),
+  EXPECT_THAT_EXPECTED(Stencil->eval(StmtMatch->Result),
Failed(testing::Property(
::getMessage, MessageMatcher)));
 }
@@ -195,28 +195,28 @@
 
 TEST_F(StencilTest, IfBoundOpBound) {
   StringRef Id = "id";
-  testExpr(Id, "3;", cat(ifBound(Id, text("5"), text("7"))), "5");
+  testExpr(Id, "3;", ifBound(Id, text("5"), text("7")), "5");
 }
 
 TEST_F(StencilTest, IfBoundOpUnbound) {
   StringRef Id = "id";
-  testExpr(Id, "3;", cat(ifBound("other", text("5"), text("7"))), "7");
+  testExpr(Id, "3;", ifBound("other", text("5"), text("7")), "7");
 }
 
 TEST_F(StencilTest, ExpressionOpNoParens) {
   StringRef Id = "id";
-  testExpr(Id, "3;", cat(expression(Id)), "3");
+  testExpr(Id, "3;", expression(Id), "3");
 }
 
 // Don't parenthesize a parens expression.
 TEST_F(StencilTest, ExpressionOpNoParensParens) {
   StringRef Id = "id";
-  testExpr(Id, "(3);", cat(expression(Id)), "(3)");
+  testExpr(Id, "(3);", expression(Id), "(3)");
 }
 
 TEST_F(StencilTest, ExpressionOpBinaryOpParens) {
   StringRef Id = "id";
-  testExpr(Id, "3+4;", cat(expression(Id)), "(3+4)");
+  testExpr(Id, "3+4;", expression(Id), "(3+4)");
 }
 
 // `expression` shares code with other ops, so we get sufficient coverage of the
@@ -224,33 +224,33 @@
 // tests should be added.
 TEST_F(StencilTest, ExpressionOpUnbound) {
   StringRef Id = "id";
-  testFailure(Id, "3;", cat(expression("ACACA")),
+  testFailure(Id, "3;", expression("ACACA"),
   AllOf(HasSubstr("ACACA"), HasSubstr("not bound")));
 }
 
 TEST_F(StencilTest, DerefPointer) {
   StringRef Id = "id";
-  testExpr(Id, "int *x; x;", cat(deref(Id)), "*x");
+  testExpr(Id, "int *x; x;", deref(Id), "*x");
 }
 
 TEST_F(StencilTest, DerefBinOp) {
   StringRef Id = "id";
-  testExpr(Id, "int *x; x + 

[PATCH] D69613: [libTooling] Simplify type structure of `Stencil`s.

2019-10-30 Thread Yitzhak Mandelbaum via Phabricator via cfe-commits
ymandel updated this revision to Diff 227072.
ymandel added a comment.

commented sequence operator


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D69613/new/

https://reviews.llvm.org/D69613

Files:
  clang/include/clang/Tooling/Transformer/Stencil.h
  clang/lib/Tooling/Transformer/Stencil.cpp
  clang/unittests/Tooling/StencilTest.cpp

Index: clang/unittests/Tooling/StencilTest.cpp
===
--- clang/unittests/Tooling/StencilTest.cpp
+++ clang/unittests/Tooling/StencilTest.cpp
@@ -96,7 +96,7 @@
  .bind("expr")))
 .bind("stmt"));
 ASSERT_TRUE(StmtMatch);
-if (auto ResultOrErr = Stencil.eval(StmtMatch->Result)) {
+if (auto ResultOrErr = Stencil->eval(StmtMatch->Result)) {
   ADD_FAILURE() << "Expected failure but succeeded: " << *ResultOrErr;
 } else {
   auto Err = llvm::handleErrors(ResultOrErr.takeError(),
@@ -131,11 +131,11 @@
   // Invert the if-then-else.
   auto Stencil = cat("if (!", node(Condition), ") ", statement(Else), " else ",
  statement(Then));
-  EXPECT_THAT_EXPECTED(Stencil.eval(StmtMatch->Result),
+  EXPECT_THAT_EXPECTED(Stencil->eval(StmtMatch->Result),
HasValue("if (!true) return 0; else return 1;"));
 }
 
-TEST_F(StencilTest, SingleStatementCallOperator) {
+TEST_F(StencilTest, StencilFactoryFunction) {
   StringRef Condition("C"), Then("T"), Else("E");
   const std::string Snippet = R"cc(
 if (true)
@@ -148,9 +148,9 @@
   hasThen(stmt().bind(Then)), hasElse(stmt().bind(Else;
   ASSERT_TRUE(StmtMatch);
   // Invert the if-then-else.
-  Stencil S = cat("if (!", node(Condition), ") ", statement(Else), " else ",
-  statement(Then));
-  EXPECT_THAT_EXPECTED(S(StmtMatch->Result),
+  auto Consumer = stencil("if (!", node(Condition), ") ", statement(Else),
+  " else ", statement(Then));
+  EXPECT_THAT_EXPECTED(Consumer(StmtMatch->Result),
HasValue("if (!true) return 0; else return 1;"));
 }
 
@@ -165,7 +165,7 @@
  hasThen(stmt().bind("a2";
   ASSERT_TRUE(StmtMatch);
   auto Stencil = cat("if(!", node("a1"), ") ", node("UNBOUND"), ";");
-  auto ResultOrErr = Stencil.eval(StmtMatch->Result);
+  auto ResultOrErr = Stencil->eval(StmtMatch->Result);
   EXPECT_TRUE(llvm::errorToBool(ResultOrErr.takeError()))
   << "Expected unbound node, got " << *ResultOrErr;
 }
@@ -176,14 +176,14 @@
   StringRef Expected) {
   auto StmtMatch = matchStmt(Snippet, expr().bind(Id));
   ASSERT_TRUE(StmtMatch);
-  EXPECT_THAT_EXPECTED(Stencil.eval(StmtMatch->Result), HasValue(Expected));
+  EXPECT_THAT_EXPECTED(Stencil->eval(StmtMatch->Result), HasValue(Expected));
 }
 
 void testFailure(StringRef Id, StringRef Snippet, const Stencil ,
  testing::Matcher MessageMatcher) {
   auto StmtMatch = matchStmt(Snippet, expr().bind(Id));
   ASSERT_TRUE(StmtMatch);
-  EXPECT_THAT_EXPECTED(Stencil.eval(StmtMatch->Result),
+  EXPECT_THAT_EXPECTED(Stencil->eval(StmtMatch->Result),
Failed(testing::Property(
::getMessage, MessageMatcher)));
 }
@@ -195,28 +195,28 @@
 
 TEST_F(StencilTest, IfBoundOpBound) {
   StringRef Id = "id";
-  testExpr(Id, "3;", cat(ifBound(Id, text("5"), text("7"))), "5");
+  testExpr(Id, "3;", ifBound(Id, text("5"), text("7")), "5");
 }
 
 TEST_F(StencilTest, IfBoundOpUnbound) {
   StringRef Id = "id";
-  testExpr(Id, "3;", cat(ifBound("other", text("5"), text("7"))), "7");
+  testExpr(Id, "3;", ifBound("other", text("5"), text("7")), "7");
 }
 
 TEST_F(StencilTest, ExpressionOpNoParens) {
   StringRef Id = "id";
-  testExpr(Id, "3;", cat(expression(Id)), "3");
+  testExpr(Id, "3;", expression(Id), "3");
 }
 
 // Don't parenthesize a parens expression.
 TEST_F(StencilTest, ExpressionOpNoParensParens) {
   StringRef Id = "id";
-  testExpr(Id, "(3);", cat(expression(Id)), "(3)");
+  testExpr(Id, "(3);", expression(Id), "(3)");
 }
 
 TEST_F(StencilTest, ExpressionOpBinaryOpParens) {
   StringRef Id = "id";
-  testExpr(Id, "3+4;", cat(expression(Id)), "(3+4)");
+  testExpr(Id, "3+4;", expression(Id), "(3+4)");
 }
 
 // `expression` shares code with other ops, so we get sufficient coverage of the
@@ -224,33 +224,33 @@
 // tests should be added.
 TEST_F(StencilTest, ExpressionOpUnbound) {
   StringRef Id = "id";
-  testFailure(Id, "3;", cat(expression("ACACA")),
+  testFailure(Id, "3;", expression("ACACA"),
   AllOf(HasSubstr("ACACA"), HasSubstr("not bound")));
 }
 
 TEST_F(StencilTest, DerefPointer) {
   StringRef Id = "id";
-  testExpr(Id, "int *x; x;", cat(deref(Id)), "*x");
+  testExpr(Id, "int *x; x;", deref(Id), "*x");
 }
 
 TEST_F(StencilTest, DerefBinOp) {
   StringRef Id = "id";
-  testExpr(Id, "int *x; x + 1;", cat(deref(Id)), "*(x + 1)");
+  testExpr(Id, "int *x; x + 1;", 

[PATCH] D69613: [libTooling] Simplify type structure of `Stencil`s.

2019-10-30 Thread Yitzhak Mandelbaum via Phabricator via cfe-commits
ymandel created this revision.
ymandel added a reviewer: gribozavr.
Herald added a project: clang.

Currently, stencils are defined as a sequence of `StencilParts`. This
differentiation adds an unneeded layer of complexity to the definition of
Stencils. This change significantly simplifies the type structure: a stencil is
now conceptually any object implementing `StencilInterface` and `Stencil` is
just an alias for pointers to this interface.

To account for the sequencing that was supported by the old `Stencil` type, we
introduce a sequencing class that implements `StencilInterface`. That is,
sequences are just another kind of Stencil and no longer have any special
status.

Corresponding to this change in the type structure, we change the way `cat` is
used (and defined). `cat` bundles multiple features: it builds a stencil from a
sequence of subcomponents and admits multiple different types for its arguments,
while coercing them into the right type. Previously, `cat` was also used to
coerce a single `StencilPart` into a `Stencil`. With that distinction gone, many
uses of `cat` (e.g. in the tests) are unnecessary and have, therefore, been
removed.

Finally, we expose the "coercion" functionality with the first-class function
`makeStencil`, which was, previously, the private method `wrap`. This way, other
functions with Stencil-typed arguments can leverage `makeStencil`.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D69613

Files:
  clang/include/clang/Tooling/Transformer/Stencil.h
  clang/lib/Tooling/Transformer/Stencil.cpp
  clang/unittests/Tooling/StencilTest.cpp

Index: clang/unittests/Tooling/StencilTest.cpp
===
--- clang/unittests/Tooling/StencilTest.cpp
+++ clang/unittests/Tooling/StencilTest.cpp
@@ -96,7 +96,7 @@
  .bind("expr")))
 .bind("stmt"));
 ASSERT_TRUE(StmtMatch);
-if (auto ResultOrErr = Stencil.eval(StmtMatch->Result)) {
+if (auto ResultOrErr = Stencil->eval(StmtMatch->Result)) {
   ADD_FAILURE() << "Expected failure but succeeded: " << *ResultOrErr;
 } else {
   auto Err = llvm::handleErrors(ResultOrErr.takeError(),
@@ -131,11 +131,11 @@
   // Invert the if-then-else.
   auto Stencil = cat("if (!", node(Condition), ") ", statement(Else), " else ",
  statement(Then));
-  EXPECT_THAT_EXPECTED(Stencil.eval(StmtMatch->Result),
+  EXPECT_THAT_EXPECTED(Stencil->eval(StmtMatch->Result),
HasValue("if (!true) return 0; else return 1;"));
 }
 
-TEST_F(StencilTest, SingleStatementCallOperator) {
+TEST_F(StencilTest, StencilFactoryFunction) {
   StringRef Condition("C"), Then("T"), Else("E");
   const std::string Snippet = R"cc(
 if (true)
@@ -148,9 +148,9 @@
   hasThen(stmt().bind(Then)), hasElse(stmt().bind(Else;
   ASSERT_TRUE(StmtMatch);
   // Invert the if-then-else.
-  Stencil S = cat("if (!", node(Condition), ") ", statement(Else), " else ",
-  statement(Then));
-  EXPECT_THAT_EXPECTED(S(StmtMatch->Result),
+  auto Consumer = stencil("if (!", node(Condition), ") ", statement(Else),
+  " else ", statement(Then));
+  EXPECT_THAT_EXPECTED(Consumer(StmtMatch->Result),
HasValue("if (!true) return 0; else return 1;"));
 }
 
@@ -165,7 +165,7 @@
  hasThen(stmt().bind("a2";
   ASSERT_TRUE(StmtMatch);
   auto Stencil = cat("if(!", node("a1"), ") ", node("UNBOUND"), ";");
-  auto ResultOrErr = Stencil.eval(StmtMatch->Result);
+  auto ResultOrErr = Stencil->eval(StmtMatch->Result);
   EXPECT_TRUE(llvm::errorToBool(ResultOrErr.takeError()))
   << "Expected unbound node, got " << *ResultOrErr;
 }
@@ -176,14 +176,14 @@
   StringRef Expected) {
   auto StmtMatch = matchStmt(Snippet, expr().bind(Id));
   ASSERT_TRUE(StmtMatch);
-  EXPECT_THAT_EXPECTED(Stencil.eval(StmtMatch->Result), HasValue(Expected));
+  EXPECT_THAT_EXPECTED(Stencil->eval(StmtMatch->Result), HasValue(Expected));
 }
 
 void testFailure(StringRef Id, StringRef Snippet, const Stencil ,
  testing::Matcher MessageMatcher) {
   auto StmtMatch = matchStmt(Snippet, expr().bind(Id));
   ASSERT_TRUE(StmtMatch);
-  EXPECT_THAT_EXPECTED(Stencil.eval(StmtMatch->Result),
+  EXPECT_THAT_EXPECTED(Stencil->eval(StmtMatch->Result),
Failed(testing::Property(
::getMessage, MessageMatcher)));
 }
@@ -195,28 +195,28 @@
 
 TEST_F(StencilTest, IfBoundOpBound) {
   StringRef Id = "id";
-  testExpr(Id, "3;", cat(ifBound(Id, text("5"), text("7"))), "5");
+  testExpr(Id, "3;", ifBound(Id, text("5"), text("7")), "5");
 }
 
 TEST_F(StencilTest, IfBoundOpUnbound) {
   StringRef Id = "id";
-  testExpr(Id, "3;", cat(ifBound("other", text("5"), text("7"))), "7");
+  testExpr(Id, "3;", ifBound("other", text("5"), text("7")), "7");
 }
 
 TEST_F(StencilTest,