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