/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===- CheckerRegistry.cpp - Maintains all available checkers -------------===// |
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/Frontend/CheckerRegistry.h" |
10 | | #include "clang/Basic/Diagnostic.h" |
11 | | #include "clang/Basic/LLVM.h" |
12 | | #include "clang/Driver/DriverDiagnostic.h" |
13 | | #include "clang/Frontend/FrontendDiagnostic.h" |
14 | | #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" |
15 | | #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" |
16 | | #include "clang/StaticAnalyzer/Core/CheckerManager.h" |
17 | | #include "llvm/ADT/STLExtras.h" |
18 | | #include "llvm/ADT/StringMap.h" |
19 | | #include "llvm/ADT/StringRef.h" |
20 | | #include "llvm/Support/DynamicLibrary.h" |
21 | | #include "llvm/Support/Path.h" |
22 | | #include "llvm/Support/raw_ostream.h" |
23 | | #include <algorithm> |
24 | | |
25 | | using namespace clang; |
26 | | using namespace ento; |
27 | | using namespace checker_registry; |
28 | | using llvm::sys::DynamicLibrary; |
29 | | |
30 | | //===----------------------------------------------------------------------===// |
31 | | // Utilities. |
32 | | //===----------------------------------------------------------------------===// |
33 | | |
34 | 0 | static bool isCompatibleAPIVersion(const char *VersionString) { |
35 | | // If the version string is null, its not an analyzer plugin. |
36 | 0 | if (!VersionString) |
37 | 0 | return false; |
38 | | |
39 | | // For now, none of the static analyzer API is considered stable. |
40 | | // Versions must match exactly. |
41 | 0 | return strcmp(VersionString, CLANG_ANALYZER_API_VERSION_STRING) == 0; |
42 | 0 | } |
43 | | |
44 | | static constexpr char PackageSeparator = '.'; |
45 | | |
46 | | //===----------------------------------------------------------------------===// |
47 | | // Methods of CheckerRegistry. |
48 | | //===----------------------------------------------------------------------===// |
49 | | |
50 | | CheckerRegistry::CheckerRegistry( |
51 | | CheckerRegistryData &Data, ArrayRef<std::string> Plugins, |
52 | | DiagnosticsEngine &Diags, AnalyzerOptions &AnOpts, |
53 | | ArrayRef<std::function<void(CheckerRegistry &)>> CheckerRegistrationFns) |
54 | 1.84k | : Data(Data), Diags(Diags), AnOpts(AnOpts) { |
55 | | |
56 | | // Register builtin checkers. |
57 | 1.84k | #define GET_CHECKERS |
58 | 1.84k | #define CHECKER(FULLNAME, CLASS, HELPTEXT, DOC_URI, IS_HIDDEN) \ |
59 | 356k | addChecker(register##CLASS, shouldRegister##CLASS, FULLNAME, HELPTEXT, \ |
60 | 356k | DOC_URI, IS_HIDDEN); |
61 | | |
62 | 1.84k | #define GET_PACKAGES |
63 | 92.3k | #define PACKAGE(FULLNAME) addPackage(FULLNAME); |
64 | | |
65 | 1.84k | #include "clang/StaticAnalyzer/Checkers/Checkers.inc" |
66 | 1.84k | #undef CHECKER |
67 | 1.84k | #undef GET_CHECKERS |
68 | 1.84k | #undef PACKAGE |
69 | 1.84k | #undef GET_PACKAGES |
70 | | |
71 | | // Register checkers from plugins. |
72 | 1.84k | for (const std::string &Plugin : Plugins) { |
73 | | // Get access to the plugin. |
74 | 0 | std::string ErrorMsg; |
75 | 0 | DynamicLibrary Lib = |
76 | 0 | DynamicLibrary::getPermanentLibrary(Plugin.c_str(), &ErrorMsg); |
77 | 0 | if (!Lib.isValid()) { |
78 | 0 | Diags.Report(diag::err_fe_unable_to_load_plugin) << Plugin << ErrorMsg; |
79 | 0 | continue; |
80 | 0 | } |
81 | | |
82 | | // See if its compatible with this build of clang. |
83 | 0 | const char *PluginAPIVersion = static_cast<const char *>( |
84 | 0 | Lib.getAddressOfSymbol("clang_analyzerAPIVersionString")); |
85 | |
|
86 | 0 | if (!isCompatibleAPIVersion(PluginAPIVersion)) { |
87 | 0 | Diags.Report(diag::warn_incompatible_analyzer_plugin_api) |
88 | 0 | << llvm::sys::path::filename(Plugin); |
89 | 0 | Diags.Report(diag::note_incompatible_analyzer_plugin_api) |
90 | 0 | << CLANG_ANALYZER_API_VERSION_STRING << PluginAPIVersion; |
91 | 0 | continue; |
92 | 0 | } |
93 | | |
94 | 0 | using RegisterPluginCheckerFn = void (*)(CheckerRegistry &); |
95 | | // Register its checkers. |
96 | 0 | RegisterPluginCheckerFn RegisterPluginCheckers = |
97 | 0 | reinterpret_cast<RegisterPluginCheckerFn>( |
98 | 0 | Lib.getAddressOfSymbol("clang_registerCheckers")); |
99 | 0 | if (RegisterPluginCheckers) |
100 | 0 | RegisterPluginCheckers(*this); |
101 | 0 | } |
102 | | |
103 | | // Register statically linked checkers, that aren't generated from the tblgen |
104 | | // file, but rather passed their registry function as a parameter in |
105 | | // checkerRegistrationFns. |
106 | | |
107 | 1.84k | for (const auto &Fn : CheckerRegistrationFns) |
108 | 217 | Fn(*this); |
109 | | |
110 | | // Sort checkers for efficient collection. |
111 | | // FIXME: Alphabetical sort puts 'experimental' in the middle. |
112 | | // Would it be better to name it '~experimental' or something else |
113 | | // that's ASCIIbetically last? |
114 | 1.84k | llvm::sort(Data.Packages, checker_registry::PackageNameLT{}); |
115 | 1.84k | llvm::sort(Data.Checkers, checker_registry::CheckerNameLT{}); |
116 | | |
117 | 1.84k | #define GET_CHECKER_DEPENDENCIES |
118 | | |
119 | 1.84k | #define CHECKER_DEPENDENCY(FULLNAME, DEPENDENCY) \ |
120 | 112k | addDependency(FULLNAME, DEPENDENCY); |
121 | | |
122 | 1.84k | #define GET_CHECKER_WEAK_DEPENDENCIES |
123 | | |
124 | 1.84k | #define CHECKER_WEAK_DEPENDENCY(FULLNAME, DEPENDENCY) \ |
125 | 7.38k | addWeakDependency(FULLNAME, DEPENDENCY); |
126 | | |
127 | 1.84k | #define GET_CHECKER_OPTIONS |
128 | 1.84k | #define CHECKER_OPTION(TYPE, FULLNAME, CMDFLAG, DESC, DEFAULT_VAL, \ |
129 | 1.84k | DEVELOPMENT_STATUS, IS_HIDDEN) \ |
130 | 112k | addCheckerOption(TYPE, FULLNAME, CMDFLAG, DEFAULT_VAL, DESC, \ |
131 | 112k | DEVELOPMENT_STATUS, IS_HIDDEN); |
132 | | |
133 | 1.84k | #define GET_PACKAGE_OPTIONS |
134 | 1.84k | #define PACKAGE_OPTION(TYPE, FULLNAME, CMDFLAG, DESC, DEFAULT_VAL, \ |
135 | 1.84k | DEVELOPMENT_STATUS, IS_HIDDEN) \ |
136 | 1.84k | addPackageOption(TYPE, FULLNAME, CMDFLAG, DEFAULT_VAL, DESC, \ |
137 | 1.84k | DEVELOPMENT_STATUS, IS_HIDDEN); |
138 | | |
139 | 1.84k | #include "clang/StaticAnalyzer/Checkers/Checkers.inc" |
140 | 1.84k | #undef CHECKER_DEPENDENCY |
141 | 1.84k | #undef GET_CHECKER_DEPENDENCIES |
142 | 1.84k | #undef CHECKER_WEAK_DEPENDENCY |
143 | 1.84k | #undef GET_CHECKER_WEAK_DEPENDENCIES |
144 | 1.84k | #undef CHECKER_OPTION |
145 | 1.84k | #undef GET_CHECKER_OPTIONS |
146 | 1.84k | #undef PACKAGE_OPTION |
147 | 1.84k | #undef GET_PACKAGE_OPTIONS |
148 | | |
149 | 1.84k | resolveDependencies<true>(); |
150 | 1.84k | resolveDependencies<false>(); |
151 | | |
152 | 1.84k | #ifndef NDEBUG |
153 | 112k | for (auto &DepPair : Data.Dependencies) { |
154 | 451k | for (auto &WeakDepPair : Data.WeakDependencies) { |
155 | | // Some assertions to enforce that strong dependencies are relations in |
156 | | // between purely modeling checkers, and weak dependencies are about |
157 | | // diagnostics. |
158 | 451k | assert(WeakDepPair != DepPair && |
159 | 451k | "A checker cannot strong and weak depend on the same checker!"); |
160 | 451k | assert(WeakDepPair.first != DepPair.second && |
161 | 451k | "A strong dependency mustn't have weak dependencies!"); |
162 | 451k | assert(WeakDepPair.second != DepPair.second && |
163 | 451k | "A strong dependency mustn't be a weak dependency as well!"); |
164 | 451k | } |
165 | 112k | } |
166 | 1.84k | #endif |
167 | | |
168 | 1.84k | resolveCheckerAndPackageOptions(); |
169 | | |
170 | | // Parse '-analyzer-checker' and '-analyzer-disable-checker' options from the |
171 | | // command line. |
172 | 3.61k | for (const std::pair<std::string, bool> &Opt : AnOpts.CheckersAndPackages) { |
173 | 3.61k | CheckerInfoListRange CheckerForCmdLineArg = |
174 | 3.61k | Data.getMutableCheckersForCmdLineArg(Opt.first); |
175 | | |
176 | 3.61k | if (CheckerForCmdLineArg.begin() == CheckerForCmdLineArg.end()) { |
177 | 1 | Diags.Report(diag::err_unknown_analyzer_checker_or_package) << Opt.first; |
178 | 1 | Diags.Report(diag::note_suggest_disabling_all_checkers); |
179 | 1 | } |
180 | | |
181 | 31.9k | for (CheckerInfo &checker : CheckerForCmdLineArg) { |
182 | 31.9k | checker.State = Opt.second ? StateFromCmdLine::State_Enabled31.9k |
183 | 31.9k | : StateFromCmdLine::State_Disabled32 ; |
184 | 31.9k | } |
185 | 3.61k | } |
186 | 1.84k | validateCheckerOptions(); |
187 | 1.84k | } |
188 | | |
189 | | //===----------------------------------------------------------------------===// |
190 | | // Dependency resolving. |
191 | | //===----------------------------------------------------------------------===// |
192 | | |
193 | | template <typename IsEnabledFn> |
194 | | static bool collectStrongDependencies(const ConstCheckerInfoList &Deps, |
195 | | const CheckerManager &Mgr, |
196 | | CheckerInfoSet &Ret, |
197 | | IsEnabledFn IsEnabled); |
198 | | |
199 | | /// Collects weak dependencies in \p enabledData.Checkers. |
200 | | template <typename IsEnabledFn> |
201 | | static void collectWeakDependencies(const ConstCheckerInfoList &Deps, |
202 | | const CheckerManager &Mgr, |
203 | | CheckerInfoSet &Ret, IsEnabledFn IsEnabled); |
204 | | |
205 | 1.84k | void CheckerRegistry::initializeRegistry(const CheckerManager &Mgr) { |
206 | | // First, we calculate the list of enabled checkers as specified by the |
207 | | // invocation. Weak dependencies will not enable their unspecified strong |
208 | | // depenencies, but its only after resolving strong dependencies for all |
209 | | // checkers when we know whether they will be enabled. |
210 | 1.84k | CheckerInfoSet Tmp; |
211 | 10.3k | auto IsEnabledFromCmdLine = [&](const CheckerInfo *Checker) { |
212 | 10.3k | return !Checker->isDisabled(Mgr); |
213 | 10.3k | }; |
214 | 356k | for (const CheckerInfo &Checker : Data.Checkers) { |
215 | 356k | if (!Checker.isEnabled(Mgr)) |
216 | 325k | continue; |
217 | | |
218 | 31.2k | CheckerInfoSet Deps; |
219 | 31.2k | if (!collectStrongDependencies(Checker.Dependencies, Mgr, Deps, |
220 | 31.2k | IsEnabledFromCmdLine)) { |
221 | | // If we failed to enable any of the dependencies, don't enable this |
222 | | // checker. |
223 | 5 | continue; |
224 | 5 | } |
225 | | |
226 | 31.2k | Tmp.insert(Deps.begin(), Deps.end()); |
227 | | |
228 | | // Enable the checker. |
229 | 31.2k | Tmp.insert(&Checker); |
230 | 31.2k | } |
231 | | |
232 | | // Calculate enabled checkers with the correct registration order. As this is |
233 | | // done recursively, its arguably cheaper, but for sure less error prone to |
234 | | // recalculate from scratch. |
235 | 1.84k | auto IsEnabled = [&](const CheckerInfo *Checker) { |
236 | 292 | return Tmp.contains(Checker); |
237 | 292 | }; |
238 | 356k | for (const CheckerInfo &Checker : Data.Checkers) { |
239 | 356k | if (!Checker.isEnabled(Mgr)) |
240 | 325k | continue; |
241 | | |
242 | 31.2k | CheckerInfoSet Deps; |
243 | | |
244 | 31.2k | collectWeakDependencies(Checker.WeakDependencies, Mgr, Deps, IsEnabled); |
245 | | |
246 | 31.2k | if (!collectStrongDependencies(Checker.Dependencies, Mgr, Deps, |
247 | 31.2k | IsEnabledFromCmdLine)) { |
248 | | // If we failed to enable any of the dependencies, don't enable this |
249 | | // checker. |
250 | 5 | continue; |
251 | 5 | } |
252 | | |
253 | | // Note that set_union also preserves the order of insertion. |
254 | 31.2k | Data.EnabledCheckers.set_union(Deps); |
255 | 31.2k | Data.EnabledCheckers.insert(&Checker); |
256 | 31.2k | } |
257 | 1.84k | } |
258 | | |
259 | | template <typename IsEnabledFn> |
260 | | static bool collectStrongDependencies(const ConstCheckerInfoList &Deps, |
261 | | const CheckerManager &Mgr, |
262 | | CheckerInfoSet &Ret, |
263 | 73.0k | IsEnabledFn IsEnabled) { |
264 | | |
265 | 73.0k | for (const CheckerInfo *Dependency : Deps) { |
266 | 10.4k | if (!IsEnabled(Dependency)) |
267 | 10 | return false; |
268 | | |
269 | | // Collect dependencies recursively. |
270 | 10.4k | if (!collectStrongDependencies(Dependency->Dependencies, Mgr, Ret, |
271 | 10.4k | IsEnabled)) |
272 | 4 | return false; |
273 | 10.4k | Ret.insert(Dependency); |
274 | 10.4k | } |
275 | | |
276 | 73.0k | return true; |
277 | 73.0k | } CheckerRegistry.cpp:bool collectStrongDependencies<clang::ento::CheckerRegistry::initializeRegistry(clang::ento::CheckerManager const&)::$_0>(llvm::SmallVector<clang::ento::CheckerInfo const*, 0u> const&, clang::ento::CheckerManager const&, llvm::SetVector<clang::ento::CheckerInfo const*, llvm::SmallVector<clang::ento::CheckerInfo const*, 0u>, llvm::DenseSet<clang::ento::CheckerInfo const*, llvm::DenseMapInfo<clang::ento::CheckerInfo const*, void> >, 0u>&, clang::ento::CheckerRegistry::initializeRegistry(clang::ento::CheckerManager const&)::$_0) Line | Count | Source | 263 | 72.8k | IsEnabledFn IsEnabled) { | 264 | | | 265 | 72.8k | for (const CheckerInfo *Dependency : Deps) { | 266 | 10.3k | if (!IsEnabled(Dependency)) | 267 | 10 | return false; | 268 | | | 269 | | // Collect dependencies recursively. | 270 | 10.3k | if (!collectStrongDependencies(Dependency->Dependencies, Mgr, Ret, | 271 | 10.3k | IsEnabled)) | 272 | 4 | return false; | 273 | 10.3k | Ret.insert(Dependency); | 274 | 10.3k | } | 275 | | | 276 | 72.8k | return true; | 277 | 72.8k | } |
CheckerRegistry.cpp:bool collectStrongDependencies<clang::ento::CheckerRegistry::initializeRegistry(clang::ento::CheckerManager const&)::$_1>(llvm::SmallVector<clang::ento::CheckerInfo const*, 0u> const&, clang::ento::CheckerManager const&, llvm::SetVector<clang::ento::CheckerInfo const*, llvm::SmallVector<clang::ento::CheckerInfo const*, 0u>, llvm::DenseSet<clang::ento::CheckerInfo const*, llvm::DenseMapInfo<clang::ento::CheckerInfo const*, void> >, 0u>&, clang::ento::CheckerRegistry::initializeRegistry(clang::ento::CheckerManager const&)::$_1) Line | Count | Source | 263 | 223 | IsEnabledFn IsEnabled) { | 264 | | | 265 | 223 | for (const CheckerInfo *Dependency : Deps) { | 266 | 48 | if (!IsEnabled(Dependency)) | 267 | 0 | return false; | 268 | | | 269 | | // Collect dependencies recursively. | 270 | 48 | if (!collectStrongDependencies(Dependency->Dependencies, Mgr, Ret, | 271 | 48 | IsEnabled)) | 272 | 0 | return false; | 273 | 48 | Ret.insert(Dependency); | 274 | 48 | } | 275 | | | 276 | 223 | return true; | 277 | 223 | } |
|
278 | | |
279 | | template <typename IsEnabledFn> |
280 | | static void collectWeakDependencies(const ConstCheckerInfoList &WeakDeps, |
281 | | const CheckerManager &Mgr, |
282 | | CheckerInfoSet &Ret, |
283 | 31.4k | IsEnabledFn IsEnabled) { |
284 | | |
285 | 31.4k | for (const CheckerInfo *Dependency : WeakDeps) { |
286 | | // Don't enable this checker if strong dependencies are unsatisfied, but |
287 | | // assume that weak dependencies are transitive. |
288 | 244 | collectWeakDependencies(Dependency->WeakDependencies, Mgr, Ret, IsEnabled); |
289 | | |
290 | 244 | if (IsEnabled(Dependency) && |
291 | 244 | collectStrongDependencies(Dependency->Dependencies, Mgr, Ret, |
292 | 175 | IsEnabled)) |
293 | 175 | Ret.insert(Dependency); |
294 | 244 | } |
295 | 31.4k | } |
296 | | |
297 | 3.69k | template <bool IsWeak> void CheckerRegistry::resolveDependencies() { |
298 | 3.69k | for (const std::pair<StringRef, StringRef> &Entry : |
299 | 120k | (IsWeak3.69k ? Data.WeakDependencies1.84k : Data.Dependencies1.84k )) { |
300 | | |
301 | 120k | auto CheckerIt = binaryFind(Data.Checkers, Entry.first); |
302 | 120k | assert(CheckerIt != Data.Checkers.end() && |
303 | 120k | CheckerIt->FullName == Entry.first && |
304 | 120k | "Failed to find the checker while attempting to set up its " |
305 | 120k | "dependencies!"); |
306 | | |
307 | 120k | auto DependencyIt = binaryFind(Data.Checkers, Entry.second); |
308 | 120k | assert(DependencyIt != Data.Checkers.end() && |
309 | 120k | DependencyIt->FullName == Entry.second && |
310 | 120k | "Failed to find the dependency of a checker!"); |
311 | | |
312 | | // We do allow diagnostics from unit test/example dependency checkers. |
313 | 120k | assert((DependencyIt->FullName.startswith("test") || |
314 | 120k | DependencyIt->FullName.startswith("example") || IsWeak || |
315 | 120k | DependencyIt->IsHidden) && |
316 | 120k | "Strong dependencies are modeling checkers, and as such " |
317 | 120k | "non-user facing! Mark them hidden in Checkers.td!"); |
318 | | |
319 | 120k | if (IsWeak) |
320 | 7.40k | CheckerIt->WeakDependencies.emplace_back(&*DependencyIt); |
321 | 112k | else |
322 | 112k | CheckerIt->Dependencies.emplace_back(&*DependencyIt); |
323 | 120k | } |
324 | 3.69k | } void clang::ento::CheckerRegistry::resolveDependencies<true>() Line | Count | Source | 297 | 1.84k | template <bool IsWeak> void CheckerRegistry::resolveDependencies() { | 298 | 1.84k | for (const std::pair<StringRef, StringRef> &Entry : | 299 | 7.40k | (IsWeak1.84k ? Data.WeakDependencies1.84k : Data.Dependencies0 )) { | 300 | | | 301 | 7.40k | auto CheckerIt = binaryFind(Data.Checkers, Entry.first); | 302 | 7.40k | assert(CheckerIt != Data.Checkers.end() && | 303 | 7.40k | CheckerIt->FullName == Entry.first && | 304 | 7.40k | "Failed to find the checker while attempting to set up its " | 305 | 7.40k | "dependencies!"); | 306 | | | 307 | 7.40k | auto DependencyIt = binaryFind(Data.Checkers, Entry.second); | 308 | 7.40k | assert(DependencyIt != Data.Checkers.end() && | 309 | 7.40k | DependencyIt->FullName == Entry.second && | 310 | 7.40k | "Failed to find the dependency of a checker!"); | 311 | | | 312 | | // We do allow diagnostics from unit test/example dependency checkers. | 313 | 7.40k | assert((DependencyIt->FullName.startswith("test") || | 314 | 7.40k | DependencyIt->FullName.startswith("example") || IsWeak || | 315 | 7.40k | DependencyIt->IsHidden) && | 316 | 7.40k | "Strong dependencies are modeling checkers, and as such " | 317 | 7.40k | "non-user facing! Mark them hidden in Checkers.td!"); | 318 | | | 319 | 7.40k | if (IsWeak) | 320 | 7.40k | CheckerIt->WeakDependencies.emplace_back(&*DependencyIt); | 321 | 0 | else | 322 | 0 | CheckerIt->Dependencies.emplace_back(&*DependencyIt); | 323 | 7.40k | } | 324 | 1.84k | } |
void clang::ento::CheckerRegistry::resolveDependencies<false>() Line | Count | Source | 297 | 1.84k | template <bool IsWeak> void CheckerRegistry::resolveDependencies() { | 298 | 1.84k | for (const std::pair<StringRef, StringRef> &Entry : | 299 | 112k | (IsWeak1.84k ? Data.WeakDependencies0 : Data.Dependencies1.84k )) { | 300 | | | 301 | 112k | auto CheckerIt = binaryFind(Data.Checkers, Entry.first); | 302 | 112k | assert(CheckerIt != Data.Checkers.end() && | 303 | 112k | CheckerIt->FullName == Entry.first && | 304 | 112k | "Failed to find the checker while attempting to set up its " | 305 | 112k | "dependencies!"); | 306 | | | 307 | 112k | auto DependencyIt = binaryFind(Data.Checkers, Entry.second); | 308 | 112k | assert(DependencyIt != Data.Checkers.end() && | 309 | 112k | DependencyIt->FullName == Entry.second && | 310 | 112k | "Failed to find the dependency of a checker!"); | 311 | | | 312 | | // We do allow diagnostics from unit test/example dependency checkers. | 313 | 112k | assert((DependencyIt->FullName.startswith("test") || | 314 | 112k | DependencyIt->FullName.startswith("example") || IsWeak || | 315 | 112k | DependencyIt->IsHidden) && | 316 | 112k | "Strong dependencies are modeling checkers, and as such " | 317 | 112k | "non-user facing! Mark them hidden in Checkers.td!"); | 318 | | | 319 | 112k | if (IsWeak) | 320 | 0 | CheckerIt->WeakDependencies.emplace_back(&*DependencyIt); | 321 | 112k | else | 322 | 112k | CheckerIt->Dependencies.emplace_back(&*DependencyIt); | 323 | 112k | } | 324 | 1.84k | } |
|
325 | | |
326 | 112k | void CheckerRegistry::addDependency(StringRef FullName, StringRef Dependency) { |
327 | 112k | Data.Dependencies.emplace_back(FullName, Dependency); |
328 | 112k | } |
329 | | |
330 | | void CheckerRegistry::addWeakDependency(StringRef FullName, |
331 | 7.40k | StringRef Dependency) { |
332 | 7.40k | Data.WeakDependencies.emplace_back(FullName, Dependency); |
333 | 7.40k | } |
334 | | |
335 | | //===----------------------------------------------------------------------===// |
336 | | // Checker option resolving and validating. |
337 | | //===----------------------------------------------------------------------===// |
338 | | |
339 | | /// Insert the checker/package option to AnalyzerOptions' config table, and |
340 | | /// validate it, if the user supplied it on the command line. |
341 | | static void insertAndValidate(StringRef FullName, const CmdLineOption &Option, |
342 | | AnalyzerOptions &AnOpts, |
343 | 114k | DiagnosticsEngine &Diags) { |
344 | | |
345 | 114k | std::string FullOption = (FullName + ":" + Option.OptionName).str(); |
346 | | |
347 | 114k | auto It = |
348 | 114k | AnOpts.Config.insert({FullOption, std::string(Option.DefaultValStr)}); |
349 | | |
350 | | // Insertation was successful -- CmdLineOption's constructor will validate |
351 | | // whether values received from plugins or TableGen files are correct. |
352 | 114k | if (It.second) |
353 | 114k | return; |
354 | | |
355 | | // Insertion failed, the user supplied this package/checker option on the |
356 | | // command line. If the supplied value is invalid, we'll restore the option |
357 | | // to it's default value, and if we're in non-compatibility mode, we'll also |
358 | | // emit an error. |
359 | | |
360 | 381 | StringRef SuppliedValue = It.first->getValue(); |
361 | | |
362 | 381 | if (Option.OptionType == "bool") { |
363 | 310 | if (SuppliedValue != "true" && SuppliedValue != "false"148 ) { |
364 | 4 | if (AnOpts.ShouldEmitErrorsOnInvalidConfigValue) { |
365 | 2 | Diags.Report(diag::err_analyzer_checker_option_invalid_input) |
366 | 2 | << FullOption << "a boolean value"; |
367 | 2 | } |
368 | | |
369 | 4 | It.first->setValue(std::string(Option.DefaultValStr)); |
370 | 4 | } |
371 | 310 | return; |
372 | 310 | } |
373 | | |
374 | 71 | if (Option.OptionType == "int") { |
375 | 44 | int Tmp; |
376 | 44 | bool HasFailed = SuppliedValue.getAsInteger(0, Tmp); |
377 | 44 | if (HasFailed) { |
378 | 3 | if (AnOpts.ShouldEmitErrorsOnInvalidConfigValue) { |
379 | 1 | Diags.Report(diag::err_analyzer_checker_option_invalid_input) |
380 | 1 | << FullOption << "an integer value"; |
381 | 1 | } |
382 | | |
383 | 3 | It.first->setValue(std::string(Option.DefaultValStr)); |
384 | 3 | } |
385 | 44 | return; |
386 | 44 | } |
387 | 71 | } |
388 | | |
389 | | template <class T> |
390 | | static void insertOptionToCollection(StringRef FullName, T &Collection, |
391 | | const CmdLineOption &Option, |
392 | | AnalyzerOptions &AnOpts, |
393 | 114k | DiagnosticsEngine &Diags) { |
394 | 114k | auto It = binaryFind(Collection, FullName); |
395 | 114k | assert(It != Collection.end() && |
396 | 114k | "Failed to find the checker while attempting to add a command line " |
397 | 114k | "option to it!"); |
398 | | |
399 | 114k | insertAndValidate(FullName, Option, AnOpts, Diags); |
400 | | |
401 | 114k | It->CmdLineOptions.emplace_back(Option); |
402 | 114k | } CheckerRegistry.cpp:void insertOptionToCollection<std::__1::vector<clang::ento::CheckerInfo, std::__1::allocator<clang::ento::CheckerInfo> > >(llvm::StringRef, std::__1::vector<clang::ento::CheckerInfo, std::__1::allocator<clang::ento::CheckerInfo> >&, clang::ento::CmdLineOption const&, clang::AnalyzerOptions&, clang::DiagnosticsEngine&) Line | Count | Source | 393 | 112k | DiagnosticsEngine &Diags) { | 394 | 112k | auto It = binaryFind(Collection, FullName); | 395 | 112k | assert(It != Collection.end() && | 396 | 112k | "Failed to find the checker while attempting to add a command line " | 397 | 112k | "option to it!"); | 398 | | | 399 | 112k | insertAndValidate(FullName, Option, AnOpts, Diags); | 400 | | | 401 | 112k | It->CmdLineOptions.emplace_back(Option); | 402 | 112k | } |
CheckerRegistry.cpp:void insertOptionToCollection<llvm::SmallVector<clang::ento::PackageInfo, 0u> >(llvm::StringRef, llvm::SmallVector<clang::ento::PackageInfo, 0u>&, clang::ento::CmdLineOption const&, clang::AnalyzerOptions&, clang::DiagnosticsEngine&) Line | Count | Source | 393 | 1.84k | DiagnosticsEngine &Diags) { | 394 | 1.84k | auto It = binaryFind(Collection, FullName); | 395 | 1.84k | assert(It != Collection.end() && | 396 | 1.84k | "Failed to find the checker while attempting to add a command line " | 397 | 1.84k | "option to it!"); | 398 | | | 399 | 1.84k | insertAndValidate(FullName, Option, AnOpts, Diags); | 400 | | | 401 | 1.84k | It->CmdLineOptions.emplace_back(Option); | 402 | 1.84k | } |
|
403 | | |
404 | 1.84k | void CheckerRegistry::resolveCheckerAndPackageOptions() { |
405 | 1.84k | for (const std::pair<StringRef, CmdLineOption> &CheckerOptEntry : |
406 | 112k | Data.CheckerOptions) { |
407 | 112k | insertOptionToCollection(CheckerOptEntry.first, Data.Checkers, |
408 | 112k | CheckerOptEntry.second, AnOpts, Diags); |
409 | 112k | } |
410 | | |
411 | 1.84k | for (const std::pair<StringRef, CmdLineOption> &PackageOptEntry : |
412 | 1.84k | Data.PackageOptions) { |
413 | 1.84k | insertOptionToCollection(PackageOptEntry.first, Data.Packages, |
414 | 1.84k | PackageOptEntry.second, AnOpts, Diags); |
415 | 1.84k | } |
416 | 1.84k | } |
417 | | |
418 | 92.3k | void CheckerRegistry::addPackage(StringRef FullName) { |
419 | 92.3k | Data.Packages.emplace_back(PackageInfo(FullName)); |
420 | 92.3k | } |
421 | | |
422 | | void CheckerRegistry::addPackageOption(StringRef OptionType, |
423 | | StringRef PackageFullName, |
424 | | StringRef OptionName, |
425 | | StringRef DefaultValStr, |
426 | | StringRef Description, |
427 | | StringRef DevelopmentStatus, |
428 | 1.84k | bool IsHidden) { |
429 | 1.84k | Data.PackageOptions.emplace_back( |
430 | 1.84k | PackageFullName, CmdLineOption{OptionType, OptionName, DefaultValStr, |
431 | 1.84k | Description, DevelopmentStatus, IsHidden}); |
432 | 1.84k | } |
433 | | |
434 | | void CheckerRegistry::addChecker(RegisterCheckerFn Rfn, |
435 | | ShouldRegisterFunction Sfn, StringRef Name, |
436 | | StringRef Desc, StringRef DocsUri, |
437 | 356k | bool IsHidden) { |
438 | 356k | Data.Checkers.emplace_back(Rfn, Sfn, Name, Desc, DocsUri, IsHidden); |
439 | | |
440 | | // Record the presence of the checker in its packages. |
441 | 356k | StringRef PackageName, LeafName; |
442 | 356k | std::tie(PackageName, LeafName) = Name.rsplit(PackageSeparator); |
443 | 966k | while (!LeafName.empty()) { |
444 | 609k | Data.PackageSizes[PackageName] += 1; |
445 | 609k | std::tie(PackageName, LeafName) = PackageName.rsplit(PackageSeparator); |
446 | 609k | } |
447 | 356k | } |
448 | | |
449 | | void CheckerRegistry::addCheckerOption(StringRef OptionType, |
450 | | StringRef CheckerFullName, |
451 | | StringRef OptionName, |
452 | | StringRef DefaultValStr, |
453 | | StringRef Description, |
454 | | StringRef DevelopmentStatus, |
455 | 112k | bool IsHidden) { |
456 | 112k | Data.CheckerOptions.emplace_back( |
457 | 112k | CheckerFullName, CmdLineOption{OptionType, OptionName, DefaultValStr, |
458 | 112k | Description, DevelopmentStatus, IsHidden}); |
459 | 112k | } |
460 | | |
461 | 1.82k | void CheckerRegistry::initializeManager(CheckerManager &CheckerMgr) const { |
462 | | // Initialize the CheckerManager with all enabled checkers. |
463 | 31.7k | for (const auto *Checker : Data.EnabledCheckers) { |
464 | 31.7k | CheckerMgr.setCurrentCheckerName(CheckerNameRef(Checker->FullName)); |
465 | 31.7k | Checker->Initialize(CheckerMgr); |
466 | 31.7k | } |
467 | 1.82k | } |
468 | | |
469 | | static void isOptionContainedIn(const CmdLineOptionList &OptionList, |
470 | | StringRef SuppliedChecker, |
471 | | StringRef SuppliedOption, |
472 | | const AnalyzerOptions &AnOpts, |
473 | 114k | DiagnosticsEngine &Diags) { |
474 | | |
475 | 114k | if (!AnOpts.ShouldEmitErrorsOnInvalidConfigValue) |
476 | 1.48k | return; |
477 | | |
478 | 658k | auto SameOptName = [SuppliedOption](const CmdLineOption &Opt) 113k { |
479 | 658k | return Opt.OptionName == SuppliedOption; |
480 | 658k | }; |
481 | | |
482 | 113k | if (llvm::none_of(OptionList, SameOptName)) { |
483 | 1 | Diags.Report(diag::err_analyzer_checker_option_unknown) |
484 | 1 | << SuppliedChecker << SuppliedOption; |
485 | 1 | return; |
486 | 1 | } |
487 | 113k | } |
488 | | |
489 | 1.84k | void CheckerRegistry::validateCheckerOptions() const { |
490 | 240k | for (const auto &Config : AnOpts.Config) { |
491 | | |
492 | 240k | StringRef SuppliedCheckerOrPackage; |
493 | 240k | StringRef SuppliedOption; |
494 | 240k | std::tie(SuppliedCheckerOrPackage, SuppliedOption) = |
495 | 240k | Config.getKey().split(':'); |
496 | | |
497 | 240k | if (SuppliedOption.empty()) |
498 | 125k | continue; |
499 | | |
500 | | // AnalyzerOptions' config table contains the user input, so an entry could |
501 | | // look like this: |
502 | | // |
503 | | // cor:NoFalsePositives=true |
504 | | // |
505 | | // Since lower_bound would look for the first element *not less* than "cor", |
506 | | // it would return with an iterator to the first checker in the core, so we |
507 | | // we really have to use find here, which uses operator==. |
508 | 114k | auto CheckerIt = |
509 | 114k | llvm::find(Data.Checkers, CheckerInfo(SuppliedCheckerOrPackage)); |
510 | 114k | if (CheckerIt != Data.Checkers.end()) { |
511 | 112k | isOptionContainedIn(CheckerIt->CmdLineOptions, SuppliedCheckerOrPackage, |
512 | 112k | SuppliedOption, AnOpts, Diags); |
513 | 112k | continue; |
514 | 112k | } |
515 | | |
516 | 1.85k | const auto *PackageIt = |
517 | 1.85k | llvm::find(Data.Packages, PackageInfo(SuppliedCheckerOrPackage)); |
518 | 1.85k | if (PackageIt != Data.Packages.end()) { |
519 | 1.84k | isOptionContainedIn(PackageIt->CmdLineOptions, SuppliedCheckerOrPackage, |
520 | 1.84k | SuppliedOption, AnOpts, Diags); |
521 | 1.84k | continue; |
522 | 1.84k | } |
523 | | |
524 | 8 | Diags.Report(diag::err_unknown_analyzer_checker_or_package) |
525 | 8 | << SuppliedCheckerOrPackage; |
526 | 8 | } |
527 | 1.84k | } |