File indexing completed on 2024-04-28 09:33:46
0001 /* 0002 SPDX-FileCopyrightText: 2017 Sergio Martins <smartins@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 // clazy:excludeall=non-pod-global-static 0008 0009 #include "Clazy.h" 0010 #include "ClazyContext.h" 0011 0012 #include "checks.json.h" 0013 0014 #include <clang/Tooling/CommonOptionsParser.h> 0015 #include <clang/Tooling/Tooling.h> 0016 #include <llvm/ADT/ArrayRef.h> 0017 #include <llvm/ADT/StringRef.h> 0018 #include <llvm/Support/CommandLine.h> 0019 0020 #include <iostream> 0021 #include <string> 0022 0023 namespace clang 0024 { 0025 class FrontendAction; 0026 } // namespace clang 0027 0028 using namespace clang; 0029 using namespace clang::tooling; 0030 using namespace llvm; 0031 0032 static llvm::cl::OptionCategory s_clazyCategory("clazy options"); 0033 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)); 0034 0035 static cl::opt<std::string> 0036 s_exportFixes("export-fixes", 0037 cl::desc("YAML file to store suggested fixes in. The stored fixes can be applied to the input source code with clang-apply-replacements."), 0038 cl::init(""), 0039 cl::cat(s_clazyCategory)); 0040 0041 static cl::opt<bool> s_qt4Compat("qt4-compat", cl::desc("Turns off checks not compatible with Qt 4"), cl::init(false), cl::cat(s_clazyCategory)); 0042 0043 static cl::opt<bool> s_onlyQt("only-qt", 0044 cl::desc("Won't emit warnings for non-Qt files, or in other words, if -DQT_CORE_LIB is missing."), 0045 cl::init(false), 0046 cl::cat(s_clazyCategory)); 0047 0048 static cl::opt<bool> s_qtDeveloper("qt-developer", 0049 cl::desc("For running clazy on Qt itself, optional, but honours specific guidelines"), 0050 cl::init(false), 0051 cl::cat(s_clazyCategory)); 0052 0053 static cl::opt<bool> s_visitImplicitCode( 0054 "visit-implicit-code", 0055 cl::desc( 0056 "For visiting implicit code like compiler generated constructors. None of the built-in checks benefit from this, but can be useful for custom checks"), 0057 cl::init(false), 0058 cl::cat(s_clazyCategory)); 0059 0060 static cl::opt<bool> s_ignoreIncludedFiles("ignore-included-files", 0061 cl::desc("Only emit warnings for the current file being compiled and ignore any includes. " 0062 "Useful for performance reasons. Have a look at a check's README*.md file to see " 0063 "if it supports this feature or not."), 0064 cl::init(false), 0065 cl::cat(s_clazyCategory)); 0066 0067 static cl::opt<std::string> s_headerFilter("header-filter", 0068 cl::desc(R"(Regular expression matching the names of the 0069 headers to output diagnostics from. Diagnostics 0070 from the main file of each translation unit are 0071 always displayed.)"), 0072 cl::init(""), 0073 cl::cat(s_clazyCategory)); 0074 0075 static cl::opt<std::string> s_ignoreDirs("ignore-dirs", 0076 cl::desc(R"(Regular expression matching the names of the 0077 directories for which diagnostics should never be emitted. Useful for ignoring 3rdparty code.)"), 0078 cl::init(""), 0079 cl::cat(s_clazyCategory)); 0080 0081 static cl::opt<bool> s_supportedChecks("supported-checks-json", 0082 cl::desc("Dump meta information about supported checks in JSON format."), 0083 cl::init(false), 0084 cl::cat(s_clazyCategory)); 0085 0086 static cl::opt<bool> s_listEnabledChecks("list-checks", cl::desc("List all enabled checks and exit."), cl::init(false), cl::cat(s_clazyCategory)); 0087 0088 static cl::opt<std::string> s_vfsoverlay("vfsoverlay", 0089 cl::desc("YAML file to overlay the virtual filesystem described by file over the real file system."), 0090 cl::init(""), 0091 cl::cat(s_clazyCategory)); 0092 0093 static cl::extrahelp s_commonHelp(CommonOptionsParser::HelpMessage); 0094 0095 class ClazyToolActionFactory : public clang::tooling::FrontendActionFactory 0096 { 0097 public: 0098 ClazyToolActionFactory(std::vector<std::string> paths) 0099 : FrontendActionFactory() 0100 , m_paths(std::move(paths)) 0101 { 0102 } 0103 0104 #if LLVM_VERSION_MAJOR >= 10 0105 std::unique_ptr<FrontendAction> create() override 0106 #else 0107 FrontendAction *create() override 0108 #endif 0109 { 0110 ClazyContext::ClazyOptions options = ClazyContext::ClazyOption_None; 0111 0112 if (!s_exportFixes.getValue().empty()) { 0113 options |= ClazyContext::ClazyOption_ExportFixes; 0114 } 0115 0116 if (s_qt4Compat.getValue()) { 0117 options |= ClazyContext::ClazyOption_Qt4Compat; 0118 } 0119 0120 if (s_qtDeveloper.getValue()) { 0121 options |= ClazyContext::ClazyOption_QtDeveloper; 0122 } 0123 0124 if (s_onlyQt.getValue()) { 0125 options |= ClazyContext::ClazyOption_OnlyQt; 0126 } 0127 0128 if (s_visitImplicitCode.getValue()) { 0129 options |= ClazyContext::ClazyOption_VisitImplicitCode; 0130 } 0131 0132 if (s_ignoreIncludedFiles.getValue()) { 0133 options |= ClazyContext::ClazyOption_IgnoreIncludedFiles; 0134 } 0135 0136 // TODO: We need to agregate the fixes with previous run 0137 return std::make_unique<ClazyStandaloneASTAction>(s_checks.getValue(), 0138 s_headerFilter.getValue(), 0139 s_ignoreDirs.getValue(), 0140 s_exportFixes.getValue(), 0141 m_paths, 0142 options); 0143 } 0144 std::vector<std::string> m_paths; 0145 }; 0146 0147 llvm::IntrusiveRefCntPtr<vfs::FileSystem> getVfsFromFile(const std::string &overlayFile, llvm::IntrusiveRefCntPtr<vfs::FileSystem> BaseFS) 0148 { 0149 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> buffer = BaseFS->getBufferForFile(overlayFile); 0150 if (!buffer) { 0151 llvm::errs() << "Can't load virtual filesystem overlay file '" << overlayFile << "': " << buffer.getError().message() << ".\n"; 0152 return nullptr; 0153 } 0154 0155 IntrusiveRefCntPtr<vfs::FileSystem> fs = vfs::getVFSFromYAML(std::move(buffer.get()), 0156 /*DiagHandler*/ nullptr, 0157 overlayFile); 0158 if (!fs) { 0159 llvm::errs() << "Error: invalid virtual filesystem overlay file '" << overlayFile << "'.\n"; 0160 return nullptr; 0161 } 0162 return fs; 0163 } 0164 0165 int main(int argc, const char **argv) 0166 { 0167 for (int i = 1; i < argc; i++) { 0168 if (strcmp(argv[i], "--version") == 0) { 0169 std::cout << "clazy version 1.12\n"; 0170 break; 0171 } 0172 } 0173 0174 auto expectedParser = CommonOptionsParser::create(argc, argv, s_clazyCategory, cl::ZeroOrMore); 0175 if (!expectedParser) { 0176 llvm::errs() << expectedParser.takeError(); 0177 return 1; 0178 } 0179 0180 auto &optionsParser = expectedParser.get(); 0181 // llvm::errs() << optionsParser.getSourcePathList().size() << "\n"; 0182 0183 if (s_supportedChecks.getValue()) { 0184 std::cout << SUPPORTED_CHECKS_JSON_STR; 0185 return 0; 0186 } 0187 0188 if (s_listEnabledChecks.getValue()) { 0189 std::string checksFromArgs = s_checks.getValue(); 0190 std::vector<std::string> checks = {checksFromArgs.empty() ? "level1" : checksFromArgs}; 0191 const RegisteredCheck::List enabledChecks = CheckManager::instance()->requestedChecks(checks, s_qt4Compat.getValue()); 0192 0193 if (!enabledChecks.empty()) { 0194 llvm::outs() << "Enabled checks:"; 0195 for (const auto &check : enabledChecks) { 0196 llvm::outs() << "\n " << check.name; 0197 } 0198 llvm::outs() << "\n"; 0199 } 0200 0201 return 0; 0202 } 0203 0204 llvm::IntrusiveRefCntPtr<vfs::OverlayFileSystem> fs(new vfs::OverlayFileSystem(vfs::getRealFileSystem())); 0205 const std::string &overlayFile = s_vfsoverlay.getValue(); 0206 if (!s_vfsoverlay.getValue().empty()) { 0207 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> buffer = fs->getBufferForFile(overlayFile); 0208 if (!buffer) { 0209 llvm::errs() << "Can't load virtual filesystem overlay file '" << overlayFile << "': " << buffer.getError().message() << ".\n"; 0210 return 0; 0211 } 0212 0213 IntrusiveRefCntPtr<vfs::FileSystem> vfso = vfs::getVFSFromYAML(std::move(buffer.get()), 0214 /*DiagHandler*/ nullptr, 0215 overlayFile); 0216 if (!vfso) { 0217 llvm::errs() << "Error: invalid virtual filesystem overlay file '" << overlayFile << "'.\n"; 0218 return 0; 0219 } 0220 fs->pushOverlay(vfso); 0221 } 0222 0223 ClangTool tool(optionsParser.getCompilations(), optionsParser.getSourcePathList(), std::make_shared<PCHContainerOperations>(), fs); 0224 0225 return tool.run(new ClazyToolActionFactory(optionsParser.getSourcePathList())); 0226 }