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