clang: lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

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

24

25using namespace clang;

26using namespace ento;

27using namespace checker_registry;

28using llvm::sys::DynamicLibrary;

29

30

31

32

33

35

36 if (!VersionString)

37 return false;

38

39

40

42}

43

45

46

47

48

49

54 : Data(Data), Diags(Diags), AnOpts(AnOpts) {

55

56

57#define GET_CHECKERS

58#define CHECKER(FULLNAME, CLASS, HELPTEXT, DOC_URI, IS_HIDDEN) \

59 addChecker(register##CLASS, shouldRegister##CLASS, FULLNAME, HELPTEXT, \

60 DOC_URI, IS_HIDDEN);

61

62#define GET_PACKAGES

63#define PACKAGE(FULLNAME) addPackage(FULLNAME);

64

65#include "clang/StaticAnalyzer/Checkers/Checkers.inc"

66#undef CHECKER

67#undef GET_CHECKERS

68#undef PACKAGE

69#undef GET_PACKAGES

70

71

72 for (const std::string &Plugin : Plugins) {

73

74 std::string ErrorMsg;

75 DynamicLibrary Lib =

76 DynamicLibrary::getPermanentLibrary(Plugin.c_str(), &ErrorMsg);

77 if (!Lib.isValid()) {

78 Diags.Report(diag::err_fe_unable_to_load_plugin) << Plugin << ErrorMsg;

79 continue;

80 }

81

82

83 const char *PluginAPIVersion = static_cast<const char *>(

84 Lib.getAddressOfSymbol("clang_analyzerAPIVersionString"));

85

87 Diags.Report(diag::warn_incompatible_analyzer_plugin_api)

88 << llvm::sys::path::filename(Plugin);

89 Diags.Report(diag::note_incompatible_analyzer_plugin_api)

91 continue;

92 }

93

94 using RegisterPluginCheckerFn = void (*)(CheckerRegistry &);

95

96 RegisterPluginCheckerFn RegisterPluginCheckers =

97 reinterpret_cast<RegisterPluginCheckerFn>(

98 Lib.getAddressOfSymbol("clang_registerCheckers"));

99 if (RegisterPluginCheckers)

100 RegisterPluginCheckers(*this);

101 }

102

103

104

105

106

107 for (const auto &Fn : CheckerRegistrationFns)

108 Fn(*this);

109

110

111

112

113

116

117#define GET_CHECKER_DEPENDENCIES

118

119#define CHECKER_DEPENDENCY(FULLNAME, DEPENDENCY) \

120 addDependency(FULLNAME, DEPENDENCY);

121

122#define GET_CHECKER_WEAK_DEPENDENCIES

123

124#define CHECKER_WEAK_DEPENDENCY(FULLNAME, DEPENDENCY) \

125 addWeakDependency(FULLNAME, DEPENDENCY);

126

127#define GET_CHECKER_OPTIONS

128#define CHECKER_OPTION(TYPE, FULLNAME, CMDFLAG, DESC, DEFAULT_VAL, \

129 DEVELOPMENT_STATUS, IS_HIDDEN) \

130 addCheckerOption(TYPE, FULLNAME, CMDFLAG, DEFAULT_VAL, DESC, \

131 DEVELOPMENT_STATUS, IS_HIDDEN);

132

133#define GET_PACKAGE_OPTIONS

134#define PACKAGE_OPTION(TYPE, FULLNAME, CMDFLAG, DESC, DEFAULT_VAL, \

135 DEVELOPMENT_STATUS, IS_HIDDEN) \

136 addPackageOption(TYPE, FULLNAME, CMDFLAG, DEFAULT_VAL, DESC, \

137 DEVELOPMENT_STATUS, IS_HIDDEN);

138

139#include "clang/StaticAnalyzer/Checkers/Checkers.inc"

140#undef CHECKER_DEPENDENCY

141#undef GET_CHECKER_DEPENDENCIES

142#undef CHECKER_WEAK_DEPENDENCY

143#undef GET_CHECKER_WEAK_DEPENDENCIES

144#undef CHECKER_OPTION

145#undef GET_CHECKER_OPTIONS

146#undef PACKAGE_OPTION

147#undef GET_PACKAGE_OPTIONS

148

149 resolveDependencies();

150 resolveDependencies();

151

152#ifndef NDEBUG

153 for (auto &DepPair : Data.Dependencies) {

154 for (auto &WeakDepPair : Data.WeakDependencies) {

155

156

157

158 assert(WeakDepPair != DepPair &&

159 "A checker cannot strong and weak depend on the same checker!");

160 assert(WeakDepPair.first != DepPair.second &&

161 "A strong dependency mustn't have weak dependencies!");

162 assert(WeakDepPair.second != DepPair.second &&

163 "A strong dependency mustn't be a weak dependency as well!");

164 }

165 }

166#endif

167

168 resolveCheckerAndPackageOptions();

169

170

171

172 for (const std::pair<std::string, bool> &Opt : AnOpts.CheckersAndPackages) {

174 Data.getMutableCheckersForCmdLineArg(Opt.first);

175

176 if (CheckerForCmdLineArg.begin() == CheckerForCmdLineArg.end()) {

177 Diags.Report(diag::err_unknown_analyzer_checker_or_package) << Opt.first;

178 Diags.Report(diag::note_suggest_disabling_all_checkers);

179 }

180

181 for (CheckerInfo &checker : CheckerForCmdLineArg) {

182 checker.State = Opt.second ? StateFromCmdLine::State_Enabled

183 : StateFromCmdLine::State_Disabled;

184 }

185 }

187}

188

189

190

191

192

193template

197 IsEnabledFn IsEnabled);

198

199

200template

204

206

207

208

209

212 return Checker->isDisabled(Mgr);

213 };

215 if (Checker.isEnabled(Mgr))

216 continue;

217

220 IsEnabledFromCmdLine)) {

221

222

223 continue;

224 }

225

226 Tmp.insert(Deps.begin(), Deps.end());

227

228

230 }

231

232

233

234

236 return Tmp.contains(Checker);

237 };

239 if (Checker.isEnabled(Mgr))

240 continue;

241

243

245

247 IsEnabledFromCmdLine)) {

248

249

250 continue;

251 }

252

253

254 Data.EnabledCheckers.set_union(Deps);

256 }

257}

258

259template

263 IsEnabledFn IsEnabled) {

264

265 for (const CheckerInfo *Dependency : Deps) {

266 if (!IsEnabled(Dependency))

267 return false;

268

269

271 IsEnabled))

272 return false;

273 Ret.insert(Dependency);

274 }

275

276 return true;

277}

278

279template

283 IsEnabledFn IsEnabled) {

284

285 for (const CheckerInfo *Dependency : WeakDeps) {

286

287

289

290 if (IsEnabled(Dependency) &&

292 IsEnabled))

293 Ret.insert(Dependency);

294 }

295}

296

297template void CheckerRegistry::resolveDependencies() {

298 for (const std::pair<StringRef, StringRef> &Entry :

299 (IsWeak ? Data.WeakDependencies : Data.Dependencies)) {

300

301 auto CheckerIt = binaryFind(Data.Checkers, Entry.first);

302 assert(CheckerIt != Data.Checkers.end() &&

303 CheckerIt->FullName == Entry.first &&

304 "Failed to find the checker while attempting to set up its "

305 "dependencies!");

306

307 auto DependencyIt = binaryFind(Data.Checkers, Entry.second);

308 assert(DependencyIt != Data.Checkers.end() &&

309 DependencyIt->FullName == Entry.second &&

310 "Failed to find the dependency of a checker!");

311

312

313 assert((DependencyIt->FullName.starts_with("test") ||

314 DependencyIt->FullName.starts_with("example") || IsWeak ||

315 DependencyIt->IsHidden) &&

316 "Strong dependencies are modeling checkers, and as such "

317 "non-user facing! Mark them hidden in Checkers.td!");

318

319 if (IsWeak)

320 CheckerIt->WeakDependencies.emplace_back(&*DependencyIt);

321 else

322 CheckerIt->Dependencies.emplace_back(&*DependencyIt);

323 }

324}

325

327 Data.Dependencies.emplace_back(FullName, Dependency);

328}

329

331 StringRef Dependency) {

332 Data.WeakDependencies.emplace_back(FullName, Dependency);

333}

334

335

336

337

338

339

340

344

346

347 auto It =

349

350

351

352 if (It.second)

353 return;

354

355

356

357

358

359

360 StringRef SuppliedValue = It.first->getValue();

361

363 if (SuppliedValue != "true" && SuppliedValue != "false") {

365 Diags.Report(diag::err_analyzer_checker_option_invalid_input)

366 << FullOption << "a boolean value";

367 }

368

369 It.first->setValue(std::string(Option.DefaultValStr));

370 }

371 return;

372 }

373

375 int Tmp;

376 bool HasFailed = SuppliedValue.getAsInteger(0, Tmp);

377 if (HasFailed) {

379 Diags.Report(diag::err_analyzer_checker_option_invalid_input)

380 << FullOption << "an integer value";

381 }

382

383 It.first->setValue(std::string(Option.DefaultValStr));

384 }

385 return;

386 }

387}

388

389template

395 assert(It != Collection.end() &&

396 "Failed to find the checker while attempting to add a command line "

397 "option to it!");

398

400

401 It->CmdLineOptions.emplace_back(Option);

402}

403

404void CheckerRegistry::resolveCheckerAndPackageOptions() {

405 for (const std::pair<StringRef, CmdLineOption> &CheckerOptEntry :

406 Data.CheckerOptions) {

408 CheckerOptEntry.second, AnOpts, Diags);

409 }

410

411 for (const std::pair<StringRef, CmdLineOption> &PackageOptEntry :

412 Data.PackageOptions) {

414 PackageOptEntry.second, AnOpts, Diags);

415 }

416}

417

420}

421

423 StringRef PackageFullName,

424 StringRef OptionName,

425 StringRef DefaultValStr,

426 StringRef Description,

427 StringRef DevelopmentStatus,

428 bool IsHidden) {

429 Data.PackageOptions.emplace_back(

430 PackageFullName, CmdLineOption{OptionType, OptionName, DefaultValStr,

431 Description, DevelopmentStatus, IsHidden});

432}

433

436 StringRef Desc, StringRef DocsUri,

437 bool IsHidden) {

438 Data.Checkers.emplace_back(Rfn, Sfn, Name, Desc, DocsUri, IsHidden);

439

440

441 StringRef PackageName, LeafName;

442 std::tie(PackageName, LeafName) = Name.rsplit(PackageSeparator);

443 while (!LeafName.empty()) {

444 Data.PackageSizes[PackageName] += 1;

445 std::tie(PackageName, LeafName) = PackageName.rsplit(PackageSeparator);

446 }

447}

448

450 StringRef CheckerFullName,

451 StringRef OptionName,

452 StringRef DefaultValStr,

453 StringRef Description,

454 StringRef DevelopmentStatus,

455 bool IsHidden) {

456 Data.CheckerOptions.emplace_back(

457 CheckerFullName, CmdLineOption{OptionType, OptionName, DefaultValStr,

458 Description, DevelopmentStatus, IsHidden});

459}

460

461void CheckerRegistry::initializeManager(CheckerManager &CheckerMgr) const {

462

463 for (const auto *Checker : Data.EnabledCheckers) {

465 Checker->Initialize(CheckerMgr);

466 }

467}

468

470 StringRef SuppliedChecker,

471 StringRef SuppliedOption,

474

476 return;

477

478 auto SameOptName = [SuppliedOption](const CmdLineOption &Opt) {

479 return Opt.OptionName == SuppliedOption;

480 };

481

482 if (llvm::none_of(OptionList, SameOptName)) {

483 Diags.Report(diag::err_analyzer_checker_option_unknown)

484 << SuppliedChecker << SuppliedOption;

485 return;

486 }

487}

488

490 for (const auto &Config : AnOpts.Config) {

491

492 StringRef SuppliedCheckerOrPackage;

493 StringRef SuppliedOption;

494 std::tie(SuppliedCheckerOrPackage, SuppliedOption) =

495 Config.getKey().split(':');

496

497 if (SuppliedOption.empty())

498 continue;

499

500

501

502

503

504

505

506

507

508 auto CheckerIt =

509 llvm::find(Data.Checkers, CheckerInfo(SuppliedCheckerOrPackage));

510 if (CheckerIt != Data.Checkers.end()) {

512 SuppliedOption, AnOpts, Diags);

513 continue;

514 }

515

516 const auto *PackageIt =

517 llvm::find(Data.Packages, PackageInfo(SuppliedCheckerOrPackage));

518 if (PackageIt != Data.Packages.end()) {

520 SuppliedOption, AnOpts, Diags);

521 continue;

522 }

523

524 Diags.Report(diag::err_unknown_analyzer_checker_or_package)

525 << SuppliedCheckerOrPackage;

526 }

527}

Defines the Diagnostic-related interfaces.

static constexpr char PackageSeparator

static bool isCompatibleAPIVersion(const char *VersionString)

static void collectWeakDependencies(const ConstCheckerInfoList &Deps, const CheckerManager &Mgr, CheckerInfoSet &Ret, IsEnabledFn IsEnabled)

Collects weak dependencies in enabledData.Checkers.

static constexpr char PackageSeparator

static void insertAndValidate(StringRef FullName, const CmdLineOption &Option, AnalyzerOptions &AnOpts, DiagnosticsEngine &Diags)

Insert the checker/package option to AnalyzerOptions' config table, and validate it,...

static void isOptionContainedIn(const CmdLineOptionList &OptionList, StringRef SuppliedChecker, StringRef SuppliedOption, const AnalyzerOptions &AnOpts, DiagnosticsEngine &Diags)

static bool collectStrongDependencies(const ConstCheckerInfoList &Deps, const CheckerManager &Mgr, CheckerInfoSet &Ret, IsEnabledFn IsEnabled)

static void insertOptionToCollection(StringRef FullName, T &Collection, const CmdLineOption &Option, AnalyzerOptions &AnOpts, DiagnosticsEngine &Diags)

#define CLANG_ANALYZER_API_VERSION_STRING

Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.

Stores options for the analyzer from the command line.

std::vector< std::pair< std::string, bool > > CheckersAndPackages

Pairs of checker/package name and enable/disable.

ConfigTable Config

A key-value table of use-specified configuration values.

unsigned ShouldEmitErrorsOnInvalidConfigValue

Concrete class used by the front-end to report problems and issues.

DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)

Issue the message to the client.

void setCurrentCheckerName(CheckerNameRef name)

This wrapper is used to ensure that only StringRefs originating from the CheckerRegistry are used as ...

Manages a set of available checkers for running a static analysis.

void addCheckerOption(StringRef OptionType, StringRef CheckerFullName, StringRef OptionName, StringRef DefaultValStr, StringRef Description, StringRef DevelopmentStatus, bool IsHidden=false)

Registers an option to a given checker.

void addWeakDependency(StringRef FullName, StringRef Dependency)

Makes the checker with the full name fullName weak depend on the checker called dependency.

void addPackageOption(StringRef OptionType, StringRef PackageFullName, StringRef OptionName, StringRef DefaultValStr, StringRef Description, StringRef DevelopmentStatus, bool IsHidden=false)

Registers an option to a given package.

void initializeRegistry(const CheckerManager &Mgr)

Collects all enabled checkers in the field EnabledCheckers.

void addChecker(RegisterCheckerFn Fn, ShouldRegisterFunction sfn, StringRef FullName, StringRef Desc, StringRef DocsUri, bool IsHidden)

Adds a checker to the registry.

void addPackage(StringRef FullName)

Adds a package to the registry.

void validateCheckerOptions() const

Check if every option corresponds to a specific checker or package.

void addDependency(StringRef FullName, StringRef Dependency)

Makes the checker with the full name fullName depend on the checker called dependency.

CheckerRegistry(CheckerRegistryData &Data, ArrayRef< std::string > Plugins, DiagnosticsEngine &Diags, AnalyzerOptions &AnOpts, ArrayRef< std::function< void(CheckerRegistry &)> > CheckerRegistrationFns={})

std::conditional_t< std::is_const< CheckerOrPackageInfoList >::value, typename CheckerOrPackageInfoList::const_iterator, typename CheckerOrPackageInfoList::iterator > binaryFind(CheckerOrPackageInfoList &Collection, StringRef FullName)

llvm::iterator_range< CheckerInfoList::iterator > CheckerInfoListRange

bool(*)(const CheckerManager &) ShouldRegisterFunction

void(*)(CheckerManager &) RegisterCheckerFn

Initialization functions perform any necessary setup for a checker.

llvm::SetVector< const CheckerInfo * > CheckerInfoSet

The JSON file list parser is used to communicate input to InstallAPI.

const FunctionProtoType * T

Specifies a command line option.