[Lldb-commits] [PATCH] D116377: [libTooling] Adds more support for constructing object access expressions.

2022-01-26 Thread Yitzhak Mandelbaum via Phabricator via lldb-commits
ymandel updated this revision to Diff 402984.
ymandel added a comment.
Herald added a subscriber: JDevlieghere.

fix bad previous snapshot


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D116377

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

Index: clang/unittests/Tooling/StencilTest.cpp
===
--- clang/unittests/Tooling/StencilTest.cpp
+++ clang/unittests/Tooling/StencilTest.cpp
@@ -36,10 +36,13 @@
 namespace N { class C {}; }
 namespace { class AnonC {}; }
 struct S { int Field; };
-struct Smart {
-  S* operator->() const;
-  S& operator*() const;
+namespace std {
+template 
+struct unique_ptr {
+  T* operator->() const;
+  T& operator*() const;
 };
+}
   )cc";
   return (Preface + ExtraPreface + "auto stencil_test_snippet = []{" +
   StatementCode + "};")
@@ -326,32 +329,15 @@
 TEST_F(StencilTest, MaybeDerefSmartPointer) {
   StringRef Id = "id";
   std::string Snippet = R"cc(
-Smart x;
+std::unique_ptr x;
 x;
   )cc";
   testExpr(Id, Snippet, maybeDeref(Id), "*x");
 }
 
-// Tests that unique_ptr specifically is handled.
-TEST_F(StencilTest, MaybeDerefSmartPointerUniquePtr) {
-  StringRef Id = "id";
-  // We deliberately specify `unique_ptr` as empty to verify that it matches
-  // because of its name, rather than its contents.
-  StringRef ExtraPreface =
-  "namespace std { template  class unique_ptr {}; }\n";
-  StringRef Snippet = R"cc(
-std::unique_ptr x;
-x;
-  )cc";
-  auto StmtMatch = matchStmt(Snippet, expr().bind(Id), ExtraPreface);
-  ASSERT_TRUE(StmtMatch);
-  EXPECT_THAT_EXPECTED(maybeDeref(Id)->eval(StmtMatch->Result),
-   HasValue(std::string("*x")));
-}
-
 TEST_F(StencilTest, MaybeDerefSmartPointerFromMemberExpr) {
   StringRef Id = "id";
-  std::string Snippet = "Smart x; x->Field;";
+  std::string Snippet = "std::unique_ptr x; x->Field;";
   auto StmtMatch =
   matchStmt(Snippet, memberExpr(hasObjectExpression(expr().bind(Id;
   ASSERT_TRUE(StmtMatch);
@@ -381,12 +367,12 @@
 
 TEST_F(StencilTest, MaybeAddressOfSmartPointer) {
   StringRef Id = "id";
-  testExpr(Id, "Smart x; x;", maybeAddressOf(Id), "x");
+  testExpr(Id, "std::unique_ptr x; x;", maybeAddressOf(Id), "x");
 }
 
 TEST_F(StencilTest, MaybeAddressOfSmartPointerFromMemberCall) {
   StringRef Id = "id";
-  std::string Snippet = "Smart x; x->Field;";
+  std::string Snippet = "std::unique_ptr x; x->Field;";
   auto StmtMatch =
   matchStmt(Snippet, memberExpr(hasObjectExpression(expr().bind(Id;
   ASSERT_TRUE(StmtMatch);
@@ -396,7 +382,7 @@
 
 TEST_F(StencilTest, MaybeAddressOfSmartPointerDerefNoCancel) {
   StringRef Id = "id";
-  testExpr(Id, "Smart x; *x;", maybeAddressOf(Id), "&*x");
+  testExpr(Id, "std::unique_ptr x; *x;", maybeAddressOf(Id), "&*x");
 }
 
 TEST_F(StencilTest, AccessOpValue) {
@@ -446,7 +432,7 @@
 
 TEST_F(StencilTest, AccessOpSmartPointer) {
   StringRef Snippet = R"cc(
-Smart x;
+std::unique_ptr x;
 x;
   )cc";
   StringRef Id = "id";
@@ -455,7 +441,7 @@
 
 TEST_F(StencilTest, AccessOpSmartPointerDereference) {
   StringRef Snippet = R"cc(
-Smart x;
+std::unique_ptr x;
 *x;
   )cc";
   StringRef Id = "id";
@@ -464,7 +450,7 @@
 
 TEST_F(StencilTest, AccessOpSmartPointerMemberCall) {
   StringRef Snippet = R"cc(
-Smart x;
+std::unique_ptr x;
 x->Field;
   )cc";
   StringRef Id = "id";
Index: clang/unittests/Tooling/SourceCodeBuildersTest.cpp
===
--- clang/unittests/Tooling/SourceCodeBuildersTest.cpp
+++ clang/unittests/Tooling/SourceCodeBuildersTest.cpp
@@ -7,6 +7,7 @@
 //===--===//
 
 #include "clang/Tooling/Transformer/SourceCodeBuilders.h"
+#include "clang/AST/Type.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/ASTMatchers/ASTMatchers.h"
 #include "clang/Tooling/Tooling.h"
@@ -24,8 +25,23 @@
 
 // Create a valid translation unit from a statement.
 static std::string wrapSnippet(StringRef StatementCode) {
-  return ("struct S { S(); S(int); int field; };\n"
+  return ("namespace std {\n"
+  "template  struct unique_ptr {\n"
+  "  T* operator->() const;\n"
+  "  T& operator*() const;\n"
+  "};\n"
+  "template  struct shared_ptr {\n"
+  "  T* operator->() const;\n"
+  "  T& operator*() const;\n"
+  "};\n"
+  "}\n"
+  "struct A { void super(); };\n"
+  "struct S : public A { S(); S(int); int Field; };\n"
   "S operator+(const S &a, const S &b);\n"
+

[Lldb-commits] [PATCH] D87031: [libTooling] Provide overloads of `rewriteDescendants` that operate directly on an AST node.

2020-09-04 Thread Yitzhak Mandelbaum via Phabricator via lldb-commits
ymandel updated this revision to Diff 289623.
ymandel added a comment.
Herald added a subscriber: JDevlieghere.

fix diff base; make small clang-tidy suggested change


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D87031

Files:
  clang/include/clang/Tooling/Transformer/RewriteRule.h
  clang/lib/Tooling/Transformer/RewriteRule.cpp
  clang/unittests/Tooling/TransformerTest.cpp

Index: clang/unittests/Tooling/TransformerTest.cpp
===
--- clang/unittests/Tooling/TransformerTest.cpp
+++ clang/unittests/Tooling/TransformerTest.cpp
@@ -25,6 +25,7 @@
 using ::testing::IsEmpty;
 using transformer::cat;
 using transformer::changeTo;
+using transformer::rewriteDescendants;
 using transformer::RewriteRule;
 
 constexpr char KHeaderContents[] = R"cc(
@@ -568,6 +569,88 @@
   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("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("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("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() {
Index: clang/lib/Tooling/Transformer/RewriteRule.cpp
===
--- clang/lib/Tooling/Transformer/RewriteRule.cpp
+++ clang/lib/Tooling/Transfor

[Lldb-commits] [PATCH] D61386: [clang-tidy] Add support writing a check as a Transformer rewrite rule.

2019-10-04 Thread Yitzhak Mandelbaum via Phabricator via lldb-commits
ymandel marked 2 inline comments as done.
ymandel added inline comments.



Comment at: clang-tools-extra/clang-tidy/utils/TransformerClangTidyCheck.cpp:46
+
+  StringRef Message = "no explanation";
+  if (Case.Explanation) {

ilya-biryukov wrote:
> ymandel wrote:
> > ilya-biryukov wrote:
> > > ymandel wrote:
> > > > ilya-biryukov wrote:
> > > > > The users will see this for every case without explanation, right?
> > > > > I'd expect the rules without explanation to be somewhat common, maybe 
> > > > > don't show any message at all in that case?
> > > > There's no option to call `diag()` without a message.  We could pass an 
> > > > empty string , but that may be confusing given the way the message is 
> > > > concatenated here:
> > > > https://github.com/llvm/llvm-project/blob/master/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp#L204
> > > > 
> > > > So, no matter what, there will be some message to go w/ the diagnostic. 
> > > > I figure that being explicit about the lack of explanation is better 
> > > > than an empty string, but don't feel strongly about this.
> > > Ah, so all the options are bad. I can see why you had this design in 
> > > transformers in the first place.
> > > I wonder if we should check the explanations are always set for rewrite 
> > > rules inside the clang-tidy transformation?
> > > Ah, so all the options are bad. I can see why you had this design in 
> > > transformers in the first place.
> > Heh. indeed.
> > 
> > > I wonder if we should check the explanations are always set for rewrite 
> > > rules inside the clang-tidy transformation?> Quoted Text
> > 
> > I would have thought so, but AFAIK, most folks who write one-off 
> > transformations use clang-tidy, rather than writing a standalone tool. They 
> > just ignore the diagnostics, i gather.  Transformer may shift that somewhat 
> > if we improve the experience of writing a (throwaway) standalone tool, but 
> > for the time being I think we can't assume that.
> > 
> We should focus on minimizing maintenance cost for long-term fixes rather 
> than one-off transformations. The cost of passing an empty string to a 
> required explanation field for one-off transformations is rather small and 
> falls into the hands of a person writing the check, the cost of constantly 
> finding and fixing the long-lived upstream checks that don't have explanation 
> (leading to bad user experience) is high and will probably fall into the 
> hands of `clang-tidy` maintainers in addition to people writing the checks.
> 
> FWIW, having a new API of top of plain transformers should be better than 
> `clang-tidy` for those writing one-off transformations in the long run. I 
> don't think `clang-tidy` was ever designed to cover to cover those use-cases, 
> even though today it seems to be the fastest way to do those.
Agreed on all points. I'll send a followup that enforces that constraint.


Repository:
  rL LLVM

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

https://reviews.llvm.org/D61386



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


[Lldb-commits] [PATCH] D61386: [clang-tidy] Add support writing a check as a Transformer rewrite rule.

2019-10-04 Thread Yitzhak Mandelbaum via Phabricator via lldb-commits
ymandel updated this revision to Diff 200802.
ymandel removed a subscriber: dexonsmith.
ymandel added a comment.

Replace previous diff which had the wrong base.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D61386

Files:
  clang-tools-extra/clang-tidy/utils/CMakeLists.txt
  clang-tools-extra/clang-tidy/utils/TransformerClangTidyCheck.cpp
  clang-tools-extra/clang-tidy/utils/TransformerClangTidyCheck.h
  clang-tools-extra/unittests/clang-tidy/CMakeLists.txt
  clang-tools-extra/unittests/clang-tidy/TransformerClangTidyCheckTest.cpp

Index: clang-tools-extra/unittests/clang-tidy/TransformerClangTidyCheckTest.cpp
===
--- /dev/null
+++ clang-tools-extra/unittests/clang-tidy/TransformerClangTidyCheckTest.cpp
@@ -0,0 +1,68 @@
+//=== TransformerClangTidyCheckTest.cpp - clang-tidy --===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+
+#include "../clang-tidy/utils/TransformerClangTidyCheck.h"
+#include "ClangTidyTest.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Tooling/Refactoring/RangeSelector.h"
+#include "clang/Tooling/Refactoring/Stencil.h"
+#include "clang/Tooling/Refactoring/Transformer.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace tidy {
+namespace utils {
+namespace {
+using tooling::RewriteRule;
+
+// Invert the code of an if-statement, while maintaining its semantics.
+RewriteRule invertIf() {
+  using namespace ::clang::ast_matchers;
+  using tooling::change;
+  using tooling::node;
+  using tooling::statement;
+  using tooling::stencil::cat;
+
+  StringRef C = "C", T = "T", E = "E";
+  return tooling::makeRule(ifStmt(hasCondition(expr().bind(C)),
+  hasThen(stmt().bind(T)),
+  hasElse(stmt().bind(E))),
+   change(statement(RewriteRule::RootID),
+  cat("if(!(", node(C), ")) ", statement(E),
+  " else ", statement(T;
+}
+
+class IfInverterCheck : public TransformerClangTidyCheck {
+public:
+  IfInverterCheck(StringRef Name, ClangTidyContext *Context)
+  : TransformerClangTidyCheck(invertIf(), Name, Context) {}
+};
+
+// Basic test of using a rewrite rule as a ClangTidy.
+TEST(TransformerClangTidyCheckTest, Basic) {
+  const std::string Input = R"cc(
+void log(const char* msg);
+void foo() {
+  if (10 > 1.0)
+log("oh no!");
+  else
+log("ok");
+}
+  )cc";
+  const std::string Expected = R"(
+void log(const char* msg);
+void foo() {
+  if(!(10 > 1.0)) log("ok"); else log("oh no!");
+}
+  )";
+  EXPECT_EQ(Expected, test::runCheckOnCode(Input));
+}
+} // namespace
+} // namespace utils
+} // namespace tidy
+} // namespace clang
Index: clang-tools-extra/unittests/clang-tidy/CMakeLists.txt
===
--- clang-tools-extra/unittests/clang-tidy/CMakeLists.txt
+++ clang-tools-extra/unittests/clang-tidy/CMakeLists.txt
@@ -17,6 +17,7 @@
   OverlappingReplacementsTest.cpp
   UsingInserterTest.cpp
   ReadabilityModuleTest.cpp
+  TransformerClangTidyCheckTest.cpp
   )
 
 target_link_libraries(ClangTidyTests
@@ -36,4 +37,5 @@
   clangTidyUtils
   clangTooling
   clangToolingCore
+  clangToolingRefactor
   )
Index: clang-tools-extra/clang-tidy/utils/TransformerClangTidyCheck.h
===
--- /dev/null
+++ clang-tools-extra/clang-tidy/utils/TransformerClangTidyCheck.h
@@ -0,0 +1,49 @@
+//===-- TransformerClangTidyCheck.h - clang-tidy --===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_TRANSFORMER_CLANG_TIDY_CHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_TRANSFORMER_CLANG_TIDY_CHECK_H
+
+#include "../ClangTidy.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Tooling/Refactoring/Transformer.h"
+#include 
+#include 
+
+namespace clang {
+namespace tidy {
+namespace utils {
+
+// A base class for defining a ClangTidy check based on a `RewriteRule`.
+//
+// For example, given a rule `MyCheckAsRewriteRule`, one can define a tidy check
+// as follows:
+//
+// class MyCheck : public TransformerClangTidyCheck {
+//  public:
+//   MyCheck(StringRef Name, ClangTidyContext *Context)
+//   : TransformerClangTidyCheck(MyCheckA

[Lldb-commits] [PATCH] D61386: [clang-tidy] Add support writing a check as a Transformer rewrite rule.

2019-10-04 Thread Yitzhak Mandelbaum via Phabricator via lldb-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL361418: [clang-tidy] Add support for writing a check as a 
Transformer rewrite rule. (authored by ymandel, committed by ).

Changed prior to commit:
  https://reviews.llvm.org/D61386?vs=200802&id=200804#toc

Repository:
  rL LLVM

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

https://reviews.llvm.org/D61386

Files:
  clang-tools-extra/trunk/clang-tidy/utils/CMakeLists.txt
  clang-tools-extra/trunk/clang-tidy/utils/TransformerClangTidyCheck.cpp
  clang-tools-extra/trunk/clang-tidy/utils/TransformerClangTidyCheck.h
  clang-tools-extra/trunk/unittests/clang-tidy/CMakeLists.txt
  clang-tools-extra/trunk/unittests/clang-tidy/TransformerClangTidyCheckTest.cpp

Index: clang-tools-extra/trunk/clang-tidy/utils/TransformerClangTidyCheck.h
===
--- clang-tools-extra/trunk/clang-tidy/utils/TransformerClangTidyCheck.h
+++ clang-tools-extra/trunk/clang-tidy/utils/TransformerClangTidyCheck.h
@@ -0,0 +1,49 @@
+//===-- TransformerClangTidyCheck.h - clang-tidy --===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_TRANSFORMER_CLANG_TIDY_CHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_TRANSFORMER_CLANG_TIDY_CHECK_H
+
+#include "../ClangTidy.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Tooling/Refactoring/Transformer.h"
+#include 
+#include 
+
+namespace clang {
+namespace tidy {
+namespace utils {
+
+// A base class for defining a ClangTidy check based on a `RewriteRule`.
+//
+// For example, given a rule `MyCheckAsRewriteRule`, one can define a tidy check
+// as follows:
+//
+// class MyCheck : public TransformerClangTidyCheck {
+//  public:
+//   MyCheck(StringRef Name, ClangTidyContext *Context)
+//   : TransformerClangTidyCheck(MyCheckAsRewriteRule, Name, Context) {}
+// };
+class TransformerClangTidyCheck : public ClangTidyCheck {
+public:
+  TransformerClangTidyCheck(tooling::RewriteRule R, StringRef Name,
+ClangTidyContext *Context)
+  : ClangTidyCheck(Name, Context), Rule(std::move(R)) {}
+
+  void registerMatchers(ast_matchers::MatchFinder *Finder) final;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) final;
+
+private:
+  tooling::RewriteRule Rule;
+};
+
+} // namespace utils
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_TRANSFORMER_CLANG_TIDY_CHECK_H
Index: clang-tools-extra/trunk/clang-tidy/utils/TransformerClangTidyCheck.cpp
===
--- clang-tools-extra/trunk/clang-tidy/utils/TransformerClangTidyCheck.cpp
+++ clang-tools-extra/trunk/clang-tidy/utils/TransformerClangTidyCheck.cpp
@@ -0,0 +1,63 @@
+//===-- TransformerClangTidyCheck.cpp - clang-tidy ===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+
+#include "TransformerClangTidyCheck.h"
+
+namespace clang {
+namespace tidy {
+namespace utils {
+using tooling::RewriteRule;
+
+void TransformerClangTidyCheck::registerMatchers(
+ast_matchers::MatchFinder *Finder) {
+  Finder->addDynamicMatcher(tooling::detail::buildMatcher(Rule), this);
+}
+
+void TransformerClangTidyCheck::check(
+const ast_matchers::MatchFinder::MatchResult &Result) {
+  if (Result.Context->getDiagnostics().hasErrorOccurred())
+return;
+
+  // Verify the existence and validity of the AST node that roots this rule.
+  const ast_matchers::BoundNodes::IDToNodeMap &NodesMap = Result.Nodes.getMap();
+  auto Root = NodesMap.find(RewriteRule::RootID);
+  assert(Root != NodesMap.end() && "Transformation failed: missing root node.");
+  SourceLocation RootLoc = Result.SourceManager->getExpansionLoc(
+  Root->second.getSourceRange().getBegin());
+  assert(RootLoc.isValid() && "Invalid location for Root node of match.");
+
+  RewriteRule::Case Case = tooling::detail::findSelectedCase(Result, Rule);
+  Expected> Transformations =
+  tooling::detail::translateEdits(Result, Case.Edits);
+  if (!Transformations) {
+llvm::errs() << "Rewrite failed: "
+ << llvm::toString(Transformations.takeError()) << "\n";
+return;
+  }
+
+  // No rewrite applied, but no error encountered either.
+  if (Transformations->empty())
+return;
+
+  StringRef Message = "no explanation";
+  if (Case.Explanation) {
+if (Expected E = Case.Explanation(Re