1 //===- CheckerRegistry.cpp - Maintains all available checkers -------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h" 11 #include "clang/Basic/Diagnostic.h" 12 #include "clang/Basic/LLVM.h" 13 #include "clang/Frontend/FrontendDiagnostic.h" 14 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" 15 #include "clang/StaticAnalyzer/Core/CheckerManager.h" 16 #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" 17 #include "llvm/ADT/STLExtras.h" 18 #include "llvm/ADT/SetVector.h" 19 #include "llvm/ADT/StringMap.h" 20 #include "llvm/ADT/StringRef.h" 21 #include "llvm/Support/DynamicLibrary.h" 22 #include "llvm/Support/Path.h" 23 #include "llvm/Support/raw_ostream.h" 24 #include <algorithm> 25 26 using namespace clang; 27 using namespace ento; 28 using llvm::sys::DynamicLibrary; 29 30 using RegisterCheckersFn = void (*)(CheckerRegistry &); 31 32 static bool isCompatibleAPIVersion(const char *versionString) { 33 // If the version string is null, it's not an analyzer plugin. 34 if (!versionString) 35 return false; 36 37 // For now, none of the static analyzer API is considered stable. 38 // Versions must match exactly. 39 return strcmp(versionString, CLANG_ANALYZER_API_VERSION_STRING) == 0; 40 } 41 42 CheckerRegistry::CheckerRegistry(ArrayRef<std::string> plugins, 43 DiagnosticsEngine &diags) : Diags(diags) { 44 #define GET_CHECKERS 45 #define CHECKER(FULLNAME, CLASS, HELPTEXT) \ 46 addChecker(register##CLASS, FULLNAME, HELPTEXT); 47 #include "clang/StaticAnalyzer/Checkers/Checkers.inc" 48 #undef CHECKER 49 #undef GET_CHECKERS 50 51 for (ArrayRef<std::string>::iterator i = plugins.begin(), e = plugins.end(); 52 i != e; ++i) { 53 // Get access to the plugin. 54 std::string err; 55 DynamicLibrary lib = DynamicLibrary::getPermanentLibrary(i->c_str(), &err); 56 if (!lib.isValid()) { 57 diags.Report(diag::err_fe_unable_to_load_plugin) << *i << err; 58 continue; 59 } 60 61 // See if it's compatible with this build of clang. 62 const char *pluginAPIVersion = 63 (const char *) lib.getAddressOfSymbol("clang_analyzerAPIVersionString"); 64 if (!isCompatibleAPIVersion(pluginAPIVersion)) { 65 Diags.Report(diag::warn_incompatible_analyzer_plugin_api) 66 << llvm::sys::path::filename(*i); 67 Diags.Report(diag::note_incompatible_analyzer_plugin_api) 68 << CLANG_ANALYZER_API_VERSION_STRING 69 << pluginAPIVersion; 70 continue; 71 } 72 73 // Register its checkers. 74 RegisterCheckersFn registerPluginCheckers = 75 (RegisterCheckersFn) (intptr_t) lib.getAddressOfSymbol( 76 "clang_registerCheckers"); 77 if (registerPluginCheckers) 78 registerPluginCheckers(*this); 79 } 80 } 81 82 static constexpr char PackageSeparator = '.'; 83 84 static bool checkerNameLT(const CheckerRegistry::CheckerInfo &a, 85 const CheckerRegistry::CheckerInfo &b) { 86 return a.FullName < b.FullName; 87 } 88 89 static bool isInPackage(const CheckerRegistry::CheckerInfo &checker, 90 StringRef packageName) { 91 // Does the checker's full name have the package as a prefix? 92 if (!checker.FullName.startswith(packageName)) 93 return false; 94 95 // Is the package actually just the name of a specific checker? 96 if (checker.FullName.size() == packageName.size()) 97 return true; 98 99 // Is the checker in the package (or a subpackage)? 100 if (checker.FullName[packageName.size()] == PackageSeparator) 101 return true; 102 103 return false; 104 } 105 106 CheckerRegistry::CheckerInfoSet CheckerRegistry::getEnabledCheckers( 107 const AnalyzerOptions &Opts) const { 108 109 assert(std::is_sorted(Checkers.begin(), Checkers.end(), checkerNameLT) && 110 "In order to efficiently gather checkers, this function expects them " 111 "to be already sorted!"); 112 113 CheckerInfoSet enabledCheckers; 114 const auto end = Checkers.cend(); 115 116 for (const std::pair<std::string, bool> &opt : Opts.CheckersControlList) { 117 // Use a binary search to find the possible start of the package. 118 CheckerRegistry::CheckerInfo packageInfo(nullptr, opt.first, ""); 119 auto firstRelatedChecker = 120 std::lower_bound(Checkers.cbegin(), end, packageInfo, checkerNameLT); 121 122 if (firstRelatedChecker == end || 123 !isInPackage(*firstRelatedChecker, opt.first)) { 124 Diags.Report(diag::err_unknown_analyzer_checker) << opt.first; 125 Diags.Report(diag::note_suggest_disabling_all_checkers); 126 return {}; 127 } 128 129 // See how large the package is. 130 // If the package doesn't exist, assume the option refers to a single 131 // checker. 132 size_t size = 1; 133 llvm::StringMap<size_t>::const_iterator packageSize = 134 Packages.find(opt.first); 135 if (packageSize != Packages.end()) 136 size = packageSize->getValue(); 137 138 // Step through all the checkers in the package. 139 for (auto lastRelatedChecker = firstRelatedChecker+size; 140 firstRelatedChecker != lastRelatedChecker; ++firstRelatedChecker) 141 if (opt.second) 142 enabledCheckers.insert(&*firstRelatedChecker); 143 else 144 enabledCheckers.remove(&*firstRelatedChecker); 145 } 146 147 return enabledCheckers; 148 } 149 150 void CheckerRegistry::addChecker(InitializationFunction fn, StringRef name, 151 StringRef desc) { 152 Checkers.push_back(CheckerInfo(fn, name, desc)); 153 154 // Record the presence of the checker in its packages. 155 StringRef packageName, leafName; 156 std::tie(packageName, leafName) = name.rsplit(PackageSeparator); 157 while (!leafName.empty()) { 158 Packages[packageName] += 1; 159 std::tie(packageName, leafName) = packageName.rsplit(PackageSeparator); 160 } 161 } 162 163 void CheckerRegistry::initializeManager(CheckerManager &checkerMgr, 164 const AnalyzerOptions &Opts) const { 165 // Sort checkers for efficient collection. 166 llvm::sort(Checkers, checkerNameLT); 167 168 // Collect checkers enabled by the options. 169 CheckerInfoSet enabledCheckers = getEnabledCheckers(Opts); 170 171 // Initialize the CheckerManager with all enabled checkers. 172 for (const auto *i : enabledCheckers) { 173 checkerMgr.setCurrentCheckName(CheckName(i->FullName)); 174 i->Initialize(checkerMgr); 175 } 176 } 177 178 void CheckerRegistry::validateCheckerOptions( 179 const AnalyzerOptions &opts) const { 180 for (const auto &config : opts.Config) { 181 size_t pos = config.getKey().find(':'); 182 if (pos == StringRef::npos) 183 continue; 184 185 bool hasChecker = false; 186 StringRef checkerName = config.getKey().substr(0, pos); 187 for (const auto &checker : Checkers) { 188 if (checker.FullName.startswith(checkerName) && 189 (checker.FullName.size() == pos || checker.FullName[pos] == '.')) { 190 hasChecker = true; 191 break; 192 } 193 } 194 if (!hasChecker) 195 Diags.Report(diag::err_unknown_analyzer_checker) << checkerName; 196 } 197 } 198 199 void CheckerRegistry::printHelp(raw_ostream &out, 200 size_t maxNameChars) const { 201 // FIXME: Alphabetical sort puts 'experimental' in the middle. 202 // Would it be better to name it '~experimental' or something else 203 // that's ASCIIbetically last? 204 llvm::sort(Checkers, checkerNameLT); 205 206 // FIXME: Print available packages. 207 208 out << "CHECKERS:\n"; 209 210 // Find the maximum option length. 211 size_t optionFieldWidth = 0; 212 for (const auto &i : Checkers) { 213 // Limit the amount of padding we are willing to give up for alignment. 214 // Package.Name Description [Hidden] 215 size_t nameLength = i.FullName.size(); 216 if (nameLength <= maxNameChars) 217 optionFieldWidth = std::max(optionFieldWidth, nameLength); 218 } 219 220 const size_t initialPad = 2; 221 for (const auto &i : Checkers) { 222 out.indent(initialPad) << i.FullName; 223 224 int pad = optionFieldWidth - i.FullName.size(); 225 226 // Break on long option names. 227 if (pad < 0) { 228 out << '\n'; 229 pad = optionFieldWidth + initialPad; 230 } 231 out.indent(pad + 2) << i.Desc; 232 233 out << '\n'; 234 } 235 } 236 237 void CheckerRegistry::printList(raw_ostream &out, 238 const AnalyzerOptions &opts) const { 239 // Sort checkers for efficient collection. 240 llvm::sort(Checkers, checkerNameLT); 241 242 // Collect checkers enabled by the options. 243 CheckerInfoSet enabledCheckers = getEnabledCheckers(opts); 244 245 for (const auto *i : enabledCheckers) 246 out << i->FullName << '\n'; 247 } 248