@@ -142,34 +142,19 @@ void CFErrorFunctionChecker::checkASTDecl(const FunctionDecl *D,
142
142
// ===----------------------------------------------------------------------===//
143
143
144
144
namespace {
145
+ class NSOrCFErrorDerefChecker
146
+ : public CheckerFamily<check::Location,
147
+ check::Event<ImplicitNullDerefEvent>> {
148
+ mutable IdentifierInfo *NSErrorII = nullptr ;
149
+ mutable IdentifierInfo *CFErrorII = nullptr ;
145
150
146
- class NSErrorDerefBug : public BugType {
147
- public:
148
- NSErrorDerefBug (const CheckerNameRef Checker)
149
- : BugType(Checker, " NSError** null dereference" ,
150
- " Coding conventions (Apple)" ) {}
151
- };
152
-
153
- class CFErrorDerefBug : public BugType {
154
151
public:
155
- CFErrorDerefBug (const CheckerNameRef Checker)
156
- : BugType(Checker, " CFErrorRef* null dereference" ,
157
- " Coding conventions (Apple)" ) {}
158
- };
159
-
160
- }
152
+ CheckerFrontendWithBugType NSError{" NSError** null dereference" ,
153
+ " Coding conventions (Apple)" };
154
+ CheckerFrontendWithBugType CFError{" CFErrorRef* null dereference" ,
155
+ " Coding conventions (Apple)" };
161
156
162
- namespace {
163
- class NSOrCFErrorDerefChecker
164
- : public Checker< check::Location,
165
- check::Event<ImplicitNullDerefEvent> > {
166
- mutable IdentifierInfo *NSErrorII, *CFErrorII;
167
- mutable std::unique_ptr<NSErrorDerefBug> NSBT;
168
- mutable std::unique_ptr<CFErrorDerefBug> CFBT;
169
- public:
170
- bool ShouldCheckNSError = false , ShouldCheckCFError = false ;
171
- CheckerNameRef NSErrorName, CFErrorName;
172
- NSOrCFErrorDerefChecker () : NSErrorII(nullptr ), CFErrorII(nullptr ) {}
157
+ StringRef getDebugTag () const override { return " NSOrCFErrorDerefChecker" ; }
173
158
174
159
void checkLocation (SVal loc, bool isLoad, const Stmt *S,
175
160
CheckerContext &C) const ;
@@ -236,12 +221,12 @@ void NSOrCFErrorDerefChecker::checkLocation(SVal loc, bool isLoad,
236
221
if (!CFErrorII)
237
222
CFErrorII = &Ctx.Idents .get (" CFErrorRef" );
238
223
239
- if (ShouldCheckNSError && IsNSError (parmT, NSErrorII)) {
224
+ if (NSError. isEnabled () && IsNSError (parmT, NSErrorII)) {
240
225
setFlag<NSErrorOut>(state, state->getSVal (loc.castAs <Loc>()), C);
241
226
return ;
242
227
}
243
228
244
- if (ShouldCheckCFError && IsCFError (parmT, CFErrorII)) {
229
+ if (CFError. isEnabled () && IsCFError (parmT, CFErrorII)) {
245
230
setFlag<CFErrorOut>(state, state->getSVal (loc.castAs <Loc>()), C);
246
231
return ;
247
232
}
@@ -274,19 +259,9 @@ void NSOrCFErrorDerefChecker::checkEvent(ImplicitNullDerefEvent event) const {
274
259
275
260
os << " may be null" ;
276
261
277
- BugType *bug = nullptr ;
278
- if (isNSError) {
279
- if (!NSBT)
280
- NSBT.reset (new NSErrorDerefBug(NSErrorName));
281
- bug = NSBT.get ();
282
- }
283
- else {
284
- if (!CFBT)
285
- CFBT.reset (new CFErrorDerefBug (CFErrorName));
286
- bug = CFBT.get ();
287
- }
262
+ const BugType &BT = isNSError ? NSError : CFError;
288
263
BR.emitReport (
289
- std::make_unique<PathSensitiveBugReport>(*bug , os.str (), event.SinkNode ));
264
+ std::make_unique<PathSensitiveBugReport>(BT , os.str (), event.SinkNode ));
290
265
}
291
266
292
267
static bool IsNSError (QualType T, IdentifierInfo *II) {
@@ -320,32 +295,21 @@ static bool IsCFError(QualType T, IdentifierInfo *II) {
320
295
return TT->getDecl ()->getIdentifier () == II;
321
296
}
322
297
323
- void ento::registerNSOrCFErrorDerefChecker (CheckerManager &mgr) {
324
- mgr.registerChecker <NSOrCFErrorDerefChecker>();
325
- }
326
-
327
- bool ento::shouldRegisterNSOrCFErrorDerefChecker (const CheckerManager &mgr) {
328
- return true ;
329
- }
330
-
331
- void ento::registerNSErrorChecker (CheckerManager &mgr) {
332
- mgr.registerChecker <NSErrorMethodChecker>();
333
- NSOrCFErrorDerefChecker *checker = mgr.getChecker <NSOrCFErrorDerefChecker>();
334
- checker->ShouldCheckNSError = true ;
335
- checker->NSErrorName = mgr.getCurrentCheckerName ();
336
- }
337
-
338
- bool ento::shouldRegisterNSErrorChecker (const CheckerManager &mgr) {
339
- return true ;
340
- }
341
-
342
- void ento::registerCFErrorChecker (CheckerManager &mgr) {
343
- mgr.registerChecker <CFErrorFunctionChecker>();
344
- NSOrCFErrorDerefChecker *checker = mgr.getChecker <NSOrCFErrorDerefChecker>();
345
- checker->ShouldCheckCFError = true ;
346
- checker->CFErrorName = mgr.getCurrentCheckerName ();
347
- }
298
+ // This source file implements two user-facing checkers ("osx.cocoa.NSError"
299
+ // and "osx.coreFoundation.CFError") which are both implemented as the
300
+ // combination of two `CheckerFrontend`s that are registered under the same
301
+ // name (but otherwise act independently). Among these 2+2 `CheckerFrontend`s
302
+ // two are coming from the checker family `NSOrCFErrorDerefChecker` while the
303
+ // other two (the `ADDITIONAL_PART`s) are small standalone checkers.
304
+ #define REGISTER_CHECKER (NAME, ADDITIONAL_PART ) \
305
+ void ento::register ##NAME##Checker(CheckerManager &Mgr) { \
306
+ Mgr.getChecker <NSOrCFErrorDerefChecker>()->NAME .enable (Mgr); \
307
+ Mgr.registerChecker <ADDITIONAL_PART>(); \
308
+ } \
309
+ \
310
+ bool ento::shouldRegister##NAME##Checker(const CheckerManager &) { \
311
+ return true ; \
312
+ }
348
313
349
- bool ento::shouldRegisterCFErrorChecker (const CheckerManager &mgr) {
350
- return true ;
351
- }
314
+ REGISTER_CHECKER (NSError, NSErrorMethodChecker)
315
+ REGISTER_CHECKER(CFError, CFErrorFunctionChecker)
0 commit comments