ymandel updated this revision to Diff 309542.
ymandel added a comment.

renamed the combinator


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D92658

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
@@ -55,14 +55,14 @@
 // `StatementCode` may contain other statements not described by `Matcher`.
 static llvm::Optional<TestMatch> matchStmt(StringRef StatementCode,
                                            StatementMatcher Matcher) {
-  auto AstUnit = tooling::buildASTFromCode(wrapSnippet(StatementCode));
+  auto AstUnit = tooling::buildASTFromCodeWithArgs(wrapSnippet(StatementCode),
+                                                   {"-Wno-unused-value"});
   if (AstUnit == nullptr) {
     ADD_FAILURE() << "AST construction failed";
     return llvm::None;
   }
   ASTContext &Context = AstUnit->getASTContext();
-  auto Matches = ast_matchers::match(
-      traverse(ast_type_traits::TK_AsIs, wrapMatcher(Matcher)), Context);
+  auto Matches = ast_matchers::match(wrapMatcher(Matcher), Context);
   // We expect a single, exact match for the statement.
   if (Matches.size() != 1) {
     ADD_FAILURE() << "Wrong number of matches: " << Matches.size();
@@ -365,6 +365,50 @@
   EXPECT_THAT_EXPECTED(Stencil->eval(StmtMatch->Result), HasValue("field"));
 }
 
+TEST_F(StencilTest, NodeAsStringStmt) {
+  std::string Snippet = "int *x; if (x == nullptr) (void)*x;";
+  std::string Expected = "if (x == nullptr)\n    (void)*x;\n";
+  auto StmtMatch = matchStmt(Snippet, ifStmt().bind("id"));
+  ASSERT_TRUE(StmtMatch);
+  EXPECT_THAT_EXPECTED(nodeAsString("id")->eval(StmtMatch->Result),
+                       HasValue(std::string(Expected)));
+}
+
+TEST_F(StencilTest, NodeAsStringExpr) {
+  StringRef Id = "id";
+  testExpr(Id, "int *x; (*x + 1);", nodeAsString(Id), "(*x + 1)");
+}
+
+TEST_F(StencilTest, NodeAsStringType) {
+  std::string Snippet = "int *x; x;";
+  std::string Expected = "int *";
+  auto StmtMatch =
+      matchStmt(Snippet, declRefExpr(hasType(qualType().bind("type"))));
+  ASSERT_TRUE(StmtMatch);
+  EXPECT_THAT_EXPECTED(nodeAsString("type")->eval(StmtMatch->Result),
+                       HasValue(std::string(Expected)));
+}
+
+TEST_F(StencilTest, NodeAsStringSugaredType) {
+  std::string Snippet = "using Ty = int; Ty *x; x;";
+  std::string Expected = "Ty *";
+  auto StmtMatch =
+      matchStmt(Snippet, declRefExpr(hasType(qualType().bind("type"))));
+  ASSERT_TRUE(StmtMatch);
+  EXPECT_THAT_EXPECTED(nodeAsString("type")->eval(StmtMatch->Result),
+                       HasValue(std::string(Expected)));
+}
+
+TEST_F(StencilTest, NodeAsStringDecl) {
+  std::string Snippet = "int *x; x;";
+  std::string Expected = "int *x";
+  auto StmtMatch =
+      matchStmt(Snippet, declStmt(hasSingleDecl(decl().bind("decl"))));
+  ASSERT_TRUE(StmtMatch);
+  EXPECT_THAT_EXPECTED(nodeAsString("decl")->eval(StmtMatch->Result),
+                       HasValue(std::string(Expected)));
+}
+
 TEST_F(StencilTest, RunOp) {
   StringRef Id = "id";
   auto SimpleFn = [Id](const MatchResult &R) {
@@ -448,6 +492,12 @@
   EXPECT_EQ(S->toString(), Expected);
 }
 
+TEST(StencilToStringTest, NodeAsStringOp) {
+  auto S = nodeAsString("Id");
+  StringRef Expected = R"repr(nodeAsString("Id"))repr";
+  EXPECT_EQ(S->toString(), Expected);
+}
+
 TEST(StencilToStringTest, DebugPrintNodeOp) {
   auto S = dPrint("Id");
   StringRef Expected = R"repr(dPrint("Id"))repr";
Index: clang/lib/Tooling/Transformer/Stencil.cpp
===================================================================
--- clang/lib/Tooling/Transformer/Stencil.cpp
+++ clang/lib/Tooling/Transformer/Stencil.cpp
@@ -63,6 +63,7 @@
   MaybeDeref,
   AddressOf,
   MaybeAddressOf,
+  AsString,
 };
 
 // Generic container for stencil operations with a (single) node-id argument.
@@ -133,6 +134,9 @@
   case UnaryNodeOperator::MaybeAddressOf:
     OpName = "maybeAddressOf";
     break;
+  case UnaryNodeOperator::AsString:
+    OpName = "nodeAsString";
+    break;
   }
   return (OpName + "(\"" + Data.Id + "\")").str();
 }
@@ -174,11 +178,11 @@
   return Error::success();
 }
 
-Error evalData(const DebugPrintNodeData &Data,
-               const MatchFinder::MatchResult &Match, std::string *Result) {
+static Error printNode(StringRef Id, const MatchFinder::MatchResult &Match,
+                       std::string *Result) {
   std::string Output;
   llvm::raw_string_ostream Os(Output);
-  auto NodeOrErr = getNode(Match.Nodes, Data.Id);
+  auto NodeOrErr = getNode(Match.Nodes, Id);
   if (auto Err = NodeOrErr.takeError())
     return Err;
   NodeOrErr->print(Os, PrintingPolicy(Match.Context->getLangOpts()));
@@ -186,8 +190,18 @@
   return Error::success();
 }
 
+Error evalData(const DebugPrintNodeData &Data,
+               const MatchFinder::MatchResult &Match, std::string *Result) {
+  return printNode(Data.Id, Match, Result);
+}
+
 Error evalData(const UnaryOperationData &Data,
                const MatchFinder::MatchResult &Match, std::string *Result) {
+  // The `AsString` operation can be applied to any node, not just expressions,
+  // so it is handled here, separately.
+  if (Data.Op == UnaryNodeOperator::AsString)
+    return printNode(Data.Id, Match, Result);
+
   const auto *E = Match.Nodes.getNodeAs<Expr>(Data.Id);
   if (E == nullptr)
     return llvm::make_error<StringError>(
@@ -217,6 +231,8 @@
     }
     Source = tooling::buildAddressOf(*E, *Match.Context);
     break;
+  case UnaryNodeOperator::AsString:
+    llvm_unreachable("This case is handled at the start of the function");
   }
   if (!Source)
     return llvm::make_error<StringError>(
@@ -359,6 +375,11 @@
       UnaryNodeOperator::MaybeAddressOf, std::string(ExprId));
 }
 
+Stencil transformer::nodeAsString(StringRef Id) {
+  return std::make_shared<StencilImpl<UnaryOperationData>>(
+      UnaryNodeOperator::AsString, std::string(Id));
+}
+
 Stencil transformer::access(StringRef BaseId, Stencil Member) {
   return std::make_shared<StencilImpl<AccessData>>(BaseId, std::move(Member));
 }
Index: clang/include/clang/Tooling/Transformer/Stencil.h
===================================================================
--- clang/include/clang/Tooling/Transformer/Stencil.h
+++ clang/include/clang/Tooling/Transformer/Stencil.h
@@ -123,6 +123,10 @@
 /// Stencil.  This supports user-defined extensions to the \c Stencil language.
 Stencil run(MatchConsumer<std::string> C);
 
+/// Produces a human-readable rendering of the node bound to `Id`, suitable for
+/// diagnostics and debugging.
+Stencil nodeAsString(llvm::StringRef Id);
+
 /// For debug use only; semantics are not guaranteed.
 ///
 /// \returns the string resulting from calling the node's print() method.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D92658: [libToo... Yitzhak Mandelbaum via Phabricator via cfe-commits
    • [PATCH] D92658: [l... Yitzhak Mandelbaum via Phabricator via cfe-commits

Reply via email to