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

23using namespace clang;

24using namespace ento;

26using llvm::sys::DynamicLibrary;

27

28

29

30

31

33

34 if (!VersionString)

35 return false;

36

37

38

40}

41

43

44

45

46

47

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

53

54

55#define GET_CHECKERS

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

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

58 DOC_URI, IS_HIDDEN);

59

60#define GET_PACKAGES

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

62

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

64#undef CHECKER

65#undef GET_CHECKERS

66#undef PACKAGE

67#undef GET_PACKAGES

68

69

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

71

72 std::string ErrorMsg;

73 DynamicLibrary Lib =

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

75 if (!Lib.isValid()) {

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

77 continue;

78 }

79

80

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

82 Lib.getAddressOfSymbol("clang_analyzerAPIVersionString"));

83

85 Diags.Report(diag::warn_incompatible_analyzer_plugin_api)

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

87 Diags.Report(diag::note_incompatible_analyzer_plugin_api)

89 continue;

90 }

91

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

93

94 RegisterPluginCheckerFn RegisterPluginCheckers =

95 reinterpret_cast<RegisterPluginCheckerFn>(

96 Lib.getAddressOfSymbol("clang_registerCheckers"));

97 if (RegisterPluginCheckers)

98 RegisterPluginCheckers(*this);

99 }

100

101

102

103

104

105 for (const auto &Fn : CheckerRegistrationFns)

106 Fn(*this);

107

108

109

110

111

114

115#define GET_CHECKER_DEPENDENCIES

116

117#define CHECKER_DEPENDENCY(FULLNAME, DEPENDENCY) \

118 addDependency(FULLNAME, DEPENDENCY);

119

120#define GET_CHECKER_WEAK_DEPENDENCIES

121

122#define CHECKER_WEAK_DEPENDENCY(FULLNAME, DEPENDENCY) \

123 addWeakDependency(FULLNAME, DEPENDENCY);

124

125#define GET_CHECKER_OPTIONS

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

127 DEVELOPMENT_STATUS, IS_HIDDEN) \

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

129 DEVELOPMENT_STATUS, IS_HIDDEN);

130

131#define GET_PACKAGE_OPTIONS

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

133 DEVELOPMENT_STATUS, IS_HIDDEN) \

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

135 DEVELOPMENT_STATUS, IS_HIDDEN);

136

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

138#undef CHECKER_DEPENDENCY

139#undef GET_CHECKER_DEPENDENCIES

140#undef CHECKER_WEAK_DEPENDENCY

141#undef GET_CHECKER_WEAK_DEPENDENCIES

142#undef CHECKER_OPTION

143#undef GET_CHECKER_OPTIONS

144#undef PACKAGE_OPTION

145#undef GET_PACKAGE_OPTIONS

146

147 resolveDependencies();

148 resolveDependencies();

149

150#ifndef NDEBUG

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

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

153

154

155

156 assert(WeakDepPair != DepPair &&

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

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

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

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

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

162 }

163 }

164#endif

165

166 resolveCheckerAndPackageOptions();

167

168

169

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

172 Data.getMutableCheckersForCmdLineArg(Opt.first);

173

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

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

176 Diags.Report(diag::note_suggest_disabling_all_checkers);

177 }

178

179 for (CheckerInfo &checker : CheckerForCmdLineArg) {

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

181 : StateFromCmdLine::State_Disabled;

182 }

183 }

185}

186

187

188

189

190

191template

195 IsEnabledFn IsEnabled);

196

197

198template

202

204

205

206

207

210 return Checker->isDisabled(Mgr);

211 };

214 continue;

215

218 IsEnabledFromCmdLine)) {

219

220

221 continue;

222 }

223

224 Tmp.insert_range(Deps);

225

226

228 }

229

230

231

232

234 return Tmp.contains(Checker);

235 };

238 continue;

239

241

243

245 IsEnabledFromCmdLine)) {

246

247

248 continue;

249 }

250

251

252 Data.EnabledCheckers.set_union(Deps);

253 Data.EnabledCheckers.insert(&Checker);

254 }

255}

256

257template

261 IsEnabledFn IsEnabled) {

262

263 for (const CheckerInfo *Dependency : Deps) {

264 if (!IsEnabled(Dependency))

265 return false;

266

267

269 IsEnabled))

270 return false;

271 Ret.insert(Dependency);

272 }

273

274 return true;

275}

276

277template

281 IsEnabledFn IsEnabled) {

282

283 for (const CheckerInfo *Dependency : WeakDeps) {

284

285

287

288 if (IsEnabled(Dependency) &&

290 IsEnabled))

291 Ret.insert(Dependency);

292 }

293}

294

295template void CheckerRegistry::resolveDependencies() {

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

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

298

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

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

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

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

303 "dependencies!");

304

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

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

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

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

309

310

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

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

313 DependencyIt->IsHidden) &&

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

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

316

317 if (IsWeak)

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

319 else

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

321 }

322}

323

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

326}

327

329 StringRef Dependency) {

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

331}

332

333

334

335

336

337

338

342

343 std::string FullOption = (FullName + ":" + Option.OptionName).str();

344

345 auto It =

347

348

349

350 if (It.second)

351 return;

352

353

354

355

356

357

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

359

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

363 Diags.Report(diag::err_analyzer_checker_option_invalid_input)

364 << FullOption << "a boolean value";

365 }

366

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

368 }

369 return;

370 }

371

373 int Tmp;

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

375 if (HasFailed) {

377 Diags.Report(diag::err_analyzer_checker_option_invalid_input)

378 << FullOption << "an integer value";

379 }

380

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

382 }

383 return;

384 }

385}

386

387template

392 auto It = binaryFind(Collection, FullName);

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

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

395 "option to it!");

396

398

399 It->CmdLineOptions.emplace_back(Option);

400}

401

402void CheckerRegistry::resolveCheckerAndPackageOptions() {

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

404 Data.CheckerOptions) {

406 CheckerOptEntry.second, AnOpts, Diags);

407 }

408

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

410 Data.PackageOptions) {

412 PackageOptEntry.second, AnOpts, Diags);

413 }

414}

415

417 Data.Packages.emplace_back(PackageInfo(FullName));

418}

419

421 StringRef PackageFullName,

422 StringRef OptionName,

423 StringRef DefaultValStr,

424 StringRef Description,

425 StringRef DevelopmentStatus,

426 bool IsHidden) {

427 Data.PackageOptions.emplace_back(

428 PackageFullName, CmdLineOption{OptionType, OptionName, DefaultValStr,

429 Description, DevelopmentStatus, IsHidden});

430}

431

434 StringRef Desc, StringRef DocsUri,

435 bool IsHidden) {

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

437

438

439 StringRef PackageName, LeafName;

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

441 while (!LeafName.empty()) {

442 Data.PackageSizes[PackageName] += 1;

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

444 }

445}

446

448 StringRef CheckerFullName,

449 StringRef OptionName,

450 StringRef DefaultValStr,

451 StringRef Description,

452 StringRef DevelopmentStatus,

453 bool IsHidden) {

454 Data.CheckerOptions.emplace_back(

455 CheckerFullName, CmdLineOption{OptionType, OptionName, DefaultValStr,

456 Description, DevelopmentStatus, IsHidden});

457}

458

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

460

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

463 Checker->Initialize(CheckerMgr);

464 }

465}

466

468 StringRef SuppliedChecker,

469 StringRef SuppliedOption,

472

474 return;

475

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

477 return Opt.OptionName == SuppliedOption;

478 };

479

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

481 Diags.Report(diag::err_analyzer_checker_option_unknown)

482 << SuppliedChecker << SuppliedOption;

483 return;

484 }

485}

486

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

489

490 StringRef SuppliedCheckerOrPackage;

491 StringRef SuppliedOption;

492 std::tie(SuppliedCheckerOrPackage, SuppliedOption) =

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

494

495 if (SuppliedOption.empty())

496 continue;

497

498

499

500

501

502

503

504

505

506 auto CheckerIt =

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

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

510 SuppliedOption, AnOpts, Diags);

511 continue;

512 }

513

514 const auto *PackageIt =

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

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

518 SuppliedOption, AnOpts, Diags);

519 continue;

520 }

521

522 Diags.Report(diag::err_unknown_analyzer_checker_or_package)

523 << SuppliedCheckerOrPackage;

524 }

525}

Defines the Diagnostic-related interfaces.

static constexpr char PackageSeparator

static bool isCompatibleAPIVersion(const char *VersionString)

Definition CheckerRegistry.cpp:32

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

Collects weak dependencies in enabledData.Checkers.

Definition CheckerRegistry.cpp:278

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

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

Definition CheckerRegistry.cpp:339

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

Definition CheckerRegistry.cpp:467

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

Definition CheckerRegistry.cpp:258

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

Definition CheckerRegistry.cpp:388

#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.

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 ...

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

Registers an option to a given checker.

Definition CheckerRegistry.cpp:447

void addWeakDependency(StringRef FullName, StringRef Dependency)

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

Definition CheckerRegistry.cpp:328

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

Registers an option to a given package.

Definition CheckerRegistry.cpp:420

void initializeRegistry(const CheckerManager &Mgr)

Collects all enabled checkers in the field EnabledCheckers.

Definition CheckerRegistry.cpp:203

void addChecker(RegisterCheckerFn Fn, ShouldRegisterFunction Sfn, StringRef FullName, StringRef Desc, StringRef DocsUri="NoDocsUri", bool IsHidden=false)

Adds a checker to the registry.

Definition CheckerRegistry.cpp:432

void addPackage(StringRef FullName)

Adds a package to the registry.

Definition CheckerRegistry.cpp:416

void validateCheckerOptions() const

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

Definition CheckerRegistry.cpp:487

void addDependency(StringRef FullName, StringRef Dependency)

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

Definition CheckerRegistry.cpp:324

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

Definition CheckerRegistry.cpp:48

Simple checker classes that implement one frontend (i.e.

FullNameLT< CheckerInfo > CheckerNameLT

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

FullNameLT< PackageInfo > PackageNameLT

void(*)(CheckerManager &) RegisterCheckerFn

Initialization functions perform any necessary setup for a checker.

llvm::iterator_range< CheckerInfoList::iterator > CheckerInfoListRange

llvm::SetVector< const CheckerInfo * > CheckerInfoSet

llvm::SmallVector< CmdLineOption, 0 > CmdLineOptionList

llvm::SmallVector< const CheckerInfo *, 0 > ConstCheckerInfoList

bool(*)(const CheckerManager &) ShouldRegisterFunction

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

const FunctionProtoType * T

int const char * function

Specifies a command line option.