[clang-tools-extra] r361418 - [clang-tidy] Add support for writing a check as a Transformer rewrite rule.
Yitzhak Mandelbaum via cfe-commits
cfe-commits at lists.llvm.org
Wed May 22 11:56:18 PDT 2019
Author: ymandel
Date: Wed May 22 11:56:18 2019
New Revision: 361418
URL: http://llvm.org/viewvc/llvm-project?rev=361418&view=rev
Log:
[clang-tidy] Add support for writing a check as a Transformer rewrite rule.
This revision introduces an adaptor from Transformer's rewrite rules
(`clang::tooling::RewriteRule`) to `ClangTidyCheck`. For example, given a
RewriteRule `MyCheckAsRewriteRule`, it lets one define a tidy check as follows:
```
class MyTidyCheck : public TransformerClangTidyCheck {
public:
MyTidyCheck(StringRef Name, ClangTidyContext *Context)
: TransformerClangTidyCheck(MyCheckAsRewriteRule, Name, Context) {}
};
```
Reviewers: aaron.ballman
Subscribers: mgorny, xazax.hun, cfe-commits, ilya-biryukov
Tags: #clang
Differential Revision: https://reviews.llvm.org/D61386
Added:
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/TransformerClangTidyCheckTest.cpp
Modified:
clang-tools-extra/trunk/clang-tidy/utils/CMakeLists.txt
clang-tools-extra/trunk/unittests/clang-tidy/CMakeLists.txt
Modified: clang-tools-extra/trunk/clang-tidy/utils/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/utils/CMakeLists.txt?rev=361418&r1=361417&r2=361418&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/utils/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/clang-tidy/utils/CMakeLists.txt Wed May 22 11:56:18 2019
@@ -13,6 +13,7 @@ add_clang_library(clangTidyUtils
LexerUtils.cpp
NamespaceAliaser.cpp
OptionsUtils.cpp
+ TransformerClangTidyCheck.cpp
TypeTraits.cpp
UsingInserter.cpp
@@ -22,4 +23,5 @@ add_clang_library(clangTidyUtils
clangBasic
clangLex
clangTidy
+ clangToolingRefactor
)
Added: clang-tools-extra/trunk/clang-tidy/utils/TransformerClangTidyCheck.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/utils/TransformerClangTidyCheck.cpp?rev=361418&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/utils/TransformerClangTidyCheck.cpp (added)
+++ clang-tools-extra/trunk/clang-tidy/utils/TransformerClangTidyCheck.cpp Wed May 22 11:56:18 2019
@@ -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<SmallVector<tooling::detail::Transformation, 1>> 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<std::string> E = Case.Explanation(Result))
+ Message = *E;
+ else
+ llvm::errs() << "Error in explanation: " << llvm::toString(E.takeError())
+ << "\n";
+ }
+ DiagnosticBuilder Diag = diag(RootLoc, Message);
+ for (const auto &T : *Transformations) {
+ Diag << FixItHint::CreateReplacement(T.Range, T.Replacement);
+ }
+}
+
+} // namespace utils
+} // namespace tidy
+} // namespace clang
Added: clang-tools-extra/trunk/clang-tidy/utils/TransformerClangTidyCheck.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/utils/TransformerClangTidyCheck.h?rev=361418&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/utils/TransformerClangTidyCheck.h (added)
+++ clang-tools-extra/trunk/clang-tidy/utils/TransformerClangTidyCheck.h Wed May 22 11:56:18 2019
@@ -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 <deque>
+#include <vector>
+
+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
Modified: clang-tools-extra/trunk/unittests/clang-tidy/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clang-tidy/CMakeLists.txt?rev=361418&r1=361417&r2=361418&view=diff
==============================================================================
--- clang-tools-extra/trunk/unittests/clang-tidy/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/unittests/clang-tidy/CMakeLists.txt Wed May 22 11:56:18 2019
@@ -17,6 +17,7 @@ add_extra_unittest(ClangTidyTests
OverlappingReplacementsTest.cpp
UsingInserterTest.cpp
ReadabilityModuleTest.cpp
+ TransformerClangTidyCheckTest.cpp
)
target_link_libraries(ClangTidyTests
@@ -36,4 +37,5 @@ target_link_libraries(ClangTidyTests
clangTidyUtils
clangTooling
clangToolingCore
+ clangToolingRefactor
)
Added: clang-tools-extra/trunk/unittests/clang-tidy/TransformerClangTidyCheckTest.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clang-tidy/TransformerClangTidyCheckTest.cpp?rev=361418&view=auto
==============================================================================
--- clang-tools-extra/trunk/unittests/clang-tidy/TransformerClangTidyCheckTest.cpp (added)
+++ clang-tools-extra/trunk/unittests/clang-tidy/TransformerClangTidyCheckTest.cpp Wed May 22 11:56:18 2019
@@ -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<IfInverterCheck>(Input));
+}
+} // namespace
+} // namespace utils
+} // namespace tidy
+} // namespace clang
More information about the cfe-commits
mailing list