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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits