feat(tidy): Add new fairmq-tidy tool

This commit is contained in:
Dennis Klein
2021-06-15 13:56:40 +02:00
parent 8e6c50e7cc
commit db727092c5
8 changed files with 236 additions and 3 deletions

View File

@@ -0,0 +1,24 @@
################################################################################
# Copyright (C) 2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
# #
# This software is distributed under the terms of the #
# GNU Lesser General Public Licence (LGPL) version 3, #
# copied verbatim in the file "LICENSE" #
################################################################################
set(target fairmq-tidy)
add_executable(${target}
ModernizeNonNamespacedTypes.h
Tool.h
runTool.cpp
)
target_compile_features(${target} PRIVATE cxx_std_17)
target_link_libraries(${target} PRIVATE clang-cpp LLVM)
target_include_directories(${target} PRIVATE
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}>
$<BUILD_INTERFACE:${CMAKE_BINARY_DIR}>
)
install(TARGETS ${target}
EXPORT ${PROJECT_EXPORT_SET}
RUNTIME DESTINATION ${PROJECT_INSTALL_BINDIR}
)

View File

@@ -0,0 +1,81 @@
/********************************************************************************
* Copyright (C) 2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/
#ifndef FAIR_MQ_TIDY_MODERNIZENONNAMESPACEDTYPES
#define FAIR_MQ_TIDY_MODERNIZENONNAMESPACEDTYPES
#include <clang/AST/AST.h>
#include <clang/ASTMatchers/ASTMatchFinder.h>
#include <clang/ASTMatchers/ASTMatchers.h>
#include <clang/Basic/Diagnostic.h>
#include <llvm/Support/Casting.h>
#include <sstream>
namespace fair::mq::tidy {
struct ModernizeNonNamespacedTypes
{
ModernizeNonNamespacedTypes() = delete;
ModernizeNonNamespacedTypes(clang::ast_matchers::MatchFinder& finder)
{
using namespace clang::ast_matchers;
// https://clang.llvm.org/docs/LibASTMatchersReference.html
finder.addMatcher(
typeLoc(loc(qualType(hasDeclaration(namedDecl(matchesName("FairMQ.*")).bind("decl")))))
.bind("loc"),
&fCallback);
}
struct Callback : clang::ast_matchers::MatchFinder::MatchCallback
{
auto run(clang::ast_matchers::MatchFinder::MatchResult const& m) -> void final
{
using namespace clang;
auto const type_loc(m.Nodes.getNodeAs<TypeLoc>("loc"));
auto const named_decl(m.Nodes.getNodeAs<NamedDecl>("decl"));
if (auto const type_alias_decl = m.Nodes.getNodeAs<TypeAliasDecl>("decl")) {
auto const underlying_type(type_alias_decl->getUnderlyingType());
// auto ldecl_ctx(type_loc->getType()getLexicalDeclContext());
// std::stringstream s;
// while (ldecl_ctx) {
// s << "." << ldecl_ctx->getDeclKindName();
// if (ldecl_ctx->isNamespace()) {
// s << dyn_cast<NamespaceDecl>(ldecl_ctx)->getNameAsString();
// }
// ldecl_ctx = ldecl_ctx->getLexicalParent();
// }
if (underlying_type.getAsString().rfind("fair::mq::", 0) == 0) {
auto& diag_engine(m.Context->getDiagnostics());
auto builder(
diag_engine.Report(type_loc->getBeginLoc(),
diag_engine.getCustomDiagID(
DiagnosticsEngine::Warning,
"Modernize non-namespaced type %0 with %1. [%2]")));
builder << named_decl;
builder << underlying_type;
builder << "fairmq-modernize-nonnamespaced-types";
builder.AddFixItHint(FixItHint::CreateReplacement(
type_loc->getSourceRange(), underlying_type.getAsString()));
}
}
}
};
private:
Callback fCallback;
};
} // namespace fair::mq::tidy
#endif /* FAIR_MQ_TIDY_MODERNIZENONNAMESPACEDTYPES */

76
fairmq/tidy/Tool.h Normal file
View File

@@ -0,0 +1,76 @@
/********************************************************************************
* Copyright (C) 2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/
#ifndef FAIR_MQ_TIDY_TOOL
#define FAIR_MQ_TIDY_TOOL
#include <clang/ASTMatchers/ASTMatchFinder.h>
#include <clang/Basic/FileManager.h>
#include <clang/Tooling/CompilationDatabase.h>
#include <clang/Tooling/Tooling.h>
#include <fairmq/tidy/ModernizeNonNamespacedTypes.h>
#include <string>
namespace fair::mq::tidy {
// Getting up to speed, read this:
// https://clang.llvm.org/docs/LibTooling.html
// https://clang.llvm.org/docs/IntroductionToTheClangAST.html
// Watch https://www.youtube.com/watch?v=VqCkCDFLSsc !!!
//
// optional, but helpful:
// https://static.linaro.org/connect/yvr18/presentations/yvr18-223.pdf
// https://steveire.wordpress.com/2018/11/20/composing-ast-matchers-in-clang-tidy/
// https://www.goldsborough.me/c++/clang/llvm/tools/2017/02/24/00-00-06-emitting_diagnostics_and_fixithints_in_clang_tools/
// https://steveire.com/CodeDive2018Presentation.pdf
//
// reference (no built-in search, however google will find things):
// https://clang.llvm.org/doxygen/
//
// Note: Implementing a standalone tool will impose double PP and parsing cost if one also
// runs clang-tidy. At the moment, one cannot extend clang-tidy with new checks without
// recompiling clang-tidy. In principle llvm-project/clang-extra-tools/clang-tidy
// has install rules, but Fedora is not packaging them which is likely due to their
// unstable state (lots of comments aka todo, fixme, refactor etc). Also, it seems
// focus has shifted towards implementing the
// https://microsoft.github.io/language-server-protocol/
// via https://clangd.llvm.org/ which includes clang-tidy, but also does not have
// an extension/plugin interface for third-party checks yet AFAICS.
struct Tool
{
static auto run(clang::tooling::CompilationDatabase const &compilations,
clang::ArrayRef<std::string> sources) -> int
{
using namespace clang;
// compose all checks in a single match finder
ast_matchers::MatchFinder finder;
ModernizeNonNamespacedTypes check1(finder);
// configure the clang tool
tooling::ClangTool tool(compilations, sources);
tool.appendArgumentsAdjuster(
[](tooling::CommandLineArguments const &_args, StringRef /*file*/) {
tooling::CommandLineArguments args(_args);
// TODO add only if cdb was generated with GCC
args.emplace(args.begin() + 1, "-I/usr/lib64/clang/12.0.0/include");
// TODO add only if missing
args.emplace(args.begin() + 1, "-std=c++17");
args.emplace_back("-Wno-everything");
return args;
});
// run checks on given files
return tool.run(clang::tooling::newFrontendActionFactory(&finder).get());
}
};
} // namespace fair::mq::tidy
#endif /* FAIR_MQ_TIDY_TOOL */

29
fairmq/tidy/runTool.cpp Normal file
View File

@@ -0,0 +1,29 @@
/********************************************************************************
* Copyright (C) 2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/
#include <clang/Tooling/CommonOptionsParser.h>
#include <clang/Tooling/Tooling.h>
#include <fairmq/tidy/Tool.h>
#include <llvm/ADT/STLExtras.h>
#include <llvm/Support/CommandLine.h>
static llvm::cl::OptionCategory ToolCategory("fairmq-tidy options");
static llvm::cl::extrahelp CommonHelp(clang::tooling::CommonOptionsParser::HelpMessage);
int main(int argc, const char** argv)
{
// TODO Replace command line parser with CLI11
auto parser(clang::tooling::CommonOptionsParser::create(
argc, argv, ToolCategory, llvm::cl::NumOccurrencesFlag::Optional, ""));
if (!parser) {
llvm::errs() << parser.takeError();
return EXIT_FAILURE;
}
return fair::mq::tidy::Tool::run(parser->getCompilations(), parser->getSourcePathList());
}