Coverage Report

Created: 2023-11-11 10:31

/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.85k
    : Data(Data), Diags(Diags), AnOpts(AnOpts) {
55
56
  // Register builtin checkers.
57
1.85k
#define GET_CHECKERS
58
1.85k
#define CHECKER(FULLNAME, CLASS, HELPTEXT, DOC_URI, IS_HIDDEN)                 \
59
360k
  addChecker(register##CLASS, shouldRegister##CLASS, FULLNAME, HELPTEXT,       \
60
360k
             DOC_URI, IS_HIDDEN);
61
62
1.85k
#define GET_PACKAGES
63
92.8k
#define PACKAGE(FULLNAME) addPackage(FULLNAME);
64
65
1.85k
#include "clang/StaticAnalyzer/Checkers/Checkers.inc"
66
1.85k
#undef CHECKER
67
1.85k
#undef GET_CHECKERS
68
1.85k
#undef PACKAGE
69
1.85k
#undef GET_PACKAGES
70
71
  // Register checkers from plugins.
72
1.85k
  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.85k
  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.85k
  llvm::sort(Data.Packages, checker_registry::PackageNameLT{});
115
1.85k
  llvm::sort(Data.Checkers, checker_registry::CheckerNameLT{});
116
117
1.85k
#define GET_CHECKER_DEPENDENCIES
118
119
1.85k
#define CHECKER_DEPENDENCY(FULLNAME, DEPENDENCY)                               \
120
113k
  addDependency(FULLNAME, DEPENDENCY);
121
122
1.85k
#define GET_CHECKER_WEAK_DEPENDENCIES
123
124
1.85k
#define CHECKER_WEAK_DEPENDENCY(FULLNAME, DEPENDENCY)                          \
125
7.42k
  addWeakDependency(FULLNAME, DEPENDENCY);
126
127
1.85k
#define GET_CHECKER_OPTIONS
128
1.85k
#define CHECKER_OPTION(TYPE, FULLNAME, CMDFLAG, DESC, DEFAULT_VAL,             \
129
1.85k
                       DEVELOPMENT_STATUS, IS_HIDDEN)                          \
130
115k
  addCheckerOption(TYPE, FULLNAME, CMDFLAG, DEFAULT_VAL, DESC,                 \
131
115k
                   DEVELOPMENT_STATUS, IS_HIDDEN);
132
133
1.85k
#define GET_PACKAGE_OPTIONS
134
1.85k
#define PACKAGE_OPTION(TYPE, FULLNAME, CMDFLAG, DESC, DEFAULT_VAL,             \
135
1.85k
                       DEVELOPMENT_STATUS, IS_HIDDEN)                          \
136
1.85k
  addPackageOption(TYPE, FULLNAME, CMDFLAG, DEFAULT_VAL, DESC,                 \
137
1.85k
                   DEVELOPMENT_STATUS, IS_HIDDEN);
138
139
1.85k
#include "clang/StaticAnalyzer/Checkers/Checkers.inc"
140
1.85k
#undef CHECKER_DEPENDENCY
141
1.85k
#undef GET_CHECKER_DEPENDENCIES
142
1.85k
#undef CHECKER_WEAK_DEPENDENCY
143
1.85k
#undef GET_CHECKER_WEAK_DEPENDENCIES
144
1.85k
#undef CHECKER_OPTION
145
1.85k
#undef GET_CHECKER_OPTIONS
146
1.85k
#undef PACKAGE_OPTION
147
1.85k
#undef GET_PACKAGE_OPTIONS
148
149
1.85k
  resolveDependencies<true>();
150
1.85k
  resolveDependencies<false>();
151
152
1.85k
#ifndef NDEBUG
153
113k
  for (auto &DepPair : Data.Dependencies) {
154
453k
    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
453k
      assert(WeakDepPair != DepPair &&
159
453k
             "A checker cannot strong and weak depend on the same checker!");
160
453k
      assert(WeakDepPair.first != DepPair.second &&
161
453k
             "A strong dependency mustn't have weak dependencies!");
162
453k
      assert(WeakDepPair.second != DepPair.second &&
163
453k
             "A strong dependency mustn't be a weak dependency as well!");
164
453k
    }
165
113k
  }
166
1.85k
#endif
167
168
1.85k
  resolveCheckerAndPackageOptions();
169
170
  // Parse '-analyzer-checker' and '-analyzer-disable-checker' options from the
171
  // command line.
172
3.62k
  for (const std::pair<std::string, bool> &Opt : AnOpts.CheckersAndPackages) {
173
3.62k
    CheckerInfoListRange CheckerForCmdLineArg =
174
3.62k
        Data.getMutableCheckersForCmdLineArg(Opt.first);
175
176
3.62k
    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
32.1k
    for (CheckerInfo &checker : CheckerForCmdLineArg) {
182
32.1k
      checker.State = Opt.second ? 
StateFromCmdLine::State_Enabled32.0k
183
32.1k
                                 : 
StateFromCmdLine::State_Disabled28
;
184
32.1k
    }
185
3.62k
  }
186
1.85k
  validateCheckerOptions();
187
1.85k
}
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.85k
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.85k
  CheckerInfoSet Tmp;
211
10.4k
  auto IsEnabledFromCmdLine = [&](const CheckerInfo *Checker) {
212
10.4k
    return !Checker->isDisabled(Mgr);
213
10.4k
  };
214
360k
  for (const CheckerInfo &Checker : Data.Checkers) {
215
360k
    if (!Checker.isEnabled(Mgr))
216
328k
      continue;
217
218
31.4k
    CheckerInfoSet Deps;
219
31.4k
    if (!collectStrongDependencies(Checker.Dependencies, Mgr, Deps,
220
31.4k
                                   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.4k
    Tmp.insert(Deps.begin(), Deps.end());
227
228
    // Enable the checker.
229
31.4k
    Tmp.insert(&Checker);
230
31.4k
  }
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.85k
  auto IsEnabled = [&](const CheckerInfo *Checker) {
236
409
    return Tmp.contains(Checker);
237
409
  };
238
360k
  for (const CheckerInfo &Checker : Data.Checkers) {
239
360k
    if (!Checker.isEnabled(Mgr))
240
328k
      continue;
241
242
31.4k
    CheckerInfoSet Deps;
243
244
31.4k
    collectWeakDependencies(Checker.WeakDependencies, Mgr, Deps, IsEnabled);
245
246
31.4k
    if (!collectStrongDependencies(Checker.Dependencies, Mgr, Deps,
247
31.4k
                                   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.4k
    Data.EnabledCheckers.set_union(Deps);
255
31.4k
    Data.EnabledCheckers.insert(&Checker);
256
31.4k
  }
257
1.85k
}
258
259
template <typename IsEnabledFn>
260
static bool collectStrongDependencies(const ConstCheckerInfoList &Deps,
261
                                      const CheckerManager &Mgr,
262
                                      CheckerInfoSet &Ret,
263
73.6k
                                      IsEnabledFn IsEnabled) {
264
265
73.6k
  for (const CheckerInfo *Dependency : Deps) {
266
10.5k
    if (!IsEnabled(Dependency))
267
10
      return false;
268
269
    // Collect dependencies recursively.
270
10.5k
    if (!collectStrongDependencies(Dependency->Dependencies, Mgr, Ret,
271
10.5k
                                   IsEnabled))
272
4
      return false;
273
10.5k
    Ret.insert(Dependency);
274
10.5k
  }
275
276
73.5k
  return true;
277
73.6k
}
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
73.2k
                                      IsEnabledFn IsEnabled) {
264
265
73.2k
  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.3k
    Ret.insert(Dependency);
274
10.3k
  }
275
276
73.2k
  return true;
277
73.2k
}
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
385
                                      IsEnabledFn IsEnabled) {
264
265
385
  for (const CheckerInfo *Dependency : Deps) {
266
118
    if (!IsEnabled(Dependency))
267
0
      return false;
268
269
    // Collect dependencies recursively.
270
118
    if (!collectStrongDependencies(Dependency->Dependencies, Mgr, Ret,
271
118
                                   IsEnabled))
272
0
      return false;
273
118
    Ret.insert(Dependency);
274
118
  }
275
276
385
  return true;
277
385
}
278
279
template <typename IsEnabledFn>
280
static void collectWeakDependencies(const ConstCheckerInfoList &WeakDeps,
281
                                    const CheckerManager &Mgr,
282
                                    CheckerInfoSet &Ret,
283
31.7k
                                    IsEnabledFn IsEnabled) {
284
285
31.7k
  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
291
    collectWeakDependencies(Dependency->WeakDependencies, Mgr, Ret, IsEnabled);
289
290
291
    if (IsEnabled(Dependency) &&
291
291
        collectStrongDependencies(Dependency->Dependencies, Mgr, Ret,
292
267
                                  IsEnabled))
293
267
      Ret.insert(Dependency);
294
291
  }
295
31.7k
}
296
297
3.71k
template <bool IsWeak> void CheckerRegistry::resolveDependencies() {
298
3.71k
  for (const std::pair<StringRef, StringRef> &Entry :
299
120k
       (
IsWeak3.71k
?
Data.WeakDependencies1.85k
:
Data.Dependencies1.85k
)) {
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.43k
      CheckerIt->WeakDependencies.emplace_back(&*DependencyIt);
321
113k
    else
322
113k
      CheckerIt->Dependencies.emplace_back(&*DependencyIt);
323
120k
  }
324
3.71k
}
void clang::ento::CheckerRegistry::resolveDependencies<true>()
Line
Count
Source
297
1.85k
template <bool IsWeak> void CheckerRegistry::resolveDependencies() {
298
1.85k
  for (const std::pair<StringRef, StringRef> &Entry :
299
7.43k
       (
IsWeak1.85k
?
Data.WeakDependencies1.85k
:
Data.Dependencies0
)) {
300
301
7.43k
    auto CheckerIt = binaryFind(Data.Checkers, Entry.first);
302
7.43k
    assert(CheckerIt != Data.Checkers.end() &&
303
7.43k
           CheckerIt->FullName == Entry.first &&
304
7.43k
           "Failed to find the checker while attempting to set up its "
305
7.43k
           "dependencies!");
306
307
7.43k
    auto DependencyIt = binaryFind(Data.Checkers, Entry.second);
308
7.43k
    assert(DependencyIt != Data.Checkers.end() &&
309
7.43k
           DependencyIt->FullName == Entry.second &&
310
7.43k
           "Failed to find the dependency of a checker!");
311
312
    // We do allow diagnostics from unit test/example dependency checkers.
313
7.43k
    assert((DependencyIt->FullName.startswith("test") ||
314
7.43k
            DependencyIt->FullName.startswith("example") || IsWeak ||
315
7.43k
            DependencyIt->IsHidden) &&
316
7.43k
           "Strong dependencies are modeling checkers, and as such "
317
7.43k
           "non-user facing! Mark them hidden in Checkers.td!");
318
319
7.43k
    if (IsWeak)
320
7.43k
      CheckerIt->WeakDependencies.emplace_back(&*DependencyIt);
321
0
    else
322
0
      CheckerIt->Dependencies.emplace_back(&*DependencyIt);
323
7.43k
  }
324
1.85k
}
void clang::ento::CheckerRegistry::resolveDependencies<false>()
Line
Count
Source
297
1.85k
template <bool IsWeak> void CheckerRegistry::resolveDependencies() {
298
1.85k
  for (const std::pair<StringRef, StringRef> &Entry :
299
113k
       (
IsWeak1.85k
?
Data.WeakDependencies0
:
Data.Dependencies1.85k
)) {
300
301
113k
    auto CheckerIt = binaryFind(Data.Checkers, Entry.first);
302
113k
    assert(CheckerIt != Data.Checkers.end() &&
303
113k
           CheckerIt->FullName == Entry.first &&
304
113k
           "Failed to find the checker while attempting to set up its "
305
113k
           "dependencies!");
306
307
113k
    auto DependencyIt = binaryFind(Data.Checkers, Entry.second);
308
113k
    assert(DependencyIt != Data.Checkers.end() &&
309
113k
           DependencyIt->FullName == Entry.second &&
310
113k
           "Failed to find the dependency of a checker!");
311
312
    // We do allow diagnostics from unit test/example dependency checkers.
313
113k
    assert((DependencyIt->FullName.startswith("test") ||
314
113k
            DependencyIt->FullName.startswith("example") || IsWeak ||
315
113k
            DependencyIt->IsHidden) &&
316
113k
           "Strong dependencies are modeling checkers, and as such "
317
113k
           "non-user facing! Mark them hidden in Checkers.td!");
318
319
113k
    if (IsWeak)
320
0
      CheckerIt->WeakDependencies.emplace_back(&*DependencyIt);
321
113k
    else
322
113k
      CheckerIt->Dependencies.emplace_back(&*DependencyIt);
323
113k
  }
324
1.85k
}
325
326
113k
void CheckerRegistry::addDependency(StringRef FullName, StringRef Dependency) {
327
113k
  Data.Dependencies.emplace_back(FullName, Dependency);
328
113k
}
329
330
void CheckerRegistry::addWeakDependency(StringRef FullName,
331
7.43k
                                        StringRef Dependency) {
332
7.43k
  Data.WeakDependencies.emplace_back(FullName, Dependency);
333
7.43k
}
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
116k
                              DiagnosticsEngine &Diags) {
344
345
116k
  std::string FullOption = (FullName + ":" + Option.OptionName).str();
346
347
116k
  auto It =
348
116k
      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
116k
  if (It.second)
353
116k
    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
388
  StringRef SuppliedValue = It.first->getValue();
361
362
388
  if (Option.OptionType == "bool") {
363
317
    if (SuppliedValue != "true" && 
SuppliedValue != "false"152
) {
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
317
    return;
372
317
  }
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
116k
                                     DiagnosticsEngine &Diags) {
394
116k
  auto It = binaryFind(Collection, FullName);
395
116k
  assert(It != Collection.end() &&
396
116k
         "Failed to find the checker while attempting to add a command line "
397
116k
         "option to it!");
398
399
116k
  insertAndValidate(FullName, Option, AnOpts, Diags);
400
401
116k
  It->CmdLineOptions.emplace_back(Option);
402
116k
}
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
115k
                                     DiagnosticsEngine &Diags) {
394
115k
  auto It = binaryFind(Collection, FullName);
395
115k
  assert(It != Collection.end() &&
396
115k
         "Failed to find the checker while attempting to add a command line "
397
115k
         "option to it!");
398
399
115k
  insertAndValidate(FullName, Option, AnOpts, Diags);
400
401
115k
  It->CmdLineOptions.emplace_back(Option);
402
115k
}
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.85k
                                     DiagnosticsEngine &Diags) {
394
1.85k
  auto It = binaryFind(Collection, FullName);
395
1.85k
  assert(It != Collection.end() &&
396
1.85k
         "Failed to find the checker while attempting to add a command line "
397
1.85k
         "option to it!");
398
399
1.85k
  insertAndValidate(FullName, Option, AnOpts, Diags);
400
401
1.85k
  It->CmdLineOptions.emplace_back(Option);
402
1.85k
}
403
404
1.85k
void CheckerRegistry::resolveCheckerAndPackageOptions() {
405
1.85k
  for (const std::pair<StringRef, CmdLineOption> &CheckerOptEntry :
406
115k
       Data.CheckerOptions) {
407
115k
    insertOptionToCollection(CheckerOptEntry.first, Data.Checkers,
408
115k
                             CheckerOptEntry.second, AnOpts, Diags);
409
115k
  }
410
411
1.85k
  for (const std::pair<StringRef, CmdLineOption> &PackageOptEntry :
412
1.85k
       Data.PackageOptions) {
413
1.85k
    insertOptionToCollection(PackageOptEntry.first, Data.Packages,
414
1.85k
                             PackageOptEntry.second, AnOpts, Diags);
415
1.85k
  }
416
1.85k
}
417
418
92.8k
void CheckerRegistry::addPackage(StringRef FullName) {
419
92.8k
  Data.Packages.emplace_back(PackageInfo(FullName));
420
92.8k
}
421
422
void CheckerRegistry::addPackageOption(StringRef OptionType,
423
                                       StringRef PackageFullName,
424
                                       StringRef OptionName,
425
                                       StringRef DefaultValStr,
426
                                       StringRef Description,
427
                                       StringRef DevelopmentStatus,
428
1.85k
                                       bool IsHidden) {
429
1.85k
  Data.PackageOptions.emplace_back(
430
1.85k
      PackageFullName, CmdLineOption{OptionType, OptionName, DefaultValStr,
431
1.85k
                                     Description, DevelopmentStatus, IsHidden});
432
1.85k
}
433
434
void CheckerRegistry::addChecker(RegisterCheckerFn Rfn,
435
                                 ShouldRegisterFunction Sfn, StringRef Name,
436
                                 StringRef Desc, StringRef DocsUri,
437
360k
                                 bool IsHidden) {
438
360k
  Data.Checkers.emplace_back(Rfn, Sfn, Name, Desc, DocsUri, IsHidden);
439
440
  // Record the presence of the checker in its packages.
441
360k
  StringRef PackageName, LeafName;
442
360k
  std::tie(PackageName, LeafName) = Name.rsplit(PackageSeparator);
443
974k
  while (!LeafName.empty()) {
444
614k
    Data.PackageSizes[PackageName] += 1;
445
614k
    std::tie(PackageName, LeafName) = PackageName.rsplit(PackageSeparator);
446
614k
  }
447
360k
}
448
449
void CheckerRegistry::addCheckerOption(StringRef OptionType,
450
                                       StringRef CheckerFullName,
451
                                       StringRef OptionName,
452
                                       StringRef DefaultValStr,
453
                                       StringRef Description,
454
                                       StringRef DevelopmentStatus,
455
115k
                                       bool IsHidden) {
456
115k
  Data.CheckerOptions.emplace_back(
457
115k
      CheckerFullName, CmdLineOption{OptionType, OptionName, DefaultValStr,
458
115k
                                     Description, DevelopmentStatus, IsHidden});
459
115k
}
460
461
1.83k
void CheckerRegistry::initializeManager(CheckerManager &CheckerMgr) const {
462
  // Initialize the CheckerManager with all enabled checkers.
463
31.9k
  for (const auto *Checker : Data.EnabledCheckers) {
464
31.9k
    CheckerMgr.setCurrentCheckerName(CheckerNameRef(Checker->FullName));
465
31.9k
    Checker->Initialize(CheckerMgr);
466
31.9k
  }
467
1.83k
}
468
469
static void isOptionContainedIn(const CmdLineOptionList &OptionList,
470
                                StringRef SuppliedChecker,
471
                                StringRef SuppliedOption,
472
                                const AnalyzerOptions &AnOpts,
473
116k
                                DiagnosticsEngine &Diags) {
474
475
116k
  if (!AnOpts.ShouldEmitErrorsOnInvalidConfigValue)
476
1.51k
    return;
477
478
663k
  
auto SameOptName = [SuppliedOption](const CmdLineOption &Opt) 115k
{
479
663k
    return Opt.OptionName == SuppliedOption;
480
663k
  };
481
482
115k
  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
115k
}
488
489
1.85k
void CheckerRegistry::validateCheckerOptions() const {
490
243k
  for (const auto &Config : AnOpts.Config) {
491
492
243k
    StringRef SuppliedCheckerOrPackage;
493
243k
    StringRef SuppliedOption;
494
243k
    std::tie(SuppliedCheckerOrPackage, SuppliedOption) =
495
243k
        Config.getKey().split(':');
496
497
243k
    if (SuppliedOption.empty())
498
126k
      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
116k
    auto CheckerIt =
509
116k
        llvm::find(Data.Checkers, CheckerInfo(SuppliedCheckerOrPackage));
510
116k
    if (CheckerIt != Data.Checkers.end()) {
511
115k
      isOptionContainedIn(CheckerIt->CmdLineOptions, SuppliedCheckerOrPackage,
512
115k
                          SuppliedOption, AnOpts, Diags);
513
115k
      continue;
514
115k
    }
515
516
1.86k
    const auto *PackageIt =
517
1.86k
        llvm::find(Data.Packages, PackageInfo(SuppliedCheckerOrPackage));
518
1.86k
    if (PackageIt != Data.Packages.end()) {
519
1.85k
      isOptionContainedIn(PackageIt->CmdLineOptions, SuppliedCheckerOrPackage,
520
1.85k
                          SuppliedOption, AnOpts, Diags);
521
1.85k
      continue;
522
1.85k
    }
523
524
8
    Diags.Report(diag::err_unknown_analyzer_checker_or_package)
525
8
        << SuppliedCheckerOrPackage;
526
8
  }
527
1.85k
}