108b86531ade68727c56918f162816075b87c864aJordy Rose//===--- CheckerRegistry.cpp - Maintains all available checkers -*- C++ -*-===// 208b86531ade68727c56918f162816075b87c864aJordy Rose// 308b86531ade68727c56918f162816075b87c864aJordy Rose// The LLVM Compiler Infrastructure 408b86531ade68727c56918f162816075b87c864aJordy Rose// 508b86531ade68727c56918f162816075b87c864aJordy Rose// This file is distributed under the University of Illinois Open Source 608b86531ade68727c56918f162816075b87c864aJordy Rose// License. See LICENSE.TXT for details. 708b86531ade68727c56918f162816075b87c864aJordy Rose// 808b86531ade68727c56918f162816075b87c864aJordy Rose//===----------------------------------------------------------------------===// 908b86531ade68727c56918f162816075b87c864aJordy Rose 1008b86531ade68727c56918f162816075b87c864aJordy Rose#include "clang/StaticAnalyzer/Core/CheckerRegistry.h" 1108b86531ade68727c56918f162816075b87c864aJordy Rose#include "clang/StaticAnalyzer/Core/CheckerOptInfo.h" 12557a3829ebe0e36785b9a7679dc19dc67dbc7639Anna Zaks#include "llvm/ADT/SetVector.h" 13a93d0f280693b8418bc88cf7a8c93325f7fcf4c6Benjamin Kramer#include "llvm/Support/raw_ostream.h" 1408b86531ade68727c56918f162816075b87c864aJordy Rose 1508b86531ade68727c56918f162816075b87c864aJordy Roseusing namespace clang; 1608b86531ade68727c56918f162816075b87c864aJordy Roseusing namespace ento; 1708b86531ade68727c56918f162816075b87c864aJordy Rose 1808b86531ade68727c56918f162816075b87c864aJordy Rosestatic const char PackageSeparator = '.'; 19557a3829ebe0e36785b9a7679dc19dc67dbc7639Anna Zakstypedef llvm::SetVector<const CheckerRegistry::CheckerInfo *> CheckerInfoSet; 2008b86531ade68727c56918f162816075b87c864aJordy Rose 2108b86531ade68727c56918f162816075b87c864aJordy Rose 2208b86531ade68727c56918f162816075b87c864aJordy Rosestatic bool checkerNameLT(const CheckerRegistry::CheckerInfo &a, 2308b86531ade68727c56918f162816075b87c864aJordy Rose const CheckerRegistry::CheckerInfo &b) { 2408b86531ade68727c56918f162816075b87c864aJordy Rose return a.FullName < b.FullName; 2508b86531ade68727c56918f162816075b87c864aJordy Rose} 2608b86531ade68727c56918f162816075b87c864aJordy Rose 2708b86531ade68727c56918f162816075b87c864aJordy Rosestatic bool isInPackage(const CheckerRegistry::CheckerInfo &checker, 2808b86531ade68727c56918f162816075b87c864aJordy Rose StringRef packageName) { 2908b86531ade68727c56918f162816075b87c864aJordy Rose // Does the checker's full name have the package as a prefix? 3008b86531ade68727c56918f162816075b87c864aJordy Rose if (!checker.FullName.startswith(packageName)) 3108b86531ade68727c56918f162816075b87c864aJordy Rose return false; 3208b86531ade68727c56918f162816075b87c864aJordy Rose 3308b86531ade68727c56918f162816075b87c864aJordy Rose // Is the package actually just the name of a specific checker? 3408b86531ade68727c56918f162816075b87c864aJordy Rose if (checker.FullName.size() == packageName.size()) 3508b86531ade68727c56918f162816075b87c864aJordy Rose return true; 3608b86531ade68727c56918f162816075b87c864aJordy Rose 3708b86531ade68727c56918f162816075b87c864aJordy Rose // Is the checker in the package (or a subpackage)? 3808b86531ade68727c56918f162816075b87c864aJordy Rose if (checker.FullName[packageName.size()] == PackageSeparator) 3908b86531ade68727c56918f162816075b87c864aJordy Rose return true; 4008b86531ade68727c56918f162816075b87c864aJordy Rose 4108b86531ade68727c56918f162816075b87c864aJordy Rose return false; 4208b86531ade68727c56918f162816075b87c864aJordy Rose} 4308b86531ade68727c56918f162816075b87c864aJordy Rose 4408b86531ade68727c56918f162816075b87c864aJordy Rosestatic void collectCheckers(const CheckerRegistry::CheckerInfoList &checkers, 4508b86531ade68727c56918f162816075b87c864aJordy Rose const llvm::StringMap<size_t> &packageSizes, 4608b86531ade68727c56918f162816075b87c864aJordy Rose CheckerOptInfo &opt, CheckerInfoSet &collected) { 4708b86531ade68727c56918f162816075b87c864aJordy Rose // Use a binary search to find the possible start of the package. 486bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines CheckerRegistry::CheckerInfo packageInfo(nullptr, opt.getName(), ""); 4908b86531ade68727c56918f162816075b87c864aJordy Rose CheckerRegistry::CheckerInfoList::const_iterator e = checkers.end(); 5008b86531ade68727c56918f162816075b87c864aJordy Rose CheckerRegistry::CheckerInfoList::const_iterator i = 5108b86531ade68727c56918f162816075b87c864aJordy Rose std::lower_bound(checkers.begin(), e, packageInfo, checkerNameLT); 5208b86531ade68727c56918f162816075b87c864aJordy Rose 5308b86531ade68727c56918f162816075b87c864aJordy Rose // If we didn't even find a possible package, give up. 5408b86531ade68727c56918f162816075b87c864aJordy Rose if (i == e) 5508b86531ade68727c56918f162816075b87c864aJordy Rose return; 5608b86531ade68727c56918f162816075b87c864aJordy Rose 5708b86531ade68727c56918f162816075b87c864aJordy Rose // If what we found doesn't actually start the package, give up. 5808b86531ade68727c56918f162816075b87c864aJordy Rose if (!isInPackage(*i, opt.getName())) 5908b86531ade68727c56918f162816075b87c864aJordy Rose return; 6008b86531ade68727c56918f162816075b87c864aJordy Rose 6108b86531ade68727c56918f162816075b87c864aJordy Rose // There is at least one checker in the package; claim the option. 6208b86531ade68727c56918f162816075b87c864aJordy Rose opt.claim(); 6308b86531ade68727c56918f162816075b87c864aJordy Rose 6408b86531ade68727c56918f162816075b87c864aJordy Rose // See how large the package is. 6508b86531ade68727c56918f162816075b87c864aJordy Rose // If the package doesn't exist, assume the option refers to a single checker. 6608b86531ade68727c56918f162816075b87c864aJordy Rose size_t size = 1; 6708b86531ade68727c56918f162816075b87c864aJordy Rose llvm::StringMap<size_t>::const_iterator packageSize = 6808b86531ade68727c56918f162816075b87c864aJordy Rose packageSizes.find(opt.getName()); 6908b86531ade68727c56918f162816075b87c864aJordy Rose if (packageSize != packageSizes.end()) 7008b86531ade68727c56918f162816075b87c864aJordy Rose size = packageSize->getValue(); 7108b86531ade68727c56918f162816075b87c864aJordy Rose 7208b86531ade68727c56918f162816075b87c864aJordy Rose // Step through all the checkers in the package. 7308b86531ade68727c56918f162816075b87c864aJordy Rose for (e = i+size; i != e; ++i) { 7408b86531ade68727c56918f162816075b87c864aJordy Rose if (opt.isEnabled()) 7508b86531ade68727c56918f162816075b87c864aJordy Rose collected.insert(&*i); 7608b86531ade68727c56918f162816075b87c864aJordy Rose else 77557a3829ebe0e36785b9a7679dc19dc67dbc7639Anna Zaks collected.remove(&*i); 7808b86531ade68727c56918f162816075b87c864aJordy Rose } 7908b86531ade68727c56918f162816075b87c864aJordy Rose} 8008b86531ade68727c56918f162816075b87c864aJordy Rose 8108b86531ade68727c56918f162816075b87c864aJordy Rosevoid CheckerRegistry::addChecker(InitializationFunction fn, StringRef name, 8208b86531ade68727c56918f162816075b87c864aJordy Rose StringRef desc) { 8308b86531ade68727c56918f162816075b87c864aJordy Rose Checkers.push_back(CheckerInfo(fn, name, desc)); 8408b86531ade68727c56918f162816075b87c864aJordy Rose 8508b86531ade68727c56918f162816075b87c864aJordy Rose // Record the presence of the checker in its packages. 8608b86531ade68727c56918f162816075b87c864aJordy Rose StringRef packageName, leafName; 87651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines std::tie(packageName, leafName) = name.rsplit(PackageSeparator); 8808b86531ade68727c56918f162816075b87c864aJordy Rose while (!leafName.empty()) { 8908b86531ade68727c56918f162816075b87c864aJordy Rose Packages[packageName] += 1; 90651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines std::tie(packageName, leafName) = packageName.rsplit(PackageSeparator); 9108b86531ade68727c56918f162816075b87c864aJordy Rose } 9208b86531ade68727c56918f162816075b87c864aJordy Rose} 9308b86531ade68727c56918f162816075b87c864aJordy Rose 9408b86531ade68727c56918f162816075b87c864aJordy Rosevoid CheckerRegistry::initializeManager(CheckerManager &checkerMgr, 9508b86531ade68727c56918f162816075b87c864aJordy Rose SmallVectorImpl<CheckerOptInfo> &opts) const { 9608b86531ade68727c56918f162816075b87c864aJordy Rose // Sort checkers for efficient collection. 9708b86531ade68727c56918f162816075b87c864aJordy Rose std::sort(Checkers.begin(), Checkers.end(), checkerNameLT); 9808b86531ade68727c56918f162816075b87c864aJordy Rose 9908b86531ade68727c56918f162816075b87c864aJordy Rose // Collect checkers enabled by the options. 10008b86531ade68727c56918f162816075b87c864aJordy Rose CheckerInfoSet enabledCheckers; 10108b86531ade68727c56918f162816075b87c864aJordy Rose for (SmallVectorImpl<CheckerOptInfo>::iterator 10208b86531ade68727c56918f162816075b87c864aJordy Rose i = opts.begin(), e = opts.end(); i != e; ++i) { 10308b86531ade68727c56918f162816075b87c864aJordy Rose collectCheckers(Checkers, Packages, *i, enabledCheckers); 10408b86531ade68727c56918f162816075b87c864aJordy Rose } 10508b86531ade68727c56918f162816075b87c864aJordy Rose 10608b86531ade68727c56918f162816075b87c864aJordy Rose // Initialize the CheckerManager with all enabled checkers. 10708b86531ade68727c56918f162816075b87c864aJordy Rose for (CheckerInfoSet::iterator 10808b86531ade68727c56918f162816075b87c864aJordy Rose i = enabledCheckers.begin(), e = enabledCheckers.end(); i != e; ++i) { 109651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines checkerMgr.setCurrentCheckName(CheckName((*i)->FullName)); 11008b86531ade68727c56918f162816075b87c864aJordy Rose (*i)->Initialize(checkerMgr); 11108b86531ade68727c56918f162816075b87c864aJordy Rose } 11208b86531ade68727c56918f162816075b87c864aJordy Rose} 11308b86531ade68727c56918f162816075b87c864aJordy Rose 114cfa88f893915ceb8ae4ce2f17c46c24a4d67502fDmitri Gribenkovoid CheckerRegistry::printHelp(raw_ostream &out, 11508b86531ade68727c56918f162816075b87c864aJordy Rose size_t maxNameChars) const { 11608b86531ade68727c56918f162816075b87c864aJordy Rose // FIXME: Alphabetical sort puts 'experimental' in the middle. 11708b86531ade68727c56918f162816075b87c864aJordy Rose // Would it be better to name it '~experimental' or something else 11808b86531ade68727c56918f162816075b87c864aJordy Rose // that's ASCIIbetically last? 11908b86531ade68727c56918f162816075b87c864aJordy Rose std::sort(Checkers.begin(), Checkers.end(), checkerNameLT); 12008b86531ade68727c56918f162816075b87c864aJordy Rose 12108b86531ade68727c56918f162816075b87c864aJordy Rose // FIXME: Print available packages. 12208b86531ade68727c56918f162816075b87c864aJordy Rose 12308b86531ade68727c56918f162816075b87c864aJordy Rose out << "CHECKERS:\n"; 12408b86531ade68727c56918f162816075b87c864aJordy Rose 12508b86531ade68727c56918f162816075b87c864aJordy Rose // Find the maximum option length. 12608b86531ade68727c56918f162816075b87c864aJordy Rose size_t optionFieldWidth = 0; 12708b86531ade68727c56918f162816075b87c864aJordy Rose for (CheckerInfoList::const_iterator i = Checkers.begin(), e = Checkers.end(); 12808b86531ade68727c56918f162816075b87c864aJordy Rose i != e; ++i) { 12908b86531ade68727c56918f162816075b87c864aJordy Rose // Limit the amount of padding we are willing to give up for alignment. 13008b86531ade68727c56918f162816075b87c864aJordy Rose // Package.Name Description [Hidden] 13108b86531ade68727c56918f162816075b87c864aJordy Rose size_t nameLength = i->FullName.size(); 13208b86531ade68727c56918f162816075b87c864aJordy Rose if (nameLength <= maxNameChars) 13308b86531ade68727c56918f162816075b87c864aJordy Rose optionFieldWidth = std::max(optionFieldWidth, nameLength); 13408b86531ade68727c56918f162816075b87c864aJordy Rose } 13508b86531ade68727c56918f162816075b87c864aJordy Rose 13608b86531ade68727c56918f162816075b87c864aJordy Rose const size_t initialPad = 2; 13708b86531ade68727c56918f162816075b87c864aJordy Rose for (CheckerInfoList::const_iterator i = Checkers.begin(), e = Checkers.end(); 13808b86531ade68727c56918f162816075b87c864aJordy Rose i != e; ++i) { 13908b86531ade68727c56918f162816075b87c864aJordy Rose out.indent(initialPad) << i->FullName; 14008b86531ade68727c56918f162816075b87c864aJordy Rose 14108b86531ade68727c56918f162816075b87c864aJordy Rose int pad = optionFieldWidth - i->FullName.size(); 14208b86531ade68727c56918f162816075b87c864aJordy Rose 14308b86531ade68727c56918f162816075b87c864aJordy Rose // Break on long option names. 14408b86531ade68727c56918f162816075b87c864aJordy Rose if (pad < 0) { 14508b86531ade68727c56918f162816075b87c864aJordy Rose out << '\n'; 14608b86531ade68727c56918f162816075b87c864aJordy Rose pad = optionFieldWidth + initialPad; 14708b86531ade68727c56918f162816075b87c864aJordy Rose } 14808b86531ade68727c56918f162816075b87c864aJordy Rose out.indent(pad + 2) << i->Desc; 14908b86531ade68727c56918f162816075b87c864aJordy Rose 15008b86531ade68727c56918f162816075b87c864aJordy Rose out << '\n'; 15108b86531ade68727c56918f162816075b87c864aJordy Rose } 15208b86531ade68727c56918f162816075b87c864aJordy Rose} 153