1 //===--- CheckerRegistry.cpp - Maintains all available checkers -*- C++ -*-===// 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/Core/CheckerRegistry.h" 11 #include "clang/Basic/Diagnostic.h" 12 #include "clang/Frontend/FrontendDiagnostic.h" 13 #include "clang/StaticAnalyzer/Core/CheckerOptInfo.h" 14 #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" 15 #include "llvm/ADT/SetVector.h" 16 #include "llvm/Support/raw_ostream.h" 17 18 using namespace clang; 19 using namespace ento; 20 21 static const char PackageSeparator = '.'; 22 typedef llvm::SetVector<const CheckerRegistry::CheckerInfo *> CheckerInfoSet; 23 24 25 static bool checkerNameLT(const CheckerRegistry::CheckerInfo &a, 26 const CheckerRegistry::CheckerInfo &b) { 27 return a.FullName < b.FullName; 28 } 29 30 static bool isInPackage(const CheckerRegistry::CheckerInfo &checker, 31 StringRef packageName) { 32 // Does the checker's full name have the package as a prefix? 33 if (!checker.FullName.startswith(packageName)) 34 return false; 35 36 // Is the package actually just the name of a specific checker? 37 if (checker.FullName.size() == packageName.size()) 38 return true; 39 40 // Is the checker in the package (or a subpackage)? 41 if (checker.FullName[packageName.size()] == PackageSeparator) 42 return true; 43 44 return false; 45 } 46 47 static void collectCheckers(const CheckerRegistry::CheckerInfoList &checkers, 48 const llvm::StringMap<size_t> &packageSizes, 49 CheckerOptInfo &opt, CheckerInfoSet &collected) { 50 // Use a binary search to find the possible start of the package. 51 CheckerRegistry::CheckerInfo packageInfo(nullptr, opt.getName(), ""); 52 CheckerRegistry::CheckerInfoList::const_iterator e = checkers.end(); 53 CheckerRegistry::CheckerInfoList::const_iterator i = 54 std::lower_bound(checkers.begin(), e, packageInfo, checkerNameLT); 55 56 // If we didn't even find a possible package, give up. 57 if (i == e) 58 return; 59 60 // If what we found doesn't actually start the package, give up. 61 if (!isInPackage(*i, opt.getName())) 62 return; 63 64 // There is at least one checker in the package; claim the option. 65 opt.claim(); 66 67 // See how large the package is. 68 // If the package doesn't exist, assume the option refers to a single checker. 69 size_t size = 1; 70 llvm::StringMap<size_t>::const_iterator packageSize = 71 packageSizes.find(opt.getName()); 72 if (packageSize != packageSizes.end()) 73 size = packageSize->getValue(); 74 75 // Step through all the checkers in the package. 76 for (e = i+size; i != e; ++i) { 77 if (opt.isEnabled()) 78 collected.insert(&*i); 79 else 80 collected.remove(&*i); 81 } 82 } 83 84 void CheckerRegistry::addChecker(InitializationFunction fn, StringRef name, 85 StringRef desc) { 86 Checkers.push_back(CheckerInfo(fn, name, desc)); 87 88 // Record the presence of the checker in its packages. 89 StringRef packageName, leafName; 90 std::tie(packageName, leafName) = name.rsplit(PackageSeparator); 91 while (!leafName.empty()) { 92 Packages[packageName] += 1; 93 std::tie(packageName, leafName) = packageName.rsplit(PackageSeparator); 94 } 95 } 96 97 void CheckerRegistry::initializeManager(CheckerManager &checkerMgr, 98 SmallVectorImpl<CheckerOptInfo> &opts) const { 99 // Sort checkers for efficient collection. 100 std::sort(Checkers.begin(), Checkers.end(), checkerNameLT); 101 102 // Collect checkers enabled by the options. 103 CheckerInfoSet enabledCheckers; 104 for (SmallVectorImpl<CheckerOptInfo>::iterator 105 i = opts.begin(), e = opts.end(); i != e; ++i) { 106 collectCheckers(Checkers, Packages, *i, enabledCheckers); 107 } 108 109 // Initialize the CheckerManager with all enabled checkers. 110 for (CheckerInfoSet::iterator 111 i = enabledCheckers.begin(), e = enabledCheckers.end(); i != e; ++i) { 112 checkerMgr.setCurrentCheckName(CheckName((*i)->FullName)); 113 (*i)->Initialize(checkerMgr); 114 } 115 } 116 117 void CheckerRegistry::validateCheckerOptions(const AnalyzerOptions &opts, 118 DiagnosticsEngine &diags) const { 119 for (auto &config : opts.Config) { 120 size_t pos = config.getKey().find(':'); 121 if (pos == StringRef::npos) 122 continue; 123 124 bool hasChecker = false; 125 StringRef checkerName = config.getKey().substr(0, pos); 126 for (auto &checker : Checkers) { 127 if (checker.FullName.startswith(checkerName) && 128 (checker.FullName.size() == pos || checker.FullName[pos] == '.')) { 129 hasChecker = true; 130 break; 131 } 132 } 133 if (!hasChecker) { 134 diags.Report(diag::err_unknown_analyzer_checker) << checkerName; 135 } 136 } 137 } 138 139 void CheckerRegistry::printHelp(raw_ostream &out, 140 size_t maxNameChars) const { 141 // FIXME: Alphabetical sort puts 'experimental' in the middle. 142 // Would it be better to name it '~experimental' or something else 143 // that's ASCIIbetically last? 144 std::sort(Checkers.begin(), Checkers.end(), checkerNameLT); 145 146 // FIXME: Print available packages. 147 148 out << "CHECKERS:\n"; 149 150 // Find the maximum option length. 151 size_t optionFieldWidth = 0; 152 for (CheckerInfoList::const_iterator i = Checkers.begin(), e = Checkers.end(); 153 i != e; ++i) { 154 // Limit the amount of padding we are willing to give up for alignment. 155 // Package.Name Description [Hidden] 156 size_t nameLength = i->FullName.size(); 157 if (nameLength <= maxNameChars) 158 optionFieldWidth = std::max(optionFieldWidth, nameLength); 159 } 160 161 const size_t initialPad = 2; 162 for (CheckerInfoList::const_iterator i = Checkers.begin(), e = Checkers.end(); 163 i != e; ++i) { 164 out.indent(initialPad) << i->FullName; 165 166 int pad = optionFieldWidth - i->FullName.size(); 167 168 // Break on long option names. 169 if (pad < 0) { 170 out << '\n'; 171 pad = optionFieldWidth + initialPad; 172 } 173 out.indent(pad + 2) << i->Desc; 174 175 out << '\n'; 176 } 177 } 178