CheckerRegistry.cpp revision 6bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89
158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)//===--- CheckerRegistry.cpp - Maintains all available checkers -*- C++ -*-===// 258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// 358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// The LLVM Compiler Infrastructure 458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// 558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// This file is distributed under the University of Illinois Open Source 658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// License. See LICENSE.TXT for details. 758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// 858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)//===----------------------------------------------------------------------===// 958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 1058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "clang/StaticAnalyzer/Core/CheckerRegistry.h" 11a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "clang/StaticAnalyzer/Core/CheckerOptInfo.h" 12a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "llvm/ADT/SetVector.h" 13a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "llvm/Support/raw_ostream.h" 1458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 1558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)using namespace clang; 1658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)using namespace ento; 1758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 1858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)static const char PackageSeparator = '.'; 1958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)typedef llvm::SetVector<const CheckerRegistry::CheckerInfo *> CheckerInfoSet; 2058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 2158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 2258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)static bool checkerNameLT(const CheckerRegistry::CheckerInfo &a, 2358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) const CheckerRegistry::CheckerInfo &b) { 2458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return a.FullName < b.FullName; 2558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 2658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 2758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)static bool isInPackage(const CheckerRegistry::CheckerInfo &checker, 2858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) StringRef packageName) { 2958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // Does the checker's full name have the package as a prefix? 3058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (!checker.FullName.startswith(packageName)) 3158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return false; 3258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 3358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // Is the package actually just the name of a specific checker? 3458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (checker.FullName.size() == packageName.size()) 3558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return true; 3658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 3758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // Is the checker in the package (or a subpackage)? 3858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (checker.FullName[packageName.size()] == PackageSeparator) 3958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return true; 4058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 4158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return false; 4258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 4358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 4458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)static void collectCheckers(const CheckerRegistry::CheckerInfoList &checkers, 4558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) const llvm::StringMap<size_t> &packageSizes, 4658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) CheckerOptInfo &opt, CheckerInfoSet &collected) { 4758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // Use a binary search to find the possible start of the package. 4858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) CheckerRegistry::CheckerInfo packageInfo(nullptr, opt.getName(), ""); 4958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) CheckerRegistry::CheckerInfoList::const_iterator e = checkers.end(); 5058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) CheckerRegistry::CheckerInfoList::const_iterator i = 5158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) std::lower_bound(checkers.begin(), e, packageInfo, checkerNameLT); 5258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 5358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // If we didn't even find a possible package, give up. 5458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (i == e) 5558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return; 5658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 5758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // If what we found doesn't actually start the package, give up. 5858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (!isInPackage(*i, opt.getName())) 5958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return; 6058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 6158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // There is at least one checker in the package; claim the option. 6258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) opt.claim(); 6358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 6458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // See how large the package is. 6558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // If the package doesn't exist, assume the option refers to a single checker. 6658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) size_t size = 1; 6758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) llvm::StringMap<size_t>::const_iterator packageSize = 6858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) packageSizes.find(opt.getName()); 6958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (packageSize != packageSizes.end()) 7058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) size = packageSize->getValue(); 7158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 7258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // Step through all the checkers in the package. 7358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) for (e = i+size; i != e; ++i) { 7458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (opt.isEnabled()) 7558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) collected.insert(&*i); 7658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) else 7758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) collected.remove(&*i); 7858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 7958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 8058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 8158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void CheckerRegistry::addChecker(InitializationFunction fn, StringRef name, 8258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) StringRef desc) { 8358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) Checkers.push_back(CheckerInfo(fn, name, desc)); 8458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 8558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // Record the presence of the checker in its packages. 8658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) StringRef packageName, leafName; 8758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) std::tie(packageName, leafName) = name.rsplit(PackageSeparator); 8858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) while (!leafName.empty()) { 8958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) Packages[packageName] += 1; 9058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) std::tie(packageName, leafName) = packageName.rsplit(PackageSeparator); 9168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } 9258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 9368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 9468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void CheckerRegistry::initializeManager(CheckerManager &checkerMgr, 9568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) SmallVectorImpl<CheckerOptInfo> &opts) const { 9658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // Sort checkers for efficient collection. 9768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) std::sort(Checkers.begin(), Checkers.end(), checkerNameLT); 9868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 9968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) // Collect checkers enabled by the options. 10058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) CheckerInfoSet enabledCheckers; 10168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) for (SmallVectorImpl<CheckerOptInfo>::iterator 10268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) i = opts.begin(), e = opts.end(); i != e; ++i) { 10368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) collectCheckers(Checkers, Packages, *i, enabledCheckers); 10458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 10568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 10668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) // Initialize the CheckerManager with all enabled checkers. 10768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) for (CheckerInfoSet::iterator 10858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) i = enabledCheckers.begin(), e = enabledCheckers.end(); i != e; ++i) { 10968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) checkerMgr.setCurrentCheckName(CheckName((*i)->FullName)); 11068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) (*i)->Initialize(checkerMgr); 11168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } 11258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 11368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 11468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void CheckerRegistry::printHelp(raw_ostream &out, 11568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) size_t maxNameChars) const { 11658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // FIXME: Alphabetical sort puts 'experimental' in the middle. 11768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) // Would it be better to name it '~experimental' or something else 11868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) // that's ASCIIbetically last? 11958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) std::sort(Checkers.begin(), Checkers.end(), checkerNameLT); 12058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 12158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // FIXME: Print available packages. 122 123 out << "CHECKERS:\n"; 124 125 // Find the maximum option length. 126 size_t optionFieldWidth = 0; 127 for (CheckerInfoList::const_iterator i = Checkers.begin(), e = Checkers.end(); 128 i != e; ++i) { 129 // Limit the amount of padding we are willing to give up for alignment. 130 // Package.Name Description [Hidden] 131 size_t nameLength = i->FullName.size(); 132 if (nameLength <= maxNameChars) 133 optionFieldWidth = std::max(optionFieldWidth, nameLength); 134 } 135 136 const size_t initialPad = 2; 137 for (CheckerInfoList::const_iterator i = Checkers.begin(), e = Checkers.end(); 138 i != e; ++i) { 139 out.indent(initialPad) << i->FullName; 140 141 int pad = optionFieldWidth - i->FullName.size(); 142 143 // Break on long option names. 144 if (pad < 0) { 145 out << '\n'; 146 pad = optionFieldWidth + initialPad; 147 } 148 out.indent(pad + 2) << i->Desc; 149 150 out << '\n'; 151 } 152} 153