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-exception 6 // 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 14 using namespace clang; 15 using namespace ento; 16 17 //===----------------------------------------------------------------------===// 18 // Methods of CmdLineOption, PackageInfo and CheckerInfo. 19 //===----------------------------------------------------------------------===// 20 21 LLVM_DUMP_METHOD void CmdLineOption::dump() const { 22 dumpToStream(llvm::errs()); 23 } 24 25 LLVM_DUMP_METHOD void 26 CmdLineOption::dumpToStream(llvm::raw_ostream &Out) const { 27 // The description can be just checked in Checkers.inc, the point here is to 28 // debug whether we succeeded in parsing it. 29 Out << OptionName << " (" << OptionType << ", " 30 << (IsHidden ? "hidden, " : "") << DevelopmentStatus << ") default: \"" 31 << DefaultValStr; 32 } 33 34 static 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 46 LLVM_DUMP_METHOD void CheckerInfo::dump() const { dumpToStream(llvm::errs()); } 47 48 LLVM_DUMP_METHOD void CheckerInfo::dumpToStream(llvm::raw_ostream &Out) const { 49 // The description can be just checked in Checkers.inc, the point here is to 50 // 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 69 LLVM_DUMP_METHOD void PackageInfo::dump() const { dumpToStream(llvm::errs()); } 70 71 LLVM_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 81 static constexpr char PackageSeparator = '.'; 82 83 static bool isInPackage(const CheckerInfo &Checker, StringRef PackageName) { 84 // Does the checker's full name have the package as a prefix? 85 if (!Checker.FullName.startswith(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 99 CheckerInfoListRange 100 CheckerRegistryData::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 single 108 // 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 122 void 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 display 150 // developer checkers even in the alpha output. For example, 151 // alpha.cplusplus.IteratorModeling is a modeling checker, hence it's hidden 152 // by default, and users (even when the user is a developer of an alpha 153 // 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.startswith("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 173 void CheckerRegistryData::printEnabledCheckerList(raw_ostream &Out) const { 174 for (const auto *i : EnabledCheckers) 175 Out << i->FullName << '\n'; 176 } 177 178 void 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 after 187 // 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 to 221 // display hidden alpha checker options for 222 // -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.startswith("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