242 lines · cpp
1//===- CheckerRegistry.h - Maintains all available checkers -----*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "clang/StaticAnalyzer/Core/CheckerRegistryData.h"10#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"11#include "llvm/ADT/Twine.h"12#include <map>13 14using namespace clang;15using namespace ento;16 17//===----------------------------------------------------------------------===//18// Methods of CmdLineOption, PackageInfo and CheckerInfo.19//===----------------------------------------------------------------------===//20 21LLVM_DUMP_METHOD void CmdLineOption::dump() const {22 dumpToStream(llvm::errs());23}24 25LLVM_DUMP_METHOD void26CmdLineOption::dumpToStream(llvm::raw_ostream &Out) const {27 // The description can be just checked in Checkers.inc, the point here is to28 // debug whether we succeeded in parsing it.29 Out << OptionName << " (" << OptionType << ", "30 << (IsHidden ? "hidden, " : "") << DevelopmentStatus << ") default: \""31 << DefaultValStr;32}33 34static StringRef toString(StateFromCmdLine Kind) {35 switch (Kind) {36 case StateFromCmdLine::State_Disabled:37 return "Disabled";38 case StateFromCmdLine::State_Enabled:39 return "Enabled";40 case StateFromCmdLine::State_Unspecified:41 return "Unspecified";42 }43 llvm_unreachable("Unhandled StateFromCmdLine enum");44}45 46LLVM_DUMP_METHOD void CheckerInfo::dump() const { dumpToStream(llvm::errs()); }47 48LLVM_DUMP_METHOD void CheckerInfo::dumpToStream(llvm::raw_ostream &Out) const {49 // The description can be just checked in Checkers.inc, the point here is to50 // debug whether we succeeded in parsing it. Same with documentation uri.51 Out << FullName << " (" << toString(State) << (IsHidden ? ", hidden" : "")52 << ")\n";53 Out << " Options:\n";54 for (const CmdLineOption &Option : CmdLineOptions) {55 Out << " ";56 Option.dumpToStream(Out);57 Out << '\n';58 }59 Out << " Dependencies:\n";60 for (const CheckerInfo *Dependency : Dependencies) {61 Out << " " << Dependency->FullName << '\n';62 }63 Out << " Weak dependencies:\n";64 for (const CheckerInfo *Dependency : WeakDependencies) {65 Out << " " << Dependency->FullName << '\n';66 }67}68 69LLVM_DUMP_METHOD void PackageInfo::dump() const { dumpToStream(llvm::errs()); }70 71LLVM_DUMP_METHOD void PackageInfo::dumpToStream(llvm::raw_ostream &Out) const {72 Out << FullName << "\n";73 Out << " Options:\n";74 for (const CmdLineOption &Option : CmdLineOptions) {75 Out << " ";76 Option.dumpToStream(Out);77 Out << '\n';78 }79}80 81static constexpr char PackageSeparator = '.';82 83static bool isInPackage(const CheckerInfo &Checker, StringRef PackageName) {84 // Does the checker's full name have the package as a prefix?85 if (!Checker.FullName.starts_with(PackageName))86 return false;87 88 // Is the package actually just the name of a specific checker?89 if (Checker.FullName.size() == PackageName.size())90 return true;91 92 // Is the checker in the package (or a subpackage)?93 if (Checker.FullName[PackageName.size()] == PackageSeparator)94 return true;95 96 return false;97}98 99CheckerInfoListRange100CheckerRegistryData::getMutableCheckersForCmdLineArg(StringRef CmdLineArg) {101 auto It = checker_registry::binaryFind(Checkers, CmdLineArg);102 103 if (!isInPackage(*It, CmdLineArg))104 return {Checkers.end(), Checkers.end()};105 106 // See how large the package is.107 // If the package doesn't exist, assume the option refers to a single108 // checker.109 size_t Size = 1;110 llvm::StringMap<size_t>::const_iterator PackageSize =111 PackageSizes.find(CmdLineArg);112 113 if (PackageSize != PackageSizes.end())114 Size = PackageSize->getValue();115 116 return {It, It + Size};117}118//===----------------------------------------------------------------------===//119// Printing functions.120//===----------------------------------------------------------------------===//121 122void CheckerRegistryData::printCheckerWithDescList(123 const AnalyzerOptions &AnOpts, raw_ostream &Out,124 size_t MaxNameChars) const {125 // FIXME: Print available packages.126 127 Out << "CHECKERS:\n";128 129 // Find the maximum option length.130 size_t OptionFieldWidth = 0;131 for (const auto &Checker : Checkers) {132 // Limit the amount of padding we are willing to give up for alignment.133 // Package.Name Description [Hidden]134 size_t NameLength = Checker.FullName.size();135 if (NameLength <= MaxNameChars)136 OptionFieldWidth = std::max(OptionFieldWidth, NameLength);137 }138 139 const size_t InitialPad = 2;140 141 auto Print = [=](llvm::raw_ostream &Out, const CheckerInfo &Checker,142 StringRef Description) {143 AnalyzerOptions::printFormattedEntry(Out, {Checker.FullName, Description},144 InitialPad, OptionFieldWidth);145 Out << '\n';146 };147 148 for (const auto &Checker : Checkers) {149 // The order of this if branches is significant, we wouldn't like to display150 // developer checkers even in the alpha output. For example,151 // alpha.cplusplus.IteratorModeling is a modeling checker, hence it's hidden152 // by default, and users (even when the user is a developer of an alpha153 // checker) shouldn't normally tinker with whether they should be enabled.154 155 if (Checker.IsHidden) {156 if (AnOpts.ShowCheckerHelpDeveloper)157 Print(Out, Checker, Checker.Desc);158 continue;159 }160 161 if (Checker.FullName.starts_with("alpha")) {162 if (AnOpts.ShowCheckerHelpAlpha)163 Print(Out, Checker,164 ("(Enable only for development!) " + Checker.Desc).str());165 continue;166 }167 168 if (AnOpts.ShowCheckerHelp)169 Print(Out, Checker, Checker.Desc);170 }171}172 173void CheckerRegistryData::printEnabledCheckerList(raw_ostream &Out) const {174 for (const auto *i : EnabledCheckers)175 Out << i->FullName << '\n';176}177 178void CheckerRegistryData::printCheckerOptionList(const AnalyzerOptions &AnOpts,179 raw_ostream &Out) const {180 Out << "OVERVIEW: Clang Static Analyzer Checker and Package Option List\n\n";181 Out << "USAGE: -analyzer-config <OPTION1=VALUE,OPTION2=VALUE,...>\n\n";182 Out << " -analyzer-config OPTION1=VALUE, -analyzer-config "183 "OPTION2=VALUE, ...\n\n";184 Out << "OPTIONS:\n\n";185 186 // It's usually ill-advised to use multimap, but clang will terminate after187 // this function.188 std::multimap<StringRef, const CmdLineOption &> OptionMap;189 190 for (const CheckerInfo &Checker : Checkers) {191 for (const CmdLineOption &Option : Checker.CmdLineOptions) {192 OptionMap.insert({Checker.FullName, Option});193 }194 }195 196 for (const PackageInfo &Package : Packages) {197 for (const CmdLineOption &Option : Package.CmdLineOptions) {198 OptionMap.insert({Package.FullName, Option});199 }200 }201 202 auto Print = [](llvm::raw_ostream &Out, StringRef FullOption,203 StringRef Desc) {204 AnalyzerOptions::printFormattedEntry(Out, {FullOption, Desc},205 /*InitialPad*/ 2,206 /*EntryWidth*/ 50,207 /*MinLineWidth*/ 90);208 Out << "\n\n";209 };210 for (const std::pair<const StringRef, const CmdLineOption &> &Entry :211 OptionMap) {212 const CmdLineOption &Option = Entry.second;213 std::string FullOption = (Entry.first + ":" + Option.OptionName).str();214 215 std::string Desc =216 ("(" + Option.OptionType + ") " + Option.Description + " (default: " +217 (Option.DefaultValStr.empty() ? "\"\"" : Option.DefaultValStr) + ")")218 .str();219 220 // The list of these if branches is significant, we wouldn't like to221 // display hidden alpha checker options for222 // -analyzer-checker-option-help-alpha.223 224 if (Option.IsHidden) {225 if (AnOpts.ShowCheckerOptionDeveloperList)226 Print(Out, FullOption, Desc);227 continue;228 }229 230 if (Option.DevelopmentStatus == "alpha" ||231 Entry.first.starts_with("alpha")) {232 if (AnOpts.ShowCheckerOptionAlphaList)233 Print(Out, FullOption,234 llvm::Twine("(Enable only for development!) " + Desc).str());235 continue;236 }237 238 if (AnOpts.ShowCheckerOptionList)239 Print(Out, FullOption, Desc);240 }241}242