Coverage Report

Created: 2020-02-15 09:57

/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/SetVector.h"
19
#include "llvm/ADT/StringMap.h"
20
#include "llvm/ADT/StringRef.h"
21
#include "llvm/Support/DynamicLibrary.h"
22
#include "llvm/Support/Path.h"
23
#include "llvm/Support/raw_ostream.h"
24
#include <algorithm>
25
26
using namespace clang;
27
using namespace ento;
28
using llvm::sys::DynamicLibrary;
29
30
using RegisterCheckersFn = void (*)(CheckerRegistry &);
31
32
0
static bool isCompatibleAPIVersion(const char *VersionString) {
33
0
  // If the version string is null, its not an analyzer plugin.
34
0
  if (!VersionString)
35
0
    return false;
36
0
37
0
  // For now, none of the static analyzer API is considered stable.
38
0
  // Versions must match exactly.
39
0
  return strcmp(VersionString, CLANG_ANALYZER_API_VERSION_STRING) == 0;
40
0
}
41
42
namespace {
43
template <class T> struct FullNameLT {
44
38.6M
  bool operator()(const T &Lhs, const T &Rhs) {
45
38.6M
    return Lhs.FullName < Rhs.FullName;
46
38.6M
  }
CheckerRegistry.cpp:(anonymous namespace)::FullNameLT<clang::ento::CheckerRegistry::CheckerInfo>::operator()(clang::ento::CheckerRegistry::CheckerInfo const&, clang::ento::CheckerRegistry::CheckerInfo const&)
Line
Count
Source
44
38.2M
  bool operator()(const T &Lhs, const T &Rhs) {
45
38.2M
    return Lhs.FullName < Rhs.FullName;
46
38.2M
  }
CheckerRegistry.cpp:(anonymous namespace)::FullNameLT<clang::ento::CheckerRegistry::PackageInfo>::operator()(clang::ento::CheckerRegistry::PackageInfo const&, clang::ento::CheckerRegistry::PackageInfo const&)
Line
Count
Source
44
358k
  bool operator()(const T &Lhs, const T &Rhs) {
45
358k
    return Lhs.FullName < Rhs.FullName;
46
358k
  }
47
};
48
49
using PackageNameLT = FullNameLT<CheckerRegistry::PackageInfo>;
50
using CheckerNameLT = FullNameLT<CheckerRegistry::CheckerInfo>;
51
} // end of anonymous namespace
52
53
template <class CheckerOrPackageInfoList>
54
static std::conditional_t<std::is_const<CheckerOrPackageInfoList>::value,
55
                          typename CheckerOrPackageInfoList::const_iterator,
56
                          typename CheckerOrPackageInfoList::iterator>
57
201k
binaryFind(CheckerOrPackageInfoList &Collection, StringRef FullName) {
58
201k
59
201k
  using CheckerOrPackage = typename CheckerOrPackageInfoList::value_type;
60
201k
  using CheckerOrPackageFullNameLT = FullNameLT<CheckerOrPackage>;
61
201k
62
201k
  assert(std::is_sorted(Collection.begin(), Collection.end(),
63
201k
                        CheckerOrPackageFullNameLT{}) &&
64
201k
         "In order to efficiently gather checkers/packages, this function "
65
201k
         "expects them to be already sorted!");
66
201k
67
201k
  return llvm::lower_bound(Collection, CheckerOrPackage(FullName),
68
201k
                           CheckerOrPackageFullNameLT{});
69
201k
}
CheckerRegistry.cpp:std::__1::conditional<std::is_const<std::__1::vector<clang::ento::CheckerRegistry::CheckerInfo, std::__1::allocator<clang::ento::CheckerRegistry::CheckerInfo> > >::value, std::__1::vector<clang::ento::CheckerRegistry::CheckerInfo, std::__1::allocator<clang::ento::CheckerRegistry::CheckerInfo> >::const_iterator, std::__1::vector<clang::ento::CheckerRegistry::CheckerInfo, std::__1::allocator<clang::ento::CheckerRegistry::CheckerInfo> >::iterator>::type binaryFind<std::__1::vector<clang::ento::CheckerRegistry::CheckerInfo, std::__1::allocator<clang::ento::CheckerRegistry::CheckerInfo> > >(std::__1::vector<clang::ento::CheckerRegistry::CheckerInfo, std::__1::allocator<clang::ento::CheckerRegistry::CheckerInfo> >&, llvm::StringRef)
Line
Count
Source
57
199k
binaryFind(CheckerOrPackageInfoList &Collection, StringRef FullName) {
58
199k
59
199k
  using CheckerOrPackage = typename CheckerOrPackageInfoList::value_type;
60
199k
  using CheckerOrPackageFullNameLT = FullNameLT<CheckerOrPackage>;
61
199k
62
199k
  assert(std::is_sorted(Collection.begin(), Collection.end(),
63
199k
                        CheckerOrPackageFullNameLT{}) &&
64
199k
         "In order to efficiently gather checkers/packages, this function "
65
199k
         "expects them to be already sorted!");
66
199k
67
199k
  return llvm::lower_bound(Collection, CheckerOrPackage(FullName),
68
199k
                           CheckerOrPackageFullNameLT{});
69
199k
}
CheckerRegistry.cpp:std::__1::conditional<std::is_const<llvm::SmallVector<clang::ento::CheckerRegistry::PackageInfo, 0u> >::value, llvm::SmallVector<clang::ento::CheckerRegistry::PackageInfo, 0u>::const_iterator, llvm::SmallVector<clang::ento::CheckerRegistry::PackageInfo, 0u>::iterator>::type binaryFind<llvm::SmallVector<clang::ento::CheckerRegistry::PackageInfo, 0u> >(llvm::SmallVector<clang::ento::CheckerRegistry::PackageInfo, 0u>&, llvm::StringRef)
Line
Count
Source
57
1.26k
binaryFind(CheckerOrPackageInfoList &Collection, StringRef FullName) {
58
1.26k
59
1.26k
  using CheckerOrPackage = typename CheckerOrPackageInfoList::value_type;
60
1.26k
  using CheckerOrPackageFullNameLT = FullNameLT<CheckerOrPackage>;
61
1.26k
62
1.26k
  assert(std::is_sorted(Collection.begin(), Collection.end(),
63
1.26k
                        CheckerOrPackageFullNameLT{}) &&
64
1.26k
         "In order to efficiently gather checkers/packages, this function "
65
1.26k
         "expects them to be already sorted!");
66
1.26k
67
1.26k
  return llvm::lower_bound(Collection, CheckerOrPackage(FullName),
68
1.26k
                           CheckerOrPackageFullNameLT{});
69
1.26k
}
70
71
static constexpr char PackageSeparator = '.';
72
73
static bool isInPackage(const CheckerRegistry::CheckerInfo &Checker,
74
2.49k
                        StringRef PackageName) {
75
2.49k
  // Does the checker's full name have the package as a prefix?
76
2.49k
  if (!Checker.FullName.startswith(PackageName))
77
1
    return false;
78
2.49k
79
2.49k
  // Is the package actually just the name of a specific checker?
80
2.49k
  if (Checker.FullName.size() == PackageName.size())
81
1.14k
    return true;
82
1.34k
83
1.34k
  // Is the checker in the package (or a subpackage)?
84
1.34k
  if (Checker.FullName[PackageName.size()] == PackageSeparator)
85
1.34k
    return true;
86
0
87
0
  return false;
88
0
}
89
90
CheckerRegistry::CheckerInfoListRange
91
2.49k
CheckerRegistry::getMutableCheckersForCmdLineArg(StringRef CmdLineArg) {
92
2.49k
  auto It = binaryFind(Checkers, CmdLineArg);
93
2.49k
94
2.49k
  if (!isInPackage(*It, CmdLineArg))
95
1
    return {Checkers.end(), Checkers.end()};
96
2.49k
97
2.49k
  // See how large the package is.
98
2.49k
  // If the package doesn't exist, assume the option refers to a single
99
2.49k
  // checker.
100
2.49k
  size_t Size = 1;
101
2.49k
  llvm::StringMap<size_t>::const_iterator PackageSize =
102
2.49k
      PackageSizes.find(CmdLineArg);
103
2.49k
104
2.49k
  if (PackageSize != PackageSizes.end())
105
1.34k
    Size = PackageSize->getValue();
106
2.49k
107
2.49k
  return {It, It + Size};
108
2.49k
}
109
110
CheckerRegistry::CheckerRegistry(
111
    ArrayRef<std::string> Plugins, DiagnosticsEngine &Diags,
112
    AnalyzerOptions &AnOpts, const LangOptions &LangOpts,
113
    ArrayRef<std::function<void(CheckerRegistry &)>> CheckerRegistrationFns)
114
1.26k
    : Diags(Diags), AnOpts(AnOpts), LangOpts(LangOpts) {
115
1.26k
116
1.26k
  // Register builtin checkers.
117
1.26k
#define GET_CHECKERS
118
1.26k
#define CHECKER(FULLNAME, CLASS, HELPTEXT, DOC_URI, IS_HIDDEN)                 \
119
222k
  addChecker(register##CLASS, shouldRegister##CLASS, FULLNAME, HELPTEXT,       \
120
222k
             DOC_URI, IS_HIDDEN);
121
1.26k
122
1.26k
#define GET_PACKAGES
123
55.7k
#define PACKAGE(FULLNAME) addPackage(FULLNAME);
124
1.26k
125
1.26k
#include "clang/StaticAnalyzer/Checkers/Checkers.inc"
126
1.26k
#undef CHECKER
127
1.26k
#undef GET_CHECKERS
128
1.26k
#undef PACKAGE
129
1.26k
#undef GET_PACKAGES
130
1.26k
131
1.26k
  // Register checkers from plugins.
132
1.26k
  for (const std::string &Plugin : Plugins) {
133
0
    // Get access to the plugin.
134
0
    std::string ErrorMsg;
135
0
    DynamicLibrary Lib =
136
0
        DynamicLibrary::getPermanentLibrary(Plugin.c_str(), &ErrorMsg);
137
0
    if (!Lib.isValid()) {
138
0
      Diags.Report(diag::err_fe_unable_to_load_plugin) << Plugin << ErrorMsg;
139
0
      continue;
140
0
    }
141
0
142
0
    // See if its compatible with this build of clang.
143
0
    const char *PluginAPIVersion = static_cast<const char *>(
144
0
        Lib.getAddressOfSymbol("clang_analyzerAPIVersionString"));
145
0
146
0
    if (!isCompatibleAPIVersion(PluginAPIVersion)) {
147
0
      Diags.Report(diag::warn_incompatible_analyzer_plugin_api)
148
0
          << llvm::sys::path::filename(Plugin);
149
0
      Diags.Report(diag::note_incompatible_analyzer_plugin_api)
150
0
          << CLANG_ANALYZER_API_VERSION_STRING << PluginAPIVersion;
151
0
      continue;
152
0
    }
153
0
154
0
    // Register its checkers.
155
0
    RegisterCheckersFn RegisterPluginCheckers =
156
0
        reinterpret_cast<RegisterCheckersFn>(
157
0
            Lib.getAddressOfSymbol("clang_registerCheckers"));
158
0
    if (RegisterPluginCheckers)
159
0
      RegisterPluginCheckers(*this);
160
0
  }
161
1.26k
162
1.26k
  // Register statically linked checkers, that aren't generated from the tblgen
163
1.26k
  // file, but rather passed their registry function as a parameter in
164
1.26k
  // checkerRegistrationFns.
165
1.26k
166
1.26k
  for (const auto &Fn : CheckerRegistrationFns)
167
2
    Fn(*this);
168
1.26k
169
1.26k
  // Sort checkers for efficient collection.
170
1.26k
  // FIXME: Alphabetical sort puts 'experimental' in the middle.
171
1.26k
  // Would it be better to name it '~experimental' or something else
172
1.26k
  // that's ASCIIbetically last?
173
1.26k
  llvm::sort(Packages, PackageNameLT{});
174
1.26k
  llvm::sort(Checkers, CheckerNameLT{});
175
1.26k
176
1.26k
#define GET_CHECKER_DEPENDENCIES
177
1.26k
178
1.26k
#define CHECKER_DEPENDENCY(FULLNAME, DEPENDENCY)                               \
179
73.4k
  addDependency(FULLNAME, DEPENDENCY);
180
1.26k
181
1.26k
#define GET_CHECKER_OPTIONS
182
1.26k
#define CHECKER_OPTION(TYPE, FULLNAME, CMDFLAG, DESC, DEFAULT_VAL, DEVELOPMENT_STATUS, IS_HIDDEN)  \
183
50.6k
  addCheckerOption(TYPE, FULLNAME, CMDFLAG, DEFAULT_VAL, DESC, DEVELOPMENT_STATUS, IS_HIDDEN);
184
1.26k
185
1.26k
#define GET_PACKAGE_OPTIONS
186
1.26k
#define PACKAGE_OPTION(TYPE, FULLNAME, CMDFLAG, DESC, DEFAULT_VAL, DEVELOPMENT_STATUS, IS_HIDDEN)  \
187
1.26k
  addPackageOption(TYPE, FULLNAME, CMDFLAG, DEFAULT_VAL, DESC, DEVELOPMENT_STATUS, IS_HIDDEN);
188
1.26k
189
1.26k
#include "clang/StaticAnalyzer/Checkers/Checkers.inc"
190
1.26k
#undef CHECKER_DEPENDENCY
191
1.26k
#undef GET_CHECKER_DEPENDENCIES
192
1.26k
#undef CHECKER_OPTION
193
1.26k
#undef GET_CHECKER_OPTIONS
194
1.26k
#undef PACKAGE_OPTION
195
1.26k
#undef GET_PACKAGE_OPTIONS
196
1.26k
197
1.26k
  resolveDependencies();
198
1.26k
  resolveCheckerAndPackageOptions();
199
1.26k
200
1.26k
  // Parse '-analyzer-checker' and '-analyzer-disable-checker' options from the
201
1.26k
  // command line.
202
2.49k
  for (const std::pair<std::string, bool> &Opt : AnOpts.CheckersAndPackages) {
203
2.49k
    CheckerInfoListRange CheckerForCmdLineArg =
204
2.49k
        getMutableCheckersForCmdLineArg(Opt.first);
205
2.49k
206
2.49k
    if (CheckerForCmdLineArg.begin() == CheckerForCmdLineArg.end()) {
207
1
      Diags.Report(diag::err_unknown_analyzer_checker_or_package) << Opt.first;
208
1
      Diags.Report(diag::note_suggest_disabling_all_checkers);
209
1
    }
210
2.49k
211
21.6k
    for (CheckerInfo &checker : CheckerForCmdLineArg) {
212
21.6k
      checker.State = Opt.second ? 
StateFromCmdLine::State_Enabled21.6k
213
21.6k
                                 : 
StateFromCmdLine::State_Disabled7
;
214
21.6k
    }
215
2.49k
  }
216
1.26k
}
217
218
/// Collects dependencies in \p ret, returns false on failure.
219
static bool
220
collectDependenciesImpl(const CheckerRegistry::ConstCheckerInfoList &Deps,
221
                        const LangOptions &LO,
222
                        CheckerRegistry::CheckerInfoSet &Ret);
223
224
/// Collects dependenies in \p enabledCheckers. Return None on failure.
225
LLVM_NODISCARD
226
static llvm::Optional<CheckerRegistry::CheckerInfoSet>
227
collectDependencies(const CheckerRegistry::CheckerInfo &checker,
228
21.5k
                    const LangOptions &LO) {
229
21.5k
230
21.5k
  CheckerRegistry::CheckerInfoSet Ret;
231
21.5k
  // Add dependencies to the enabled checkers only if all of them can be
232
21.5k
  // enabled.
233
21.5k
  if (!collectDependenciesImpl(checker.Dependencies, LO, Ret))
234
1
    return None;
235
21.5k
236
21.5k
  return Ret;
237
21.5k
}
238
239
static bool
240
collectDependenciesImpl(const CheckerRegistry::ConstCheckerInfoList &Deps,
241
                        const LangOptions &LO,
242
24.7k
                        CheckerRegistry::CheckerInfoSet &Ret) {
243
24.7k
244
24.7k
  for (const CheckerRegistry::CheckerInfo *Dependency : Deps) {
245
3.24k
246
3.24k
    if (Dependency->isDisabled(LO))
247
1
      return false;
248
3.24k
249
3.24k
    // Collect dependencies recursively.
250
3.24k
    if (!collectDependenciesImpl(Dependency->Dependencies, LO, Ret))
251
0
      return false;
252
3.24k
253
3.24k
    Ret.insert(Dependency);
254
3.24k
  }
255
24.7k
256
24.7k
  
return true24.7k
;
257
24.7k
}
258
259
1.25k
CheckerRegistry::CheckerInfoSet CheckerRegistry::getEnabledCheckers() const {
260
1.25k
261
1.25k
  CheckerInfoSet EnabledCheckers;
262
1.25k
263
220k
  for (const CheckerInfo &Checker : Checkers) {
264
220k
    if (!Checker.isEnabled(LangOpts))
265
198k
      continue;
266
21.5k
267
21.5k
    // Recursively enable its dependencies.
268
21.5k
    llvm::Optional<CheckerInfoSet> Deps =
269
21.5k
        collectDependencies(Checker, LangOpts);
270
21.5k
271
21.5k
    if (!Deps) {
272
1
      // If we failed to enable any of the dependencies, don't enable this
273
1
      // checker.
274
1
      continue;
275
1
    }
276
21.5k
277
21.5k
    // Note that set_union also preserves the order of insertion.
278
21.5k
    EnabledCheckers.set_union(*Deps);
279
21.5k
280
21.5k
    // Enable the checker.
281
21.5k
    EnabledCheckers.insert(&Checker);
282
21.5k
  }
283
1.25k
284
1.25k
  return EnabledCheckers;
285
1.25k
}
286
287
1.26k
void CheckerRegistry::resolveDependencies() {
288
73.4k
  for (const std::pair<StringRef, StringRef> &Entry : Dependencies) {
289
73.4k
    auto CheckerIt = binaryFind(Checkers, Entry.first);
290
73.4k
    assert(CheckerIt != Checkers.end() && CheckerIt->FullName == Entry.first &&
291
73.4k
           "Failed to find the checker while attempting to set up its "
292
73.4k
           "dependencies!");
293
73.4k
294
73.4k
    auto DependencyIt = binaryFind(Checkers, Entry.second);
295
73.4k
    assert(DependencyIt != Checkers.end() &&
296
73.4k
           DependencyIt->FullName == Entry.second &&
297
73.4k
           "Failed to find the dependency of a checker!");
298
73.4k
299
73.4k
    CheckerIt->Dependencies.emplace_back(&*DependencyIt);
300
73.4k
  }
301
1.26k
302
1.26k
  Dependencies.clear();
303
1.26k
}
304
305
73.4k
void CheckerRegistry::addDependency(StringRef FullName, StringRef Dependency) {
306
73.4k
  Dependencies.emplace_back(FullName, Dependency);
307
73.4k
}
308
309
/// Insert the checker/package option to AnalyzerOptions' config table, and
310
/// validate it, if the user supplied it on the command line.
311
static void insertAndValidate(StringRef FullName,
312
                              const CheckerRegistry::CmdLineOption &Option,
313
                              AnalyzerOptions &AnOpts,
314
51.9k
                              DiagnosticsEngine &Diags) {
315
51.9k
316
51.9k
  std::string FullOption = (FullName + ":" + Option.OptionName).str();
317
51.9k
318
51.9k
  auto It =
319
51.9k
      AnOpts.Config.insert({FullOption, std::string(Option.DefaultValStr)});
320
51.9k
321
51.9k
  // Insertation was successful -- CmdLineOption's constructor will validate
322
51.9k
  // whether values received from plugins or TableGen files are correct.
323
51.9k
  if (It.second)
324
51.7k
    return;
325
204
326
204
  // Insertion failed, the user supplied this package/checker option on the
327
204
  // command line. If the supplied value is invalid, we'll restore the option
328
204
  // to it's default value, and if we're in non-compatibility mode, we'll also
329
204
  // emit an error.
330
204
331
204
  StringRef SuppliedValue = It.first->getValue();
332
204
333
204
  if (Option.OptionType == "bool") {
334
135
    if (SuppliedValue != "true" && 
SuppliedValue != "false"69
) {
335
4
      if (AnOpts.ShouldEmitErrorsOnInvalidConfigValue) {
336
2
        Diags.Report(diag::err_analyzer_checker_option_invalid_input)
337
2
            << FullOption << "a boolean value";
338
2
      }
339
4
340
4
      It.first->setValue(std::string(Option.DefaultValStr));
341
4
    }
342
135
    return;
343
135
  }
344
69
345
69
  if (Option.OptionType == "int") {
346
42
    int Tmp;
347
42
    bool HasFailed = SuppliedValue.getAsInteger(0, Tmp);
348
42
    if (HasFailed) {
349
3
      if (AnOpts.ShouldEmitErrorsOnInvalidConfigValue) {
350
1
        Diags.Report(diag::err_analyzer_checker_option_invalid_input)
351
1
            << FullOption << "an integer value";
352
1
      }
353
3
354
3
      It.first->setValue(std::string(Option.DefaultValStr));
355
3
    }
356
42
    return;
357
42
  }
358
69
}
359
360
template <class T>
361
static void
362
insertOptionToCollection(StringRef FullName, T &Collection,
363
                         const CheckerRegistry::CmdLineOption &Option,
364
51.9k
                         AnalyzerOptions &AnOpts, DiagnosticsEngine &Diags) {
365
51.9k
  auto It = binaryFind(Collection, FullName);
366
51.9k
  assert(It != Collection.end() &&
367
51.9k
         "Failed to find the checker while attempting to add a command line "
368
51.9k
         "option to it!");
369
51.9k
370
51.9k
  insertAndValidate(FullName, Option, AnOpts, Diags);
371
51.9k
372
51.9k
  It->CmdLineOptions.emplace_back(Option);
373
51.9k
}
CheckerRegistry.cpp:void insertOptionToCollection<std::__1::vector<clang::ento::CheckerRegistry::CheckerInfo, std::__1::allocator<clang::ento::CheckerRegistry::CheckerInfo> > >(llvm::StringRef, std::__1::vector<clang::ento::CheckerRegistry::CheckerInfo, std::__1::allocator<clang::ento::CheckerRegistry::CheckerInfo> >&, clang::ento::CheckerRegistry::CmdLineOption const&, clang::AnalyzerOptions&, clang::DiagnosticsEngine&)
Line
Count
Source
364
50.6k
                         AnalyzerOptions &AnOpts, DiagnosticsEngine &Diags) {
365
50.6k
  auto It = binaryFind(Collection, FullName);
366
50.6k
  assert(It != Collection.end() &&
367
50.6k
         "Failed to find the checker while attempting to add a command line "
368
50.6k
         "option to it!");
369
50.6k
370
50.6k
  insertAndValidate(FullName, Option, AnOpts, Diags);
371
50.6k
372
50.6k
  It->CmdLineOptions.emplace_back(Option);
373
50.6k
}
CheckerRegistry.cpp:void insertOptionToCollection<llvm::SmallVector<clang::ento::CheckerRegistry::PackageInfo, 0u> >(llvm::StringRef, llvm::SmallVector<clang::ento::CheckerRegistry::PackageInfo, 0u>&, clang::ento::CheckerRegistry::CmdLineOption const&, clang::AnalyzerOptions&, clang::DiagnosticsEngine&)
Line
Count
Source
364
1.26k
                         AnalyzerOptions &AnOpts, DiagnosticsEngine &Diags) {
365
1.26k
  auto It = binaryFind(Collection, FullName);
366
1.26k
  assert(It != Collection.end() &&
367
1.26k
         "Failed to find the checker while attempting to add a command line "
368
1.26k
         "option to it!");
369
1.26k
370
1.26k
  insertAndValidate(FullName, Option, AnOpts, Diags);
371
1.26k
372
1.26k
  It->CmdLineOptions.emplace_back(Option);
373
1.26k
}
374
375
1.26k
void CheckerRegistry::resolveCheckerAndPackageOptions() {
376
1.26k
  for (const std::pair<StringRef, CmdLineOption> &CheckerOptEntry :
377
50.6k
       CheckerOptions) {
378
50.6k
    insertOptionToCollection(CheckerOptEntry.first, Checkers,
379
50.6k
                             CheckerOptEntry.second, AnOpts, Diags);
380
50.6k
  }
381
1.26k
  CheckerOptions.clear();
382
1.26k
383
1.26k
  for (const std::pair<StringRef, CmdLineOption> &PackageOptEntry :
384
1.26k
       PackageOptions) {
385
1.26k
    insertOptionToCollection(PackageOptEntry.first, Packages,
386
1.26k
                             PackageOptEntry.second, AnOpts, Diags);
387
1.26k
  }
388
1.26k
  PackageOptions.clear();
389
1.26k
}
390
391
55.7k
void CheckerRegistry::addPackage(StringRef FullName) {
392
55.7k
  Packages.emplace_back(PackageInfo(FullName));
393
55.7k
}
394
395
void CheckerRegistry::addPackageOption(StringRef OptionType,
396
                                       StringRef PackageFullName,
397
                                       StringRef OptionName,
398
                                       StringRef DefaultValStr,
399
                                       StringRef Description,
400
                                       StringRef DevelopmentStatus,
401
1.26k
                                       bool IsHidden) {
402
1.26k
  PackageOptions.emplace_back(
403
1.26k
      PackageFullName, CmdLineOption{OptionType, OptionName, DefaultValStr,
404
1.26k
                                     Description, DevelopmentStatus, IsHidden});
405
1.26k
}
406
407
void CheckerRegistry::addChecker(InitializationFunction Rfn,
408
                                 ShouldRegisterFunction Sfn, StringRef Name,
409
                                 StringRef Desc, StringRef DocsUri,
410
222k
                                 bool IsHidden) {
411
222k
  Checkers.emplace_back(Rfn, Sfn, Name, Desc, DocsUri, IsHidden);
412
222k
413
222k
  // Record the presence of the checker in its packages.
414
222k
  StringRef PackageName, LeafName;
415
222k
  std::tie(PackageName, LeafName) = Name.rsplit(PackageSeparator);
416
605k
  while (!LeafName.empty()) {
417
382k
    PackageSizes[PackageName] += 1;
418
382k
    std::tie(PackageName, LeafName) = PackageName.rsplit(PackageSeparator);
419
382k
  }
420
222k
}
421
422
void CheckerRegistry::addCheckerOption(StringRef OptionType,
423
                                       StringRef CheckerFullName,
424
                                       StringRef OptionName,
425
                                       StringRef DefaultValStr,
426
                                       StringRef Description,
427
                                       StringRef DevelopmentStatus,
428
50.6k
                                       bool IsHidden) {
429
50.6k
  CheckerOptions.emplace_back(
430
50.6k
      CheckerFullName, CmdLineOption{OptionType, OptionName, DefaultValStr,
431
50.6k
                                     Description, DevelopmentStatus, IsHidden});
432
50.6k
}
433
434
1.24k
void CheckerRegistry::initializeManager(CheckerManager &CheckerMgr) const {
435
1.24k
  // Collect checkers enabled by the options.
436
1.24k
  CheckerInfoSet enabledCheckers = getEnabledCheckers();
437
1.24k
438
1.24k
  // Initialize the CheckerManager with all enabled checkers.
439
22.0k
  for (const auto *Checker : enabledCheckers) {
440
22.0k
    CheckerMgr.setCurrentCheckerName(CheckerNameRef(Checker->FullName));
441
22.0k
    Checker->Initialize(CheckerMgr);
442
22.0k
  }
443
1.24k
}
444
445
static void
446
isOptionContainedIn(const CheckerRegistry::CmdLineOptionList &OptionList,
447
                    StringRef SuppliedChecker, StringRef SuppliedOption,
448
51.1k
                    const AnalyzerOptions &AnOpts, DiagnosticsEngine &Diags) {
449
51.1k
450
51.1k
  if (!AnOpts.ShouldEmitErrorsOnInvalidConfigValue)
451
657
    return;
452
50.4k
453
50.4k
  using CmdLineOption = CheckerRegistry::CmdLineOption;
454
50.4k
455
238k
  auto SameOptName = [SuppliedOption](const CmdLineOption &Opt) {
456
238k
    return Opt.OptionName == SuppliedOption;
457
238k
  };
458
50.4k
459
50.4k
  auto OptionIt = llvm::find_if(OptionList, SameOptName);
460
50.4k
461
50.4k
  if (OptionIt == OptionList.end()) {
462
1
    Diags.Report(diag::err_analyzer_checker_option_unknown)
463
1
        << SuppliedChecker << SuppliedOption;
464
1
    return;
465
1
  }
466
50.4k
}
467
468
1.24k
void CheckerRegistry::validateCheckerOptions() const {
469
120k
  for (const auto &Config : AnOpts.Config) {
470
120k
471
120k
    StringRef SuppliedCheckerOrPackage;
472
120k
    StringRef SuppliedOption;
473
120k
    std::tie(SuppliedCheckerOrPackage, SuppliedOption) =
474
120k
        Config.getKey().split(':');
475
120k
476
120k
    if (SuppliedOption.empty())
477
69.8k
      continue;
478
51.1k
479
51.1k
    // AnalyzerOptions' config table contains the user input, so an entry could
480
51.1k
    // look like this:
481
51.1k
    //
482
51.1k
    //   cor:NoFalsePositives=true
483
51.1k
    //
484
51.1k
    // Since lower_bound would look for the first element *not less* than "cor",
485
51.1k
    // it would return with an iterator to the first checker in the core, so we
486
51.1k
    // we really have to use find here, which uses operator==.
487
51.1k
    auto CheckerIt =
488
51.1k
        llvm::find(Checkers, CheckerInfo(SuppliedCheckerOrPackage));
489
51.1k
    if (CheckerIt != Checkers.end()) {
490
49.8k
      isOptionContainedIn(CheckerIt->CmdLineOptions, SuppliedCheckerOrPackage,
491
49.8k
                          SuppliedOption, AnOpts, Diags);
492
49.8k
      continue;
493
49.8k
    }
494
1.25k
495
1.25k
    auto PackageIt =
496
1.25k
        llvm::find(Packages, PackageInfo(SuppliedCheckerOrPackage));
497
1.25k
    if (PackageIt != Packages.end()) {
498
1.24k
      isOptionContainedIn(PackageIt->CmdLineOptions, SuppliedCheckerOrPackage,
499
1.24k
                          SuppliedOption, AnOpts, Diags);
500
1.24k
      continue;
501
1.24k
    }
502
8
503
8
    Diags.Report(diag::err_unknown_analyzer_checker_or_package)
504
8
        << SuppliedCheckerOrPackage;
505
8
  }
506
1.24k
}
507
508
void CheckerRegistry::printCheckerWithDescList(raw_ostream &Out,
509
9
                                               size_t MaxNameChars) const {
510
9
  // FIXME: Print available packages.
511
9
512
9
  Out << "CHECKERS:\n";
513
9
514
9
  // Find the maximum option length.
515
9
  size_t OptionFieldWidth = 0;
516
1.58k
  for (const auto &Checker : Checkers) {
517
1.58k
    // Limit the amount of padding we are willing to give up for alignment.
518
1.58k
    //   Package.Name     Description  [Hidden]
519
1.58k
    size_t NameLength = Checker.FullName.size();
520
1.58k
    if (NameLength <= MaxNameChars)
521
1.19k
      OptionFieldWidth = std::max(OptionFieldWidth, NameLength);
522
1.58k
  }
523
9
524
9
  const size_t InitialPad = 2;
525
9
526
9
  auto Print = [=](llvm::raw_ostream &Out, const CheckerInfo &Checker,
527
880
                   StringRef Description) {
528
880
    AnalyzerOptions::printFormattedEntry(Out, {Checker.FullName, Description},
529
880
                                         InitialPad, OptionFieldWidth);
530
880
    Out << '\n';
531
880
  };
532
9
533
1.58k
  for (const auto &Checker : Checkers) {
534
1.58k
    // The order of this if branches is significant, we wouldn't like to display
535
1.58k
    // developer checkers even in the alpha output. For example,
536
1.58k
    // alpha.cplusplus.IteratorModeling is a modeling checker, hence it's hidden
537
1.58k
    // by default, and users (even when the user is a developer of an alpha
538
1.58k
    // checker) shouldn't normally tinker with whether they should be enabled.
539
1.58k
540
1.58k
    if (Checker.IsHidden) {
541
387
      if (AnOpts.ShowCheckerHelpDeveloper)
542
172
        Print(Out, Checker, Checker.Desc);
543
387
      continue;
544
387
    }
545
1.19k
546
1.19k
    if (Checker.FullName.startswith("alpha")) {
547
405
      if (AnOpts.ShowCheckerHelpAlpha)
548
180
        Print(Out, Checker,
549
180
              ("(Enable only for development!) " + Checker.Desc).str());
550
405
      continue;
551
405
    }
552
792
553
792
    if (AnOpts.ShowCheckerHelp)
554
528
        Print(Out, Checker, Checker.Desc);
555
792
  }
556
9
}
557
558
3
void CheckerRegistry::printEnabledCheckerList(raw_ostream &Out) const {
559
3
  // Collect checkers enabled by the options.
560
3
  CheckerInfoSet EnabledCheckers = getEnabledCheckers();
561
3
562
3
  for (const auto *i : EnabledCheckers)
563
43
    Out << i->FullName << '\n';
564
3
}
565
566
7
void CheckerRegistry::printCheckerOptionList(raw_ostream &Out) const {
567
7
  Out << "OVERVIEW: Clang Static Analyzer Checker and Package Option List\n\n";
568
7
  Out << "USAGE: -analyzer-config <OPTION1=VALUE,OPTION2=VALUE,...>\n\n";
569
7
  Out << "       -analyzer-config OPTION1=VALUE, -analyzer-config "
570
7
         "OPTION2=VALUE, ...\n\n";
571
7
  Out << "OPTIONS:\n\n";
572
7
573
7
  std::multimap<StringRef, const CmdLineOption &> OptionMap;
574
7
575
1.23k
  for (const CheckerInfo &Checker : Checkers) {
576
1.23k
    for (const CmdLineOption &Option : Checker.CmdLineOptions) {
577
280
      OptionMap.insert({Checker.FullName, Option});
578
280
    }
579
1.23k
  }
580
7
581
308
  for (const PackageInfo &Package : Packages) {
582
308
    for (const CmdLineOption &Option : Package.CmdLineOptions) {
583
7
      OptionMap.insert({Package.FullName, Option});
584
7
    }
585
308
  }
586
7
587
164
  auto Print = [] (llvm::raw_ostream &Out, StringRef FullOption, StringRef Desc) {
588
164
    AnalyzerOptions::printFormattedEntry(Out, {FullOption, Desc},
589
164
                                         /*InitialPad*/ 2,
590
164
                                         /*EntryWidth*/ 50,
591
164
                                         /*MinLineWidth*/ 90);
592
164
    Out << "\n\n";
593
164
  };
594
7
  for (const std::pair<const StringRef, const CmdLineOption &> &Entry :
595
287
       OptionMap) {
596
287
    const CmdLineOption &Option = Entry.second;
597
287
    std::string FullOption = (Entry.first + ":" + Option.OptionName).str();
598
287
599
287
    std::string Desc =
600
287
        ("(" + Option.OptionType + ") " + Option.Description + " (default: " +
601
287
         (Option.DefaultValStr.empty() ? 
"\"\""7
:
Option.DefaultValStr280
) + ")")
602
287
            .str();
603
287
604
287
    // The list of these if branches is significant, we wouldn't like to
605
287
    // display hidden alpha checker options for
606
287
    // -analyzer-checker-option-help-alpha.
607
287
608
287
    if (Option.IsHidden) {
609
140
      if (AnOpts.ShowCheckerOptionDeveloperList)
610
80
        Print(Out, FullOption, Desc);
611
140
      continue;
612
140
    }
613
147
614
147
    if (Option.DevelopmentStatus == "alpha" ||
615
147
        
Entry.first.startswith("alpha")98
) {
616
91
      if (AnOpts.ShowCheckerOptionAlphaList)
617
52
        Print(Out, FullOption,
618
52
              llvm::Twine("(Enable only for development!) " + Desc).str());
619
91
      continue;
620
91
    }
621
56
622
56
    if (AnOpts.ShowCheckerOptionList)
623
32
      Print(Out, FullOption, Desc);
624
56
  }
625
7
}