src/ClazyStandaloneMain.cpp (169 lines of code) (raw):

/* SPDX-FileCopyrightText: 2017 Sergio Martins <smartins@kde.org> SPDX-License-Identifier: LGPL-2.0-or-later */ // clazy:excludeall=non-pod-global-static #include "Clazy.h" #include "ClazyContext.h" #include "checks.json.h" #include <clang/Tooling/CommonOptionsParser.h> #include <clang/Tooling/Tooling.h> #include <llvm/ADT/ArrayRef.h> #include <llvm/ADT/StringRef.h> #include <llvm/Support/CommandLine.h> #include <iostream> #include <string> namespace clang { class FrontendAction; } // namespace clang using namespace clang; using namespace clang::tooling; using namespace llvm; static llvm::cl::OptionCategory s_clazyCategory("clazy options"); static cl::opt<std::string> s_checks("checks", cl::desc("Comma-separated list of clazy checks. Default is level1"), cl::init(""), cl::cat(s_clazyCategory)); static cl::opt<std::string> s_exportFixes("export-fixes", cl::desc("YAML file to store suggested fixes in. The stored fixes can be applied to the input source code with clang-apply-replacements."), cl::init(""), cl::cat(s_clazyCategory)); static cl::opt<bool> s_onlyQt("only-qt", cl::desc("Won't emit warnings for non-Qt files, or in other words, if -DQT_CORE_LIB is missing."), cl::init(false), cl::cat(s_clazyCategory)); static cl::opt<bool> s_qtDeveloper("qt-developer", cl::desc("For running clazy on Qt itself, optional, but honours specific guidelines"), cl::init(false), cl::cat(s_clazyCategory)); static cl::opt<bool> s_visitImplicitCode( "visit-implicit-code", cl::desc( "For visiting implicit code like compiler generated constructors. None of the built-in checks benefit from this, but can be useful for custom checks"), cl::init(false), cl::cat(s_clazyCategory)); static cl::opt<bool> s_ignoreIncludedFiles("ignore-included-files", cl::desc("Only emit warnings for the current file being compiled and ignore any includes. " "Useful for performance reasons. Have a look at a check's README*.md file to see " "if it supports this feature or not."), cl::init(false), cl::cat(s_clazyCategory)); static cl::opt<std::string> s_headerFilter("header-filter", cl::desc(R"(Regular expression matching the names of the headers to output diagnostics from. Diagnostics from the main file of each translation unit are always displayed.)"), cl::init(""), cl::cat(s_clazyCategory)); static cl::opt<std::string> s_ignoreDirs("ignore-dirs", cl::desc(R"(Regular expression matching the names of the directories for which diagnostics should never be emitted. Useful for ignoring 3rdparty code.)"), cl::init(""), cl::cat(s_clazyCategory)); static cl::opt<bool> s_supportedChecks("supported-checks-json", cl::desc("Dump meta information about supported checks in JSON format."), cl::init(false), cl::cat(s_clazyCategory)); static cl::opt<bool> s_listEnabledChecks("list-checks", cl::desc("List all enabled checks and exit."), cl::init(false), cl::cat(s_clazyCategory)); static cl::opt<std::string> s_vfsoverlay("vfsoverlay", cl::desc("YAML file to overlay the virtual filesystem described by file over the real file system."), cl::init(""), cl::cat(s_clazyCategory)); static cl::extrahelp s_commonHelp(CommonOptionsParser::HelpMessage); class ClazyToolActionFactory : public clang::tooling::FrontendActionFactory { public: explicit ClazyToolActionFactory(std::vector<std::string> paths) : FrontendActionFactory() , m_paths(std::move(paths)) { } std::unique_ptr<FrontendAction> create() override { ClazyContext::ClazyOptions options = ClazyContext::ClazyOption_None; if (!s_exportFixes.getValue().empty()) { options |= ClazyContext::ClazyOption_ExportFixes; } if (s_qtDeveloper.getValue()) { options |= ClazyContext::ClazyOption_QtDeveloper; } if (s_onlyQt.getValue()) { options |= ClazyContext::ClazyOption_OnlyQt; } if (s_visitImplicitCode.getValue()) { options |= ClazyContext::ClazyOption_VisitImplicitCode; } if (s_ignoreIncludedFiles.getValue()) { options |= ClazyContext::ClazyOption_IgnoreIncludedFiles; } // TODO: We need to aggregate the fixes with previous run return std::make_unique<ClazyStandaloneASTAction>(s_checks.getValue(), s_headerFilter.getValue(), s_ignoreDirs.getValue(), s_exportFixes.getValue(), m_paths, options); } private: std::vector<std::string> m_paths; }; llvm::IntrusiveRefCntPtr<vfs::FileSystem> getVfsFromFile(const std::string &overlayFile, llvm::IntrusiveRefCntPtr<vfs::FileSystem> BaseFS) { llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> buffer = BaseFS->getBufferForFile(overlayFile); if (!buffer) { llvm::errs() << "Can't load virtual filesystem overlay file '" << overlayFile << "': " << buffer.getError().message() << ".\n"; return nullptr; } IntrusiveRefCntPtr<vfs::FileSystem> fs = vfs::getVFSFromYAML(std::move(buffer.get()), /*DiagHandler*/ nullptr, overlayFile); if (!fs) { llvm::errs() << "Error: invalid virtual filesystem overlay file '" << overlayFile << "'.\n"; return nullptr; } return fs; } int main(int argc, const char **argv) { for (int i = 1; i < argc; i++) { if (strcmp(argv[i], "--version") == 0) { std::cout << "clazy version " << CLAZY_VERSION << "\n"; break; } } auto expectedParser = CommonOptionsParser::create(argc, argv, s_clazyCategory, cl::ZeroOrMore); if (!expectedParser) { llvm::errs() << expectedParser.takeError(); return 1; } auto &optionsParser = expectedParser.get(); // llvm::errs() << optionsParser.getSourcePathList().size() << "\n"; if (s_supportedChecks.getValue()) { std::cout << SUPPORTED_CHECKS_JSON_STR; return 0; } if (s_listEnabledChecks.getValue()) { std::string checksFromArgs = s_checks.getValue(); std::vector<std::string> checks = {checksFromArgs.empty() ? "level1" : checksFromArgs}; const RegisteredCheck::List enabledChecks = CheckManager::instance()->requestedChecks(checks); if (!enabledChecks.empty()) { llvm::outs() << "Enabled checks:"; for (const auto &check : enabledChecks) { llvm::outs() << "\n " << check.name; } llvm::outs() << "\n"; } return 0; } llvm::IntrusiveRefCntPtr<vfs::OverlayFileSystem> fs(new vfs::OverlayFileSystem(vfs::getRealFileSystem())); const std::string &overlayFile = s_vfsoverlay.getValue(); if (!s_vfsoverlay.getValue().empty()) { llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> buffer = fs->getBufferForFile(overlayFile); if (!buffer) { llvm::errs() << "Can't load virtual filesystem overlay file '" << overlayFile << "': " << buffer.getError().message() << ".\n"; return 0; } IntrusiveRefCntPtr<vfs::FileSystem> vfso = vfs::getVFSFromYAML(std::move(buffer.get()), /*DiagHandler*/ nullptr, overlayFile); if (!vfso) { llvm::errs() << "Error: invalid virtual filesystem overlay file '" << overlayFile << "'.\n"; return 0; } fs->pushOverlay(vfso); } ClangTool tool(optionsParser.getCompilations(), optionsParser.getSourcePathList(), std::make_shared<PCHContainerOperations>(), fs); return tool.run(new ClazyToolActionFactory(optionsParser.getSourcePathList())); }