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