File indexing completed on 2024-04-28 16:57:50
0001 /* 0002 This file is part of the clazy static checker. 0003 0004 Copyright (C) 2017 Sergio Martins <smartins@kde.org> 0005 0006 This library is free software; you can redistribute it and/or 0007 modify it under the terms of the GNU Library General Public 0008 License as published by the Free Software Foundation; either 0009 version 2 of the License, or (at your option) any later version. 0010 0011 This library is distributed in the hope that it will be useful, 0012 but WITHOUT ANY WARRANTY; without even the implied warranty of 0013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0014 Library General Public License for more details. 0015 0016 You should have received a copy of the GNU Library General Public License 0017 along with this library; see the file COPYING.LIB. If not, write to 0018 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0019 Boston, MA 02110-1301, USA. 0020 */ 0021 0022 // clazy:excludeall=non-pod-global-static 0023 0024 #include "Clazy.h" 0025 #include "ClazyContext.h" 0026 0027 #include "checks.json.h" 0028 0029 #include <clang/Tooling/CommonOptionsParser.h> 0030 #include <clang/Tooling/Tooling.h> 0031 #include <llvm/Support/CommandLine.h> 0032 #include <llvm/ADT/ArrayRef.h> 0033 #include <llvm/ADT/StringRef.h> 0034 0035 #include <iostream> 0036 #include <string> 0037 0038 namespace clang { 0039 class FrontendAction; 0040 } // namespace clang 0041 0042 using namespace clang; 0043 using namespace clang::tooling; 0044 using namespace llvm; 0045 0046 static llvm::cl::OptionCategory s_clazyCategory("clazy options"); 0047 static cl::opt<std::string> s_checks("checks", cl::desc("Comma-separated list of clazy checks. Default is level1"), 0048 cl::init(""), cl::cat(s_clazyCategory)); 0049 0050 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."), 0051 cl::init(""), cl::cat(s_clazyCategory)); 0052 0053 static cl::opt<bool> s_qt4Compat("qt4-compat", cl::desc("Turns off checks not compatible with Qt 4"), 0054 cl::init(false), cl::cat(s_clazyCategory)); 0055 0056 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."), 0057 cl::init(false), cl::cat(s_clazyCategory)); 0058 0059 static cl::opt<bool> s_qtDeveloper("qt-developer", cl::desc("For running clazy on Qt itself, optional, but honours specific guidelines"), 0060 cl::init(false), cl::cat(s_clazyCategory)); 0061 0062 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"), 0063 cl::init(false), cl::cat(s_clazyCategory)); 0064 0065 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."), 0066 cl::init(false), cl::cat(s_clazyCategory)); 0067 0068 static cl::opt<std::string> s_headerFilter("header-filter", 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(""), cl::cat(s_clazyCategory)); 0073 0074 static cl::opt<std::string> s_ignoreDirs("ignore-dirs", cl::desc(R"(Regular expression matching the names of the 0075 directories for which diagnostics should never be emitted. Useful for ignoring 3rdparty code.)"), 0076 cl::init(""), cl::cat(s_clazyCategory)); 0077 0078 static cl::opt<bool> s_supportedChecks("supported-checks-json", cl::desc("Dump meta information about supported checks in JSON format."), 0079 cl::init(false), cl::cat(s_clazyCategory)); 0080 0081 static cl::opt<bool> s_listEnabledChecks("list-checks", cl::desc("List all enabled checks and exit."), 0082 cl::init(false), cl::cat(s_clazyCategory)); 0083 0084 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."), 0085 cl::init(""), cl::cat(s_clazyCategory)); 0086 0087 static cl::extrahelp s_commonHelp(CommonOptionsParser::HelpMessage); 0088 0089 class ClazyToolActionFactory 0090 : public clang::tooling::FrontendActionFactory 0091 { 0092 public: 0093 ClazyToolActionFactory(std::vector<std::string> paths) 0094 : FrontendActionFactory() 0095 , m_paths(std::move(paths)) 0096 { 0097 } 0098 0099 #if LLVM_VERSION_MAJOR >= 10 0100 std::unique_ptr<FrontendAction> create() override 0101 #else 0102 FrontendAction *create() override 0103 #endif 0104 { 0105 ClazyContext::ClazyOptions options = ClazyContext::ClazyOption_None; 0106 0107 if (!s_exportFixes.getValue().empty()) 0108 options |= ClazyContext::ClazyOption_ExportFixes; 0109 0110 if (s_qt4Compat.getValue()) 0111 options |= ClazyContext::ClazyOption_Qt4Compat; 0112 0113 if (s_qtDeveloper.getValue()) 0114 options |= ClazyContext::ClazyOption_QtDeveloper; 0115 0116 if (s_onlyQt.getValue()) 0117 options |= ClazyContext::ClazyOption_OnlyQt; 0118 0119 if (s_visitImplicitCode.getValue()) 0120 options |= ClazyContext::ClazyOption_VisitImplicitCode; 0121 0122 if (s_ignoreIncludedFiles.getValue()) 0123 options |= ClazyContext::ClazyOption_IgnoreIncludedFiles; 0124 0125 // TODO: We need to agregate the fixes with previous run 0126 #if LLVM_VERSION_MAJOR >= 10 0127 return std::make_unique<ClazyStandaloneASTAction>(s_checks.getValue(), s_headerFilter.getValue(), 0128 s_ignoreDirs.getValue(), s_exportFixes.getValue(), 0129 m_paths, options); 0130 #else 0131 return new ClazyStandaloneASTAction(s_checks.getValue(), s_headerFilter.getValue(), 0132 s_ignoreDirs.getValue(), s_exportFixes.getValue(), 0133 m_paths, options); 0134 #endif 0135 } 0136 std::vector<std::string> m_paths; 0137 }; 0138 0139 llvm::IntrusiveRefCntPtr<vfs::FileSystem> getVfsFromFile(const std::string &overlayFile, llvm::IntrusiveRefCntPtr<vfs::FileSystem> BaseFS) 0140 { 0141 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> buffer = BaseFS->getBufferForFile( 0142 overlayFile); 0143 if (!buffer) { 0144 llvm::errs() << "Can't load virtual filesystem overlay file '" << overlayFile 0145 << "': " << buffer.getError().message() << ".\n"; 0146 return nullptr; 0147 } 0148 0149 IntrusiveRefCntPtr<vfs::FileSystem> fs = vfs::getVFSFromYAML(std::move(buffer.get()), 0150 /*DiagHandler*/ nullptr, 0151 overlayFile); 0152 if (!fs) { 0153 llvm::errs() << "Error: invalid virtual filesystem overlay file '" << overlayFile << "'.\n"; 0154 return nullptr; 0155 } 0156 return fs; 0157 } 0158 0159 int main(int argc, const char **argv) 0160 { 0161 for (int i = 1; i < argc; i++) { 0162 if (strcmp(argv[i], "--version") == 0) { 0163 std::cout << "clazy version 1.11\n"; 0164 break; 0165 } 0166 } 0167 0168 auto expectedParser = CommonOptionsParser::create(argc, argv, s_clazyCategory, cl::ZeroOrMore); 0169 if (!expectedParser) { 0170 llvm::errs() << expectedParser.takeError(); 0171 return 1; 0172 } 0173 0174 auto &optionsParser = expectedParser.get(); 0175 // llvm::errs() << optionsParser.getSourcePathList().size() << "\n"; 0176 0177 if (s_supportedChecks.getValue()) { 0178 std::cout << SUPPORTED_CHECKS_JSON_STR; 0179 return 0; 0180 } 0181 0182 if (s_listEnabledChecks.getValue()) { 0183 std::string checksFromArgs = s_checks.getValue(); 0184 std::vector<std::string> checks = { checksFromArgs.empty() ? "level1" : checksFromArgs }; 0185 const RegisteredCheck::List enabledChecks 0186 = CheckManager::instance()->requestedChecks(checks, s_qt4Compat.getValue()); 0187 0188 if (!enabledChecks.empty()) { 0189 llvm::outs() << "Enabled checks:"; 0190 for (const auto &check : enabledChecks) { 0191 llvm::outs() << "\n " << check.name; 0192 } 0193 llvm::outs() << "\n"; 0194 } 0195 0196 return 0; 0197 } 0198 0199 llvm::IntrusiveRefCntPtr<vfs::OverlayFileSystem> fs( 0200 new vfs::OverlayFileSystem(vfs::getRealFileSystem())); 0201 const std::string &overlayFile = s_vfsoverlay.getValue(); 0202 if (!s_vfsoverlay.getValue().empty()) { 0203 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> buffer = fs->getBufferForFile( 0204 overlayFile); 0205 if (!buffer) { 0206 llvm::errs() << "Can't load virtual filesystem overlay file '" << overlayFile 0207 << "': " << buffer.getError().message() << ".\n"; 0208 return 0; 0209 } 0210 0211 IntrusiveRefCntPtr<vfs::FileSystem> vfso = vfs::getVFSFromYAML(std::move(buffer.get()), 0212 /*DiagHandler*/ nullptr, 0213 overlayFile); 0214 if (!vfso) { 0215 llvm::errs() << "Error: invalid virtual filesystem overlay file '" << overlayFile 0216 << "'.\n"; 0217 return 0; 0218 } 0219 fs->pushOverlay(vfso); 0220 } 0221 0222 ClangTool tool(optionsParser.getCompilations(), 0223 optionsParser.getSourcePathList(), 0224 std::make_shared<PCHContainerOperations>(), 0225 fs); 0226 0227 return tool.run(new ClazyToolActionFactory(optionsParser.getSourcePathList())); 0228 }