1 //===- CheckerRegistry.h - Maintains all available checkers -----*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #include "clang/StaticAnalyzer/Core/CheckerRegistryData.h"
10 #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
11 #include "llvm/ADT/Twine.h"
14 using namespace clang
;
17 //===----------------------------------------------------------------------===//
18 // Methods of CmdLineOption, PackageInfo and CheckerInfo.
19 //===----------------------------------------------------------------------===//
21 LLVM_DUMP_METHOD
void CmdLineOption::dump() const {
22 dumpToStream(llvm::errs());
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: \""
34 static StringRef
toString(StateFromCmdLine Kind
) {
36 case StateFromCmdLine::State_Disabled
:
38 case StateFromCmdLine::State_Enabled
:
40 case StateFromCmdLine::State_Unspecified
:
43 llvm_unreachable("Unhandled StateFromCmdLine enum");
46 LLVM_DUMP_METHOD
void CheckerInfo::dump() const { dumpToStream(llvm::errs()); }
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" : "")
54 for (const CmdLineOption
&Option
: CmdLineOptions
) {
56 Option
.dumpToStream(Out
);
59 Out
<< " Dependencies:\n";
60 for (const CheckerInfo
*Dependency
: Dependencies
) {
61 Out
<< " " << Dependency
->FullName
<< '\n';
63 Out
<< " Weak dependencies:\n";
64 for (const CheckerInfo
*Dependency
: WeakDependencies
) {
65 Out
<< " " << Dependency
->FullName
<< '\n';
69 LLVM_DUMP_METHOD
void PackageInfo::dump() const { dumpToStream(llvm::errs()); }
71 LLVM_DUMP_METHOD
void PackageInfo::dumpToStream(llvm::raw_ostream
&Out
) const {
72 Out
<< FullName
<< "\n";
74 for (const CmdLineOption
&Option
: CmdLineOptions
) {
76 Option
.dumpToStream(Out
);
81 static constexpr char PackageSeparator
= '.';
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
.starts_with(PackageName
))
88 // Is the package actually just the name of a specific checker?
89 if (Checker
.FullName
.size() == PackageName
.size())
92 // Is the checker in the package (or a subpackage)?
93 if (Checker
.FullName
[PackageName
.size()] == PackageSeparator
)
100 CheckerRegistryData::getMutableCheckersForCmdLineArg(StringRef CmdLineArg
) {
101 auto It
= checker_registry::binaryFind(Checkers
, CmdLineArg
);
103 if (!isInPackage(*It
, CmdLineArg
))
104 return {Checkers
.end(), Checkers
.end()};
106 // See how large the package is.
107 // If the package doesn't exist, assume the option refers to a single
110 llvm::StringMap
<size_t>::const_iterator PackageSize
=
111 PackageSizes
.find(CmdLineArg
);
113 if (PackageSize
!= PackageSizes
.end())
114 Size
= PackageSize
->getValue();
116 return {It
, It
+ Size
};
118 //===----------------------------------------------------------------------===//
119 // Printing functions.
120 //===----------------------------------------------------------------------===//
122 void CheckerRegistryData::printCheckerWithDescList(
123 const AnalyzerOptions
&AnOpts
, raw_ostream
&Out
,
124 size_t MaxNameChars
) const {
125 // FIXME: Print available packages.
127 Out
<< "CHECKERS:\n";
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
);
139 const size_t InitialPad
= 2;
141 auto Print
= [=](llvm::raw_ostream
&Out
, const CheckerInfo
&Checker
,
142 StringRef Description
) {
143 AnalyzerOptions::printFormattedEntry(Out
, {Checker
.FullName
, Description
},
144 InitialPad
, OptionFieldWidth
);
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.
155 if (Checker
.IsHidden
) {
156 if (AnOpts
.ShowCheckerHelpDeveloper
)
157 Print(Out
, Checker
, Checker
.Desc
);
161 if (Checker
.FullName
.starts_with("alpha")) {
162 if (AnOpts
.ShowCheckerHelpAlpha
)
164 ("(Enable only for development!) " + Checker
.Desc
).str());
168 if (AnOpts
.ShowCheckerHelp
)
169 Print(Out
, Checker
, Checker
.Desc
);
173 void CheckerRegistryData::printEnabledCheckerList(raw_ostream
&Out
) const {
174 for (const auto *i
: EnabledCheckers
)
175 Out
<< i
->FullName
<< '\n';
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";
186 // It's usually ill-advised to use multimap, but clang will terminate after
188 std::multimap
<StringRef
, const CmdLineOption
&> OptionMap
;
190 for (const CheckerInfo
&Checker
: Checkers
) {
191 for (const CmdLineOption
&Option
: Checker
.CmdLineOptions
) {
192 OptionMap
.insert({Checker
.FullName
, Option
});
196 for (const PackageInfo
&Package
: Packages
) {
197 for (const CmdLineOption
&Option
: Package
.CmdLineOptions
) {
198 OptionMap
.insert({Package
.FullName
, Option
});
202 auto Print
= [](llvm::raw_ostream
&Out
, StringRef FullOption
,
204 AnalyzerOptions::printFormattedEntry(Out
, {FullOption
, Desc
},
207 /*MinLineWidth*/ 90);
210 for (const std::pair
<const StringRef
, const CmdLineOption
&> &Entry
:
212 const CmdLineOption
&Option
= Entry
.second
;
213 std::string FullOption
= (Entry
.first
+ ":" + Option
.OptionName
).str();
216 ("(" + Option
.OptionType
+ ") " + Option
.Description
+ " (default: " +
217 (Option
.DefaultValStr
.empty() ? "\"\"" : Option
.DefaultValStr
) + ")")
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.
224 if (Option
.IsHidden
) {
225 if (AnOpts
.ShowCheckerOptionDeveloperList
)
226 Print(Out
, FullOption
, Desc
);
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());
238 if (AnOpts
.ShowCheckerOptionList
)
239 Print(Out
, FullOption
, Desc
);