@@ -142,34 +142,19 @@ void CFErrorFunctionChecker::checkASTDecl(const FunctionDecl *D,
142142// ===----------------------------------------------------------------------===//
143143
144144namespace {
145+ class NSOrCFErrorDerefChecker
146+ : public CheckerFamily<check::Location,
147+ check::Event<ImplicitNullDerefEvent>> {
148+ mutable IdentifierInfo *NSErrorII = nullptr ;
149+ mutable IdentifierInfo *CFErrorII = nullptr ;
145150
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 {
154151public:
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)" };
161156
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" ; }
173158
174159 void checkLocation (SVal loc, bool isLoad, const Stmt *S,
175160 CheckerContext &C) const ;
@@ -236,12 +221,12 @@ void NSOrCFErrorDerefChecker::checkLocation(SVal loc, bool isLoad,
236221 if (!CFErrorII)
237222 CFErrorII = &Ctx.Idents .get (" CFErrorRef" );
238223
239- if (ShouldCheckNSError && IsNSError (parmT, NSErrorII)) {
224+ if (NSError. isEnabled () && IsNSError (parmT, NSErrorII)) {
240225 setFlag<NSErrorOut>(state, state->getSVal (loc.castAs <Loc>()), C);
241226 return ;
242227 }
243228
244- if (ShouldCheckCFError && IsCFError (parmT, CFErrorII)) {
229+ if (CFError. isEnabled () && IsCFError (parmT, CFErrorII)) {
245230 setFlag<CFErrorOut>(state, state->getSVal (loc.castAs <Loc>()), C);
246231 return ;
247232 }
@@ -274,19 +259,9 @@ void NSOrCFErrorDerefChecker::checkEvent(ImplicitNullDerefEvent event) const {
274259
275260 os << " may be null" ;
276261
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;
288263 BR.emitReport (
289- std::make_unique<PathSensitiveBugReport>(*bug , os.str (), event.SinkNode ));
264+ std::make_unique<PathSensitiveBugReport>(BT , os.str (), event.SinkNode ));
290265}
291266
292267static bool IsNSError (QualType T, IdentifierInfo *II) {
@@ -320,32 +295,21 @@ static bool IsCFError(QualType T, IdentifierInfo *II) {
320295 return TT->getDecl ()->getIdentifier () == II;
321296}
322297
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+ }
348313
349- bool ento::shouldRegisterCFErrorChecker (const CheckerManager &mgr) {
350- return true ;
351- }
314+ REGISTER_CHECKER (NSError, NSErrorMethodChecker)
315+ REGISTER_CHECKER(CFError, CFErrorFunctionChecker)
0 commit comments