/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/StaticAnalyzer/Core/CheckerRegistryData.cpp
Line | Count | Source (jump to first uncovered line) |
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 | 0 | LLVM_DUMP_METHOD void CmdLineOption::dump() const { |
22 | 0 | dumpToStream(llvm::errs()); |
23 | 0 | } |
24 | | |
25 | | LLVM_DUMP_METHOD void |
26 | 0 | 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 | 0 | Out << OptionName << " (" << OptionType << ", " |
30 | 0 | << (IsHidden ? "hidden, " : "") << DevelopmentStatus << ") default: \"" |
31 | 0 | << DefaultValStr; |
32 | 0 | } |
33 | | |
34 | 0 | static StringRef toString(StateFromCmdLine Kind) { |
35 | 0 | switch (Kind) { |
36 | 0 | case StateFromCmdLine::State_Disabled: |
37 | 0 | return "Disabled"; |
38 | 0 | case StateFromCmdLine::State_Enabled: |
39 | 0 | return "Enabled"; |
40 | 0 | case StateFromCmdLine::State_Unspecified: |
41 | 0 | return "Unspecified"; |
42 | 0 | } |
43 | 0 | llvm_unreachable("Unhandled StateFromCmdLine enum"); |
44 | 0 | } |
45 | | |
46 | 0 | LLVM_DUMP_METHOD void CheckerInfo::dump() const { dumpToStream(llvm::errs()); } |
47 | | |
48 | 0 | 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 | 0 | Out << FullName << " (" << toString(State) << (IsHidden ? ", hidden" : "") |
52 | 0 | << ")\n"; |
53 | 0 | Out << " Options:\n"; |
54 | 0 | for (const CmdLineOption &Option : CmdLineOptions) { |
55 | 0 | Out << " "; |
56 | 0 | Option.dumpToStream(Out); |
57 | 0 | Out << '\n'; |
58 | 0 | } |
59 | 0 | Out << " Dependencies:\n"; |
60 | 0 | for (const CheckerInfo *Dependency : Dependencies) { |
61 | 0 | Out << " " << Dependency->FullName << '\n'; |
62 | 0 | } |
63 | 0 | Out << " Weak dependencies:\n"; |
64 | 0 | for (const CheckerInfo *Dependency : WeakDependencies) { |
65 | 0 | Out << " " << Dependency->FullName << '\n'; |
66 | 0 | } |
67 | 0 | } |
68 | | |
69 | 0 | LLVM_DUMP_METHOD void PackageInfo::dump() const { dumpToStream(llvm::errs()); } |
70 | | |
71 | 0 | LLVM_DUMP_METHOD void PackageInfo::dumpToStream(llvm::raw_ostream &Out) const { |
72 | 0 | Out << FullName << "\n"; |
73 | 0 | Out << " Options:\n"; |
74 | 0 | for (const CmdLineOption &Option : CmdLineOptions) { |
75 | 0 | Out << " "; |
76 | 0 | Option.dumpToStream(Out); |
77 | 0 | Out << '\n'; |
78 | 0 | } |
79 | 0 | } |
80 | | |
81 | | static constexpr char PackageSeparator = '.'; |
82 | | |
83 | 3.60k | static bool isInPackage(const CheckerInfo &Checker, StringRef PackageName) { |
84 | | // Does the checker's full name have the package as a prefix? |
85 | 3.60k | if (!Checker.FullName.startswith(PackageName)) |
86 | 1 | return false; |
87 | | |
88 | | // Is the package actually just the name of a specific checker? |
89 | 3.60k | if (Checker.FullName.size() == PackageName.size()) |
90 | 1.86k | return true; |
91 | | |
92 | | // Is the checker in the package (or a subpackage)? |
93 | 1.73k | if (Checker.FullName[PackageName.size()] == PackageSeparator) |
94 | 1.73k | return true; |
95 | | |
96 | 0 | return false; |
97 | 1.73k | } |
98 | | |
99 | | CheckerInfoListRange |
100 | 3.60k | CheckerRegistryData::getMutableCheckersForCmdLineArg(StringRef CmdLineArg) { |
101 | 3.60k | auto It = checker_registry::binaryFind(Checkers, CmdLineArg); |
102 | | |
103 | 3.60k | if (!isInPackage(*It, CmdLineArg)) |
104 | 1 | 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 | 3.60k | size_t Size = 1; |
110 | 3.60k | llvm::StringMap<size_t>::const_iterator PackageSize = |
111 | 3.60k | PackageSizes.find(CmdLineArg); |
112 | | |
113 | 3.60k | if (PackageSize != PackageSizes.end()) |
114 | 1.73k | Size = PackageSize->getValue(); |
115 | | |
116 | 3.60k | return {It, It + Size}; |
117 | 3.60k | } |
118 | | //===----------------------------------------------------------------------===// |
119 | | // Printing functions. |
120 | | //===----------------------------------------------------------------------===// |
121 | | |
122 | | void CheckerRegistryData::printCheckerWithDescList( |
123 | | const AnalyzerOptions &AnOpts, raw_ostream &Out, |
124 | 9 | size_t MaxNameChars) const { |
125 | | // FIXME: Print available packages. |
126 | | |
127 | 9 | Out << "CHECKERS:\n"; |
128 | | |
129 | | // Find the maximum option length. |
130 | 9 | size_t OptionFieldWidth = 0; |
131 | 1.73k | 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 | 1.73k | size_t NameLength = Checker.FullName.size(); |
135 | 1.73k | if (NameLength <= MaxNameChars) |
136 | 1.28k | OptionFieldWidth = std::max(OptionFieldWidth, NameLength); |
137 | 1.73k | } |
138 | | |
139 | 9 | const size_t InitialPad = 2; |
140 | | |
141 | 9 | auto Print = [=](llvm::raw_ostream &Out, const CheckerInfo &Checker, |
142 | 958 | StringRef Description) { |
143 | 958 | AnalyzerOptions::printFormattedEntry(Out, {Checker.FullName, Description}, |
144 | 958 | InitialPad, OptionFieldWidth); |
145 | 958 | Out << '\n'; |
146 | 958 | }; |
147 | | |
148 | 1.73k | 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 | 1.73k | if (Checker.IsHidden) { |
156 | 441 | if (AnOpts.ShowCheckerHelpDeveloper) |
157 | 196 | Print(Out, Checker, Checker.Desc); |
158 | 441 | continue; |
159 | 441 | } |
160 | | |
161 | 1.29k | if (Checker.FullName.startswith("alpha")) { |
162 | 459 | if (AnOpts.ShowCheckerHelpAlpha) |
163 | 204 | Print(Out, Checker, |
164 | 204 | ("(Enable only for development!) " + Checker.Desc).str()); |
165 | 459 | continue; |
166 | 459 | } |
167 | | |
168 | 837 | if (AnOpts.ShowCheckerHelp) |
169 | 558 | Print(Out, Checker, Checker.Desc); |
170 | 837 | } |
171 | 9 | } |
172 | | |
173 | 17 | void CheckerRegistryData::printEnabledCheckerList(raw_ostream &Out) const { |
174 | 17 | for (const auto *i : EnabledCheckers) |
175 | 130 | Out << i->FullName << '\n'; |
176 | 17 | } |
177 | | |
178 | | void CheckerRegistryData::printCheckerOptionList(const AnalyzerOptions &AnOpts, |
179 | 7 | raw_ostream &Out) const { |
180 | 7 | Out << "OVERVIEW: Clang Static Analyzer Checker and Package Option List\n\n"; |
181 | 7 | Out << "USAGE: -analyzer-config <OPTION1=VALUE,OPTION2=VALUE,...>\n\n"; |
182 | 7 | Out << " -analyzer-config OPTION1=VALUE, -analyzer-config " |
183 | 7 | "OPTION2=VALUE, ...\n\n"; |
184 | 7 | Out << "OPTIONS:\n\n"; |
185 | | |
186 | | // It's usually ill-advised to use multimap, but clang will terminate after |
187 | | // this function. |
188 | 7 | std::multimap<StringRef, const CmdLineOption &> OptionMap; |
189 | | |
190 | 1.35k | for (const CheckerInfo &Checker : Checkers) { |
191 | 1.35k | for (const CmdLineOption &Option : Checker.CmdLineOptions) { |
192 | 427 | OptionMap.insert({Checker.FullName, Option}); |
193 | 427 | } |
194 | 1.35k | } |
195 | | |
196 | 350 | for (const PackageInfo &Package : Packages) { |
197 | 350 | for (const CmdLineOption &Option : Package.CmdLineOptions) { |
198 | 7 | OptionMap.insert({Package.FullName, Option}); |
199 | 7 | } |
200 | 350 | } |
201 | | |
202 | 7 | auto Print = [](llvm::raw_ostream &Out, StringRef FullOption, |
203 | 248 | StringRef Desc) { |
204 | 248 | AnalyzerOptions::printFormattedEntry(Out, {FullOption, Desc}, |
205 | 248 | /*InitialPad*/ 2, |
206 | 248 | /*EntryWidth*/ 50, |
207 | 248 | /*MinLineWidth*/ 90); |
208 | 248 | Out << "\n\n"; |
209 | 248 | }; |
210 | 7 | for (const std::pair<const StringRef, const CmdLineOption &> &Entry : |
211 | 434 | OptionMap) { |
212 | 434 | const CmdLineOption &Option = Entry.second; |
213 | 434 | std::string FullOption = (Entry.first + ":" + Option.OptionName).str(); |
214 | | |
215 | 434 | std::string Desc = |
216 | 434 | ("(" + Option.OptionType + ") " + Option.Description + " (default: " + |
217 | 434 | (Option.DefaultValStr.empty() ? "\"\""7 : Option.DefaultValStr427 ) + ")") |
218 | 434 | .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 | 434 | if (Option.IsHidden) { |
225 | 196 | if (AnOpts.ShowCheckerOptionDeveloperList) |
226 | 112 | Print(Out, FullOption, Desc); |
227 | 196 | continue; |
228 | 196 | } |
229 | | |
230 | 238 | if (Option.DevelopmentStatus == "alpha" || |
231 | 238 | Entry.first.startswith("alpha")161 ) { |
232 | 119 | if (AnOpts.ShowCheckerOptionAlphaList) |
233 | 68 | Print(Out, FullOption, |
234 | 68 | llvm::Twine("(Enable only for development!) " + Desc).str()); |
235 | 119 | continue; |
236 | 119 | } |
237 | | |
238 | 119 | if (AnOpts.ShowCheckerOptionList) |
239 | 68 | Print(Out, FullOption, Desc); |
240 | 119 | } |
241 | 7 | } |